{"id":18841781,"url":"https://github.com/ypares/arpligner","last_synced_at":"2025-07-01T09:06:09.524Z","repository":{"id":65293815,"uuid":"585333343","full_name":"YPares/arpligner","owner":"YPares","description":"A multi-track \u0026 polyphonic arpeggiator plugin that takes both chords and arp patterns as live MIDI data","archived":false,"fork":false,"pushed_at":"2023-10-11T14:43:53.000Z","size":7961,"stargazers_count":36,"open_issues_count":7,"forks_count":8,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-08T02:38:10.569Z","etag":null,"topics":["arpeggiator","juce","juce-application","juce-plugins","ladspa-plugin","lv2-plugin","midi","midi-plugin","midi-processing","music","protoplug","vst","vst3-plugin"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/YPares.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":"FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":"YPares","liberapay":"Ywen"}},"created_at":"2023-01-04T22:49:01.000Z","updated_at":"2024-12-28T11:04:38.000Z","dependencies_parsed_at":"2023-10-11T18:58:26.864Z","dependency_job_id":null,"html_url":"https://github.com/YPares/arpligner","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/YPares/arpligner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YPares%2Farpligner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YPares%2Farpligner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YPares%2Farpligner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YPares%2Farpligner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/YPares","download_url":"https://codeload.github.com/YPares/arpligner/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YPares%2Farpligner/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262933277,"owners_count":23386780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arpeggiator","juce","juce-application","juce-plugins","ladspa-plugin","lv2-plugin","midi","midi-plugin","midi-processing","music","protoplug","vst","vst3-plugin"],"created_at":"2024-11-08T02:52:30.350Z","updated_at":"2025-07-01T09:06:09.501Z","avatar_url":"https://github.com/YPares.png","language":"C++","funding_links":["https://github.com/sponsors/YPares","https://liberapay.com/Ywen"],"categories":[],"sub_categories":[],"readme":"[![Build (Windows)](https://github.com/YPares/arpligner/actions/workflows/win-build-validate.yml/badge.svg)](https://github.com/YPares/arpligner/actions/workflows/win-build-validate.yml) [![Build (OSX)](https://github.com/YPares/arpligner/actions/workflows/osx-build.yml/badge.svg)](https://github.com/YPares/arpligner/actions/workflows/osx-build.yml) \u003ca href=\"https://matrix.to/#/#arpligner:gitter.im\"\u003e\u003cimg src=\"https://badges.gitter.im/arpligner/community.svg\" align=\"right\" alt=\"Join the chat at https://gitter.im/arpligner/community\"/\u003e\u003c/a\u003e\n\n[![Build (Linux x64)](https://github.com/YPares/arpligner/actions/workflows/linux-build.yml/badge.svg)](https://github.com/YPares/arpligner/actions/workflows/linux-build.yml) [![Build (RaspberryPi arm64)](https://github.com/YPares/arpligner/actions/workflows/raspberry-build.yml/badge.svg)](https://github.com/YPares/arpligner/actions/workflows/raspberry-build.yml) \n\n\u003chr/\u003e\n\u003cp align=\"center\"\u003e\u003cimg src=\"docs/logo_dark.svg\" alt=\"Arpligner logo\"/\u003e\u003c/p\u003e\n\u003chr/\u003e\n\nArpligner is a **multi-track** \u0026 **polyphonic** arpeggiator which will use your\nown arpeggiation patterns (like [2Rule\nTugMidiSeq](https://tugrulakyuz.gumroad.com/l/xfzgta),\n[LibreArp](https://librearp.gitlab.io/), [Xfer\nCthulhu](https://xferrecords.com/products/cthulhu), [Reason PolyStep\nSequencer](https://www.reasonstudios.com/shop/rack-extension/polystep-sequencer/),\nor [FL's VFX\nSequencer](https://www.image-line.com/fl-studio-learning/fl-studio-beta-online-manual/html/plugins/VFX%20Sequencer.htm)). It\nis packaged as VST3 \u0026 LV2 MIDI plugins and as a standalone application.\n\n- **Multi-track**: Multiple arpeggiation patterns can play at the same time for\n  a given chord, each one in its own track of your DAW, or on its own MIDI\n  channel,\n- **Polyphonic**: Each step can play several notes of a chord at the same\n  time. \"Steps\" can also hold over an arbitrary length of time and overlap.  So\n  besides arpeggiation _per se_, you can do strumming or really any kind of\n  \"turning a plain block chord into something more interesting\".\n\nTo achieve this, the big difference between Arpligner and the aforementioned\nplugins is that Arpligner does very intentionally _**not** come with its own\ngraphical interface for editing patterns_. Instead it will rely on arp patterns\nbeing fed to it as regular (and possibly live) MIDI data: you can thus\nmake use of your DAW piano rool and MIDI sequencing capabilities[^1], play those\npatterns live, or use an external MIDI sequencer (software or hardware).\n\nTherefore, you can use it as a regular arp, playing your chords against\npre-written patterns, or the opposite. Or both can be live data! That would be\nhaving two keyboard players: one in charge of the chords and the other one in\ncharge of how to layout those chords[^2].\n\nSee https://youtu.be/IQ9GFEaS4Ag for an overview of the tool and the basic\nfeatures (this uses the original Lua script but the video remains valid).\n\nStill experimental, please [post issues here](https://github.com/YPares/arpligner/issues/new) in case of bugs or questions, or get\nin touch on Matrix (room #arpligner:gitter.im): just [click here](https://matrix.to/#/#arpligner:gitter.im) to join the chat! :)\n\n## How to use it\n\nArpligner has two modes: **Multi-channel** and **Multi-instance**, which affect\nhow Arpligner will receive MIDI data and set what it considers to be a\n\"**chord** track\" and what it considers to be a \"**pattern** track\".\n\n### General behaviour\n\nWhatever the mode, Arpligner will interpret \"notes\" playing on **pattern**\ntracks as the degrees of the chord which is currently playing on the **chord**\ntrack. Starting from C3 and going up:\n\n- C3 means \"first chord degree\"\n- C#3 means \"second chord degree\"\n- D3 means \"third chord degree\", etc.\n\nC3 is therefore treated as the _reference_ pattern note, the one from which\neverything will be derived.\n\nHowever, you may wonder then what happens if you go below C3. Or if you go\n\"above\" the last degree of your chord. Well then, Arpligner will \"wrap around\"\nthe chord, but transposing the notes up or down as many octaves as needed, so it\nalways has a sensible chord note to play.\n\nYou can also select different mapping and wraparound methods. For instance, you\ncan choose that only the white keys will be used to select chord degrees, and leave the black keys\nto play the entire chord up to the black key you play. See the [pattern\nsettings section](#pattern-parameters) for more info.\n\n### Multi-channel mode\n\nIn this mode, you can use as little as one single Arpligner instance in your DAW\nsession. It expects to be fed MIDI data on at least 2 channels:\n\n- Channel 16 (by default), which will be treated as the **chord** channel\n  (\"track\")\n- At least one _other_ channel (say, Channel 1), which will be treated as a\n  **pattern** channel (\"track\"). Any channel other than the **chord** channel\n  will do, they will all be treated equally.\n\nYou can perfectly use several Arpligner instances set to that mode at the same\ntime, but they will just be completely independent of one another. They will\neach receive their own chord track and pattern tracks.\n\n**Multi-channel** has the advantage of requiring a bit less CPU and RAM, and\nenables you to have several chord tracks, each one affecting up to 15 patterns\ntracks.\n\n### Multi-instance mode\n\nIn this mode, the different instances of the Arpligner plugin in your DAW\nsession can communicate with one another. You would then have one Arpligner\ninstance per relevant track, one being configured as the **Global chord instance**,\nand the other ones as **Pattern instances**. MIDI channels no longer matter to\nArpligner in that mode.\n\n**Multi-instance** has the advantage of alleviating MIDI routing configuration\nin your DAW, and is not limited by the number of MIDI channels. So you have just\none chord track, but it can affect any number of pattern tracks.\n\nNote that it is perfectly possible to have in your DAW session both\n**Multi-instance** instances and **Multi-channel** instances. Only those set to\n**Multi-instance** will communicate, the other ones will keep depending solely\non the MIDI data you directly feed into them.\n\n\n## Installation\n\nArpligner is downloadable via the project's itch.io page: [ywen.itch.io/arpligner](https://ywen.itch.io/arpligner).\n\nBesides, latest builds [are available here](https://github.com/YPares/arpligner/actions), from most recent to most ancient (though github only keeps them for a few months).\nSelect in the left panel the `Plugin build` action corresponding to your OS (Linux, Windows or OSX),\nthen select the latest run that succeeded (green tick) for that action, then go to the\nArtifacts section at the bottom of the page.\n\nThe downloaded archive will contain the VST3, the LV2 and the standalone app for your OS.\nJust copy the plugin in your usual VST3/LV2 folder (depending on your OS and DAW settings).\n\n**Important:** Due to [a VST3\nlimitation](https://forum.juce.com/t/arpeggiatorplugin-vst3-recognized-as-aufio-fx-instead-of-midi-fx/43563),\nArpligner will be recognized by your DAW as an Audio Fx plugin, whereas it is\nonly a MIDI Fx plugin. So if your DAW sorts or filters plugins by categories,\nyou will have to look for Arpligner under this category.\n\nThen, I recommend to have one track dedicated to **chords**. After that, if you\nuse the **Multi-channel** mode, you'll need some way to configure MIDI routing\nin your DAW so Arpligner receives what it expects. See [this\nsection](#tips-for-multi-channel-mode) for tips.\n\n## Implementation \u0026 build\n\nArpligner is implemented in C++ with [JUCE 7](https://juce.com/), and therefore\nshould support a variety of systems and plugin formats. I'm providing\nVST3, LV2 and standalone app builds for Linux, Windows and OSX (x64). The [project file](Arpligner.jucer) for\n[Projucer](https://juce.com/discover/projucer) is also provided if you want to\ngenerate build files for other platforms or other plugin formats. Arpligner has\nno plugin-format-specific or OS-specific code so it should be pretty\nstraightforward.\n\nThe code on this repository is mostly self-contained. The build files are in the `Builds` folder.\nYou have the necessary Linux makefile, OSX Xcode project and VisualStudio2022 solution files (generated by JUCE).\nTo build Arpligner on Linux, you will though need to install first\n[the needed JUCE dependencies](https://github.com/juce-framework/JUCE/blob/master/docs/Linux%20Dependencies.md).\n\nI originally implemented Arpligner as a Lua script for\n[Protoplug](https://www.osar.fr/protoplug/), but switched to direct use of JUCE\n7 for maintainability and VST3 support. The original script can be found in\n[`ProtoplugArpligner.lua`](ProtoplugArpligner.lua) but I should no longer be\nmaintaining it.\n\n## Tips\n\n### General tips\n\n- Arpligner should give more controllable results if you write/play your chords\n  in their most canonical form: block chords, no inversions, without any\n  octaving of notes. It will really use your chord note data as they come, it\n  won't do anything fancy to try and detect which chord you are actually\n  playing, what is its root, etc. But note that \"more controllable\" does not\n  necessarily mean better ;)\n- In pattern channels, only note pitches are affected. So your \"pattern\" notes\n  will stay on the same channel, keep their velocity, etc. That means your\n  patterns may contain velocity variations, pitch bends, CCs or that kind of\n  things :)\n- As it is working with potentially live MIDI data, Arpligner has no notion of\n  things like \"start point\", \"end point\" or \"loop\", and thus cannot do things\n  like \"reset the pattern when the chord changes\". Therefore, it's up to you to\n  keep your chord and pattern clips in sync (or interestingly\n  out-of-sync). E.g. for a regular arp \"emulation\", if you work with looping\n  clips, just make your chord clip have a length that is a multiple of that of\n  your pattern clip, so you'll repeat the same pattern several times over\n  different chords.\n- Besides pre-writing chord progressions or playing them live, you can use\n  plugins like [Scaler 2](https://www.pluginboutique.com/products/6439) which\n  speed up the process of writing chord progressions, and which can output their\n  chords as MIDI and sync with the host's tempo \u0026 transport.\n- Arpligner offers different behaviours for when it is receiving no notes or\n  just one note on the chord channel. Default behaviour is \"latch \u0026 transpose\":\n  it will keep using the last chord if it receives no more notes, and it will\n  transpose it if it receives just one note. See [the settings\n  below](#available-settings) for more info.\n\n### Tips for Multi-channel mode\n\nWhen using **Multi-channel** mode, you have two options:\n\n- Dedicate one MIDI channel to each of your instruments. Then use only one\nArpligner instance on your **chord** track, and route **all** your MIDI data to\nit, making sure that this data is properly tagged by channel. Then, split back\nthe MIDI data that Arpligner outputs by MIDI channel, and route each channel to\nits corresponding instrument. Depending on your DAW, you may have to use 2\ntracks per instrument in that fashion: one for the pattern clips for this\ninstrument, and one for the actual instrument.\n- Place one instance of Arpligner on each of your **pattern** tracks, and route\nthe same **chord track** to all of them. Each instance will then receive a\npattern track on only one MIDI channel, and they will all process their patterns\naccording to the same chord progression. Each instance can then process pattern\ndata on several channels (this can be useful for multi-timbral instruments like\nKontakt or Omnisphere, or if your DAW supports layering several instruments on\nthe same track).\n\nFor example in Bitwig, you can put the `Note Receiver` device in a track to\nroute MIDI events from another track, and you can use the `Channel Map` device\nin the `Source FX` section of this `Note Receiver` to make every incoming note\ngo to the right MIDI channel. Do not forget to deactivate the `Inputs` button in\nthe \"Mutes\" so that MIDI events from the track pass through too.\n\n### Tips for Multi-instance mode\n\nIn **Multi-instance** mode, when some chord notes and pattern notes start at the\nexact same time (which is a ubiquitous case when using MIDI clips or\nsequencers), you will probably need one of the following two options (don't do\nboth at the same time):\n\n- Either introduce some delay on each one of your **pattern** tracks: if your\nDAW has a feature to delay MIDI notes by a few milliseconds on pattern tracks,\nit can be used here (in Bitwig, that's the `Note Delay` device, which can go as\nlow as 10ms delay, which in my tests was enough)\n- Or make sure the `Global chord track lookahead` on your **chord** track has a non-zero value:\nincreasing this delay parameter (in milliseconds) on your Global chord instance\nshould have an effect similar to the first option (but requires a change on only\none track, not on all your pattern tracks). The lookahead time on the Global\nchord instance is 10ms by default. You probably will need to reload\n(deactivate/reactivate) your Global chord instance if you change it, so your DAW\nmay register the change. This will tell your DAW that this Global chord instance\nneeds a bit of extra time, and it will delay all the other tracks in\nconsequence.\n\nIf you do not do that, your pattern instances may process their notes _before_\nthe chord instance has noticed that the chord has changed, and you would get\nsome final result which is still using the previous chord. This is perfectly\nexpected and cannot be avoided in situations where your MIDI is sequenced. It\ncomes from the fact that you have no guarantee over the order in which your DAW\nwill execute your plugins' logic, and therefore over which instance will notice\nfirst some perfectly synchronized MIDI events. Therefore we need to delay a\nlittle bit (by inaudible amounts) the pattern tracks with respect to the chord\ntrack to make sure everything is updated in the right order. In live situations,\nsuch perfect synchronization never occurs, so it's much less of a concern.\n\nNote that **Multi-channel** mode does not raise this concern at all (live or\nnot). In that mode, given all events are processed by the same instance, I can\nmake sure to update the current chord prior to processing pattern notes.\n\n## Available settings\n\nArpligner's GUI shows a few parameters that you can change to make Arpligner fit your usage and workflow.\nThese parameters are also exposed to the host, and can be automated[^3].\n\n| Parameter name | Default value | Possible values | Documentation |\n|--------------------------------|---------------|-----------------|---------------|\n|**Instance behaviour**|`[Multi-chan] Chords on chan 16`|Choose from:|The main behaviour of this Arpligner instance|\n| | |`Bypass`|Do nothing and just pass all MIDI events through|\n| | |`[Multi-chan] Chords on chan XX`|Sets to **Multi-channel** mode, and use channel `XX` as the chord track (and any other channel as a pattern track)|\n| | |`[Multi-instance] Global chord instance`|Sets this instance as the one that receives chord notes (any MIDI input, whatever its channel) and sets the current chord for all other connected instances|\n| | |`[Multi-instance] Pattern instance`|Sets this instance as a \"follower\" of the one set to `Global chord instance`. Any MIDI input, whatever its channel, is considered a pattern event, and will stay on the same channel|\n\n### Chord parameters\n\nThese parameters are used *only* in Multi-chan mode or by *Chord* instances.\n\n| Parameter name | Default value | Possible values | Documentation |\n|--------------------------------|---------------|-----------------|---------------|\n|**When no chord note**|`Latch last chord`|Choose from:|What to do when **no** note is playing on the chord track|\n| | |`Silence`| Ignore the pattern notes|\n| | |`Use pattern notes as final notes`|Consider the pattern \"notes\" as real notes, and pass them through without any change|\n| | |`Latch last chord`|Keep using the previous chord that played (`Silence` if no previous chord is known)|\n|**When single chord note**|`Transpose last chord`|Choose from:|What to do when a **single** note _n_ is playing on the chord track|\n| | |`Silence`|Same as for \"no chord note\"|\n| | |`Use pattern notes as final notes`|Same as for \"no chord note\"|\n| | |`Use as one-note chord`|Use _n_ as just a \"one-note chord\". Tread carefully, the end result may go up in octaves pretty fast|\n| | |`Powerchord`|Turn _n_ into a \"2-note chord\": _n_ and the note a fifth above|\n| | |`Transpose last chord`|Transpose last chord so that its lowest note becomes _n_ (`Silence` if no previous chord is known)|\n|**Global chord track lookahead**|`10ms`|A delay between 0 and 50ms|Only used by a Global chord instance. Triggers your DAW Plugin Delay Compensation (if above zero) to deal with perfectly synchronized chord and pattern events. See [this section](#tips-for-multi-instance-mode) for when to use this|\n\n### Pattern parameters\n\nThese parameters are used *only* in Multi-chan mode or by *Pattern*\ninstances. When using the **Multi-instance** mode, you can therefore select a\ndifferent behaviour for each Pattern instance. This can be useful for instance\nif some instruments are to be played live and others via MIDI sequencing, or if\ndifferent live players have different preferences.\n\n| Parameter name | Default value | Possible values | Documentation |\n|--------------------------------|---------------|-----------------|---------------|\n|**Reference pattern note**|`60 (C3)`|A MIDI note|On pattern tracks, the note that will always be mapped to the first (lowest) degree of the currently playing chord|\n|**Pattern notes mapping**|`Semitone to degree`|Choose from:|How to map midi note codes on pattern tracks to actual notes|\n| | |`Always leave unmapped`|No pattern note is mapped, and therefore always use the **Unmapped notes behaviour**|\n| | |`Semitone to degree`|Going up/down one _semitone_ in the pattern track means going up/down one degree in the chord|\n| | |`White note to degree`|Going up/down one _white key_ in the pattern track means going up/down one degree in the chord. Black keys are not mapped|\n|**Pattern octave wraparound**|`[Dynamic] After all chord degrees`|Choose from:|When should your pattern wrap around the chord, ie. play it at a higher/lower octave. _(Used depending on the mapping setting above)_|\n| | |`No wraparound`|Never. Pattern notes past the last chord degree are unmapped, as well as notes below the Reference note|\n| | |`[Dynamic] After all chord degrees`|Repeatedly go up one octave (and back to the first chord degree) as soon as we're past the last chord degree, or down one octave (and to the _last_ chord degree) in the other direction. No pattern note is therefore ever left unmapped.|\n| | |`[Fixed] Every XXth pattern note`|Use a fixed wraparound setting. You will go up one octave (and back to the first chord degree) every time your pattern goes up `XX` notes, and down one octave (and to the _last_ chord degree) every time your pattern goes _down_ `XX` notes. Intermediary pattern notes that do not correspond to chord degrees are unmapped.|\n|**Unmapped notes behaviour**|`Silence`|Choose from:|What to do when the mapping or wraparound settings above have left some pattern notes unmapped|\n| | |`Silence`|Do not output any note|\n| | |`Use as is`|Output the pattern note as it is|\n| | |`Transpose from 1st degree`|Use Arpligner as a \"dynamic\" transposer: ignore all chord degrees besides the first (lowest) one. Pattern notes are just transposed accordingly. This allows you to play notes that are outside the current chord, but keeping your patterns centered around the reference note|\n| | |`Play all degrees up to note`|Play the full chord, using the played note as a filter (all chord degrees above will be silenced)|\n\n## Current limitations\n\n- Arpligner is quite strict for now regarding the timing of notes on the chord\n  channel. When your chords are played from already quantized MIDI clips or by a\n  sequencer it's not a problem, but for \"classical\" live arp usage, i.e. when\n  playing chords live against a preset pattern, it can be. So in this scenario,\n  I recommend to use some sort of beat quantizer on your chord channel before\n  Arpligner, and to play around with the various settings until you get a\n  satisfying result.\n- I would love to be able to support MPE in patterns: given in Multi-instance\n  mode you can use as many channels as you want for your patterns, this would\n  allow you to play your patterns on any MPE instrument, with glides, polyphonic\n  bends, expression changes, etc, record them and be able to keep these in your\n  final arpeggios while re-using them over a different harmony :).  Sadly my\n  JUCE skills are not up to this task yet, but any help is welcome!\n\n[^1]: I use Bitwig and the piano roll editor and MIDI operators to manipulate\n      notes are just so much better and so much more flexible than everything\n      I've seen in plugins\n\n[^2]: And if someone ever makes a jazz jam session out of that, definitely\n      record it and send me the video ^^\n\n[^3]: **WARNING:** In some cases, automation of some of these parameters while\n      Arpligner is processing notes may cause stuck notes, please report an\n      issue here if this happens to you, preferably with a set of MIDI files\n      that will help me reproduce the problem\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fypares%2Farpligner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fypares%2Farpligner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fypares%2Farpligner/lists"}