Arpligner is a multi-track & polyphonic arpeggiator which will use your own arpeggiation patterns (like 2Rule TugMidiSeq, LibreArp, Xfer Cthulhu, Reason PolyStep Sequencer, or FL's VFX Sequencer). It is packaged as VST3 & LV2 MIDI plugins and as a standalone application.
- Multi-track: Multiple arpeggiation patterns can play at the same time for a given chord, each one in its own track of your DAW, or on its own MIDI channel,
- Polyphonic: Each step can play several notes of a chord at the same time. "Steps" can also hold over an arbitrary length of time and overlap. So besides arpeggiation per se, you can do strumming or really any kind of "turning a plain block chord into something more interesting".
To achieve this, the big difference between Arpligner and the aforementioned plugins is that Arpligner does very intentionally not come with its own graphical interface for editing patterns. Instead it will rely on arp patterns being fed to it as regular (and possibly live) MIDI data: you can thus make use of your DAW piano rool and MIDI sequencing capabilities1, play those patterns live, or use an external MIDI sequencer (software or hardware).
Therefore, you can use it as a regular arp, playing your chords against pre-written patterns, or the opposite. Or both can be live data! That would be having two keyboard players: one in charge of the chords and the other one in charge of how to layout those chords2.
See https://youtu.be/IQ9GFEaS4Ag for an overview of the tool and the basic features (this uses the original Lua script but the video remains valid).
Still experimental, please post issues here in case of bugs or questions, or get in touch on Matrix (room #arpligner:gitter.im): just click here to join the chat! :)
Arpligner has two modes: Multi-channel and Multi-instance, which affect how Arpligner will receive MIDI data and set what it considers to be a "chord track" and what it considers to be a "pattern track".
Whatever the mode, Arpligner will interpret "notes" playing on pattern tracks as the degrees of the chord which is currently playing on the chord track. Starting from C3 and going up:
- C3 means "first chord degree"
- C#3 means "second chord degree"
- D3 means "third chord degree", etc.
C3 is therefore treated as the reference pattern note, the one from which everything will be derived.
However, you may wonder then what happens if you go below C3. Or if you go "above" the last degree of your chord. Well then, Arpligner will "wrap around" the chord, but transposing the notes up or down as many octaves as needed, so it always has a sensible chord note to play.
You can also select different mapping and wraparound methods. For instance, you can choose that only the white keys will be used to select chord degrees, and leave the black keys to play the entire chord up to the black key you play. See the pattern settings section for more info.
In this mode, you can use as little as one single Arpligner instance in your DAW session. It expects to be fed MIDI data on at least 2 channels:
- Channel 16 (by default), which will be treated as the chord channel ("track")
- At least one other channel (say, Channel 1), which will be treated as a pattern channel ("track"). Any channel other than the chord channel will do, they will all be treated equally.
You can perfectly use several Arpligner instances set to that mode at the same time, but they will just be completely independent of one another. They will each receive their own chord track and pattern tracks.
Multi-channel has the advantage of requiring a bit less CPU and RAM, and enables you to have several chord tracks, each one affecting up to 15 patterns tracks.
In this mode, the different instances of the Arpligner plugin in your DAW session can communicate with one another. You would then have one Arpligner instance per relevant track, one being configured as the Global chord instance, and the other ones as Pattern instances. MIDI channels no longer matter to Arpligner in that mode.
Multi-instance has the advantage of alleviating MIDI routing configuration in your DAW, and is not limited by the number of MIDI channels. So you have just one chord track, but it can affect any number of pattern tracks.
Note that it is perfectly possible to have in your DAW session both Multi-instance instances and Multi-channel instances. Only those set to Multi-instance will communicate, the other ones will keep depending solely on the MIDI data you directly feed into them.
Arpligner is downloadable via the project's itch.io page: ywen.itch.io/arpligner.
Besides, latest builds are available here, from most recent to most ancient (though github only keeps them for a few months).
Select in the left panel the Plugin build
action corresponding to your OS (Linux, Windows or OSX),
then select the latest run that succeeded (green tick) for that action, then go to the
Artifacts section at the bottom of the page.
The downloaded archive will contain the VST3, the LV2 and the standalone app for your OS. Just copy the plugin in your usual VST3/LV2 folder (depending on your OS and DAW settings).
Important: Due to a VST3 limitation, Arpligner will be recognized by your DAW as an Audio Fx plugin, whereas it is only a MIDI Fx plugin. So if your DAW sorts or filters plugins by categories, you will have to look for Arpligner under this category.
Then, I recommend to have one track dedicated to chords. After that, if you use the Multi-channel mode, you'll need some way to configure MIDI routing in your DAW so Arpligner receives what it expects. See this section for tips.
Arpligner is implemented in C++ with JUCE 7, and therefore should support a variety of systems and plugin formats. I'm providing VST3, LV2 and standalone app builds for Linux, Windows and OSX (x64). The project file for Projucer is also provided if you want to generate build files for other platforms or other plugin formats. Arpligner has no plugin-format-specific or OS-specific code so it should be pretty straightforward.
The code on this repository is mostly self-contained. The build files are in the Builds
folder.
You have the necessary Linux makefile, OSX Xcode project and VisualStudio2022 solution files (generated by JUCE).
To build Arpligner on Linux, you will though need to install first
the needed JUCE dependencies.
I originally implemented Arpligner as a Lua script for
Protoplug, but switched to direct use of JUCE
7 for maintainability and VST3 support. The original script can be found in
ProtoplugArpligner.lua
but I should no longer be
maintaining it.
- Arpligner should give more controllable results if you write/play your chords in their most canonical form: block chords, no inversions, without any octaving of notes. It will really use your chord note data as they come, it won't do anything fancy to try and detect which chord you are actually playing, what is its root, etc. But note that "more controllable" does not necessarily mean better ;)
- In pattern channels, only note pitches are affected. So your "pattern" notes will stay on the same channel, keep their velocity, etc. That means your patterns may contain velocity variations, pitch bends, CCs or that kind of things :)
- As it is working with potentially live MIDI data, Arpligner has no notion of things like "start point", "end point" or "loop", and thus cannot do things like "reset the pattern when the chord changes". Therefore, it's up to you to keep your chord and pattern clips in sync (or interestingly out-of-sync). E.g. for a regular arp "emulation", if you work with looping clips, just make your chord clip have a length that is a multiple of that of your pattern clip, so you'll repeat the same pattern several times over different chords.
- Besides pre-writing chord progressions or playing them live, you can use plugins like Scaler 2 which speed up the process of writing chord progressions, and which can output their chords as MIDI and sync with the host's tempo & transport.
- Arpligner offers different behaviours for when it is receiving no notes or just one note on the chord channel. Default behaviour is "latch & transpose": it will keep using the last chord if it receives no more notes, and it will transpose it if it receives just one note. See the settings below for more info.
When using Multi-channel mode, you have two options:
- Dedicate one MIDI channel to each of your instruments. Then use only one Arpligner instance on your chord track, and route all your MIDI data to it, making sure that this data is properly tagged by channel. Then, split back the MIDI data that Arpligner outputs by MIDI channel, and route each channel to its corresponding instrument. Depending on your DAW, you may have to use 2 tracks per instrument in that fashion: one for the pattern clips for this instrument, and one for the actual instrument.
- Place one instance of Arpligner on each of your pattern tracks, and route the same chord track to all of them. Each instance will then receive a pattern track on only one MIDI channel, and they will all process their patterns according to the same chord progression. Each instance can then process pattern data on several channels (this can be useful for multi-timbral instruments like Kontakt or Omnisphere, or if your DAW supports layering several instruments on the same track).
For example in Bitwig, you can put the Note Receiver
device in a track to
route MIDI events from another track, and you can use the Channel Map
device
in the Source FX
section of this Note Receiver
to make every incoming note
go to the right MIDI channel. Do not forget to deactivate the Inputs
button in
the "Mutes" so that MIDI events from the track pass through too.
In Multi-instance mode, when some chord notes and pattern notes start at the exact same time (which is a ubiquitous case when using MIDI clips or sequencers), you will probably need one of the following two options (don't do both at the same time):
- Either introduce some delay on each one of your pattern tracks: if your
DAW has a feature to delay MIDI notes by a few milliseconds on pattern tracks,
it can be used here (in Bitwig, that's the
Note Delay
device, which can go as low as 10ms delay, which in my tests was enough) - Or make sure the
Global chord track lookahead
on your chord track has a non-zero value: increasing this delay parameter (in milliseconds) on your Global chord instance should have an effect similar to the first option (but requires a change on only one track, not on all your pattern tracks). The lookahead time on the Global chord instance is 10ms by default. You probably will need to reload (deactivate/reactivate) your Global chord instance if you change it, so your DAW may register the change. This will tell your DAW that this Global chord instance needs a bit of extra time, and it will delay all the other tracks in consequence.
If you do not do that, your pattern instances may process their notes before the chord instance has noticed that the chord has changed, and you would get some final result which is still using the previous chord. This is perfectly expected and cannot be avoided in situations where your MIDI is sequenced. It comes from the fact that you have no guarantee over the order in which your DAW will execute your plugins' logic, and therefore over which instance will notice first some perfectly synchronized MIDI events. Therefore we need to delay a little bit (by inaudible amounts) the pattern tracks with respect to the chord track to make sure everything is updated in the right order. In live situations, such perfect synchronization never occurs, so it's much less of a concern.
Note that Multi-channel mode does not raise this concern at all (live or not). In that mode, given all events are processed by the same instance, I can make sure to update the current chord prior to processing pattern notes.
Arpligner's GUI shows a few parameters that you can change to make Arpligner fit your usage and workflow. These parameters are also exposed to the host, and can be automated3.
Parameter name | Default value | Possible values | Documentation |
---|---|---|---|
Instance behaviour | [Multi-chan] Chords on chan 16 |
Choose from: | The main behaviour of this Arpligner instance |
Bypass |
Do nothing and just pass all MIDI events through | ||
[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) |
||
[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 | ||
[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 |
These parameters are used only in Multi-chan mode or by Chord instances.
Parameter name | Default value | Possible values | Documentation |
---|---|---|---|
When no chord note | Latch last chord |
Choose from: | What to do when no note is playing on the chord track |
Silence |
Ignore the pattern notes | ||
Use pattern notes as final notes |
Consider the pattern "notes" as real notes, and pass them through without any change | ||
Latch last chord |
Keep using the previous chord that played (Silence if no previous chord is known) |
||
When single chord note | Transpose last chord |
Choose from: | What to do when a single note n is playing on the chord track |
Silence |
Same as for "no chord note" | ||
Use pattern notes as final notes |
Same as for "no chord note" | ||
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 | ||
Powerchord |
Turn n into a "2-note chord": n and the note a fifth above | ||
Transpose last chord |
Transpose last chord so that its lowest note becomes n (Silence if no previous chord is known) |
||
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 for when to use this |
These parameters are used only in Multi-chan mode or by Pattern instances. When using the Multi-instance mode, you can therefore select a different behaviour for each Pattern instance. This can be useful for instance if some instruments are to be played live and others via MIDI sequencing, or if different live players have different preferences.
Parameter name | Default value | Possible values | Documentation |
---|---|---|---|
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 |
Pattern notes mapping | Semitone to degree |
Choose from: | How to map midi note codes on pattern tracks to actual notes |
Always leave unmapped |
No pattern note is mapped, and therefore always use the Unmapped notes behaviour | ||
Semitone to degree |
Going up/down one semitone in the pattern track means going up/down one degree in the chord | ||
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 | ||
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) |
No wraparound |
Never. Pattern notes past the last chord degree are unmapped, as well as notes below the Reference note | ||
[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. | ||
[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. |
||
Unmapped notes behaviour | Silence |
Choose from: | What to do when the mapping or wraparound settings above have left some pattern notes unmapped |
Silence |
Do not output any note | ||
Use as is |
Output the pattern note as it is | ||
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 | ||
Play all degrees up to note |
Play the full chord, using the played note as a filter (all chord degrees above will be silenced) |
- Arpligner is quite strict for now regarding the timing of notes on the chord channel. When your chords are played from already quantized MIDI clips or by a sequencer it's not a problem, but for "classical" live arp usage, i.e. when playing chords live against a preset pattern, it can be. So in this scenario, I recommend to use some sort of beat quantizer on your chord channel before Arpligner, and to play around with the various settings until you get a satisfying result.
- I would love to be able to support MPE in patterns: given in Multi-instance mode you can use as many channels as you want for your patterns, this would allow you to play your patterns on any MPE instrument, with glides, polyphonic bends, expression changes, etc, record them and be able to keep these in your final arpeggios while re-using them over a different harmony :). Sadly my JUCE skills are not up to this task yet, but any help is welcome!
Footnotes
-
I use Bitwig and the piano roll editor and MIDI operators to manipulate notes are just so much better and so much more flexible than everything I've seen in plugins ↩
-
And if someone ever makes a jazz jam session out of that, definitely record it and send me the video ^^ ↩
-
WARNING: In some cases, automation of some of these parameters while Arpligner is processing notes may cause stuck notes, please report an issue here if this happens to you, preferably with a set of MIDI files that will help me reproduce the problem ↩