What's new

Reaticulate - articulation management for REAPER - 0.5.13 now available

Replying here from this thread, just as it's more on-topic here.
By the way, is there a way to control host automation in Kontakt with Reaticulate?
Indirectly, through MIDI learn in Reaper.

In the FX window for Kontakt, click the Param button at the top of the FX window, and then FX Parameter List | Learn. Once you can associate a MIDI event with one of the host automation parameters, then you can use Reaticulate to control it via an output event for the articulation.
 
Definitely. And I should have a prerelease out later this week. (Sorry about the delayed reply.)
No problem! at all :) Looking forward to assisting with testing! :D

Since REAPER 6 is probably forever away and most likely will have lesser features as reaticulate. I'm sticking with it for the long term! :D
 
Will post some banks I've worked on. I'm not too particular about icons, colors etc. but the banks should work pretty well. Let me know if you run into any issues:


Chris Hein Winds:

//! g="Chris Hein/Winds"
//! m="CC1 - Vibrato, CC96 - Flutter tongue, CC98 - Trill minor, CC94 - Trill major"
//! chase=1
Bank 1 1 Chris Hein Winds
//! c=long i=note-whole o=note:25
25 Sustain
//! c=long i=note-whole o=note:24
24 Sustain Vibrato
//! c=legato i=legato o=note:26
26 Dynamic Expression Long
//! c=legato i=legato o=note:27
27 Dynamic Expression Short
//! c=fx i=multitongues o=note:28
28 Flutter Tongue
//! c=short-light i=staccato o=note:29
29 Short 1
//! c=short-light i=staccato o=note:30
30 Short 2
//! c=short-light i=staccato o=note:31
31 Short 3
//! c=short-light i=staccato o=note:32
32 Short 4
//! c=short-light i=staccato o=note:33
33 Short 5
//! c=short-light i=staccato o=note:34
34 Short 6
//! c=fx i=run-major o=note:35
35 Run Up
//! c=fx i=run-major o=note:38
38 Run Down
//! c=fx i=trill-min3 o=note:36
36 Trill Minor
//! c=fx i=trill-maj2 o=note:37
37 Trill Major
//! c=default i=trill-min3 o=note:44
44 Trill Minor Hotkey
//! c=default i=trill-maj2 o=note:43
43 Trill Major Hotkey
 
Last edited:
//! g="Cinematic Series/Studio Brass"
//! chase=1,2,5,11,20,64-69

Bank 2 1 Cinematic Studio Brass Section

//! c=legato i=legato o=note:24,1/note:34,65
20 Legato
//! c=long i=note-whole o=note:24,1/note:34,1
21 Sustain
//! c=short i=spiccato o=note:29,1

42 Repetitions
//! c=short i=spiccato o=note:29,33
41 Staccatissimo
//! c=short i=staccato o=note:29,65
40 Staccato
//! c=short i=sfz o=note:29,127
54 Sfz

//! c=short i=staccato o=note:25,1
1 Short Mutes
//! c=long i=note-whole o=note:25,65/note:34,1
2 Sustained mutes
//! c=legato i=con-sord o=note:25,65/note:34,65
3 Legato mutes

//! c=fx i=multitongues o=note:28,1/note:34,1
4 Sustained Fluttertongue
//! c=fx i=multitongues o=note:28,1/note:34,65
5 Legato Fluttertongue

//! c=fx i=trill-maj2 o=note:27,1/note:34,1
6 Sustained Trills
//! c=fx i=trill-maj2 o=note:27,1/note:34,65
7 Legato Trills

//! c=short i=multitongues o=note:26
8 Double Tongue

//! c=short i=marcato o=note:30,1/note:34,1
9 Marcato w/o repetition overlay
//! c=short i=marcato o=note:30,1/note:34,65
10 Marcato legato w/o repetition overlay
//! c=short i=marcato o=note:30,127/note:34,1
11 Marcato w repetition overlay
//! c=short i=marcato o=note:30,127/note:34,65
12 Marcato legato w repetition overlay

//! c=fx i=rip o=note:31
13 Rips
 
Last edited:
Embertone Herring Clarinet:
CC15 is set to vibrato and CC96 to flutter.

//! g="Embertone/Herring Clarinet"
//! chase=1,15,96

//! m="Velocity less than 13 is portamento. Velocity at 127 is ornament"

Bank 3 1 Embertone Herring Clarinet

//! c=legato i=legato o=note:36/note:41
20 Legato
//! c=legato i=legato o=note:36/note:37
21 Tongued Legato

//! c=short i=staccato o=note:38
40 Short

//! c=fx i=trill-min3 o=note:39
36 Trill Minor hotkey
//! c=fx i=trill-maj2 o=note:40
37 Trill Major hotkey

//----------------------------------------------------------------------------
 
Last edited:
8dio Claire Alto flute:

//! g="8Dio/Claire Alto Flute" n="Legato"
//! chase=1,11

Bank 7 1 Legato

//! c=legato i=legato o=note:24
20 Natural Legato

//! c=legato i=legato o=note:25
21 Soft 1 - Gentle, light vibrato

//! c=legato i=legato o=note:26
22 Soft 2 - Gentle, progressing vibrato

//! c=legato i=legato o=note:27
23 Medium

//! c=legato i=legato o=note:28
24 Strong

//! c=short i=staccato o=note:30
25 Staccattissimo

//! c=short i=marcato o=note:31
26 Marcato

//----------------------------------------------------------------------------

//! g="8Dio/Claire Alto Flute" n="Trills"
//! chase=1,11

Bank 7 2 Trills

//! c=fx i=trill-min3 o=note:28
20 Minor 2nd Trill

//! c=fx i=trill-maj2 o=note:29
21 Major 2nd Trill

//----------------------------------------------------------------------------

//! g="8Dio/Claire Alto Flute" n="Bonus"
//! chase=1,11

Bank 7 3 Bonus

//! c=fx i=legato-runs o=note:24
20 Major run

//! c=fx i=legato-runs o=note:25
21 Major run 2 Oct

//! c=fx i=legato-runs o=note:26
22 Minor run up

//! c=fx i=legato-runs o=note:27
23 Minor run 2 Oct

//! c=fx i=fx o=note:28
24 Breaths

//! c=fx i=fx o=note:29
25 Valve clicks
//----------------------------------------------------------------------------
 
Last edited:
@tack, could you tell me the best way to use Re-articulate with somthing like the ISW Ventus Bansuri.

This has separate keyswitches for attack and release ornaments, on the same note.

Which basically means keyswitches have to be stacked.

I do not want to code in every possible combination in the bank file.

Thank you in advance!
 
@tack, could you tell me the best way to use Re-articulate with somthing like the ISW Ventus Bansuri. This has separate keyswitches for attack and release ornaments, on the same note. Which basically means keyswitches have to be stacked.
Reaticulate doesn't handle this case as nicely as it might.

The obvious way to deal with this is to use different groups for attack and release ornaments. The limitation here is that Reaper doesn't understand Reaticulate's notion of groups and so it'll only chase the most recent program change, regardless of the group. In practice, this means that you need to ensure the playhead is positioned before all relevant program changes to get proper playback.

I don't know how to solve this (so that chasing will Just Work across all groups regardless of playhead position). Implementing customized chasing behavior in Reaticulate is really daunting, and I'm not sure if it could be done performantly. The only implementation I can think of is, when transport switches to playing or recording, have Reaticulate enumerate every MIDI item under the playhead, crawling backwards looking for all program changes until all applicable groups are found. If anyone has better ideas I'd be interested. It's on my to-do list to prototype that and see how badly it sucks on large projects (or maybe be surprised to learn it doesn't).

In the meantime, one workaround is to use separate banks for attack and release, and on the track definition, map the banks onto different source channels, say channel 1 for attacks and channel 2 for releases. They can both still ultimately route to channel 1 (or whatever) where your patch is in Kontakt, but then the program changes for these two types of articulations will be on different channels in your MIDI item. Because of this, Reaper will chase them properly.

Hope any of that made sense. :)

And thanks for sharing those banks!
 
Last edited:
I don't know how to solve this (so that chasing will Just Work across all groups regardless of playhead position). Implementing customized chasing behavior in Reaticulate is really daunting, and I'm not sure if it could be done performantly. The only implementation I can think of is, when transport switches to playing or recording, have Reaticulate enumerate every MIDI item under the playhead, crawling backwards looking for all program changes until all applicable groups are found. If anyone has better ideas I'd be interested. It's on my to-do list to prototype that and see how badly it sucks on large projects (or maybe be surprised to learn it doesn't).
I'm not certain how it would scale on a project with hundreds of MIDI tracks that need to be chased, but my experience has been that Reaper is reasonably fast at MIDI processing unless you're doing things that involve tons of iteration. I think just chasing program changes wouldn't hit performance too hard.

If the performance hit becomes enough of an issue that it lags the start of playback/recording, you might be able to set it up to chase and cache the program changes at a better time and then retrieve them on playback/record -- for example, a table storing the program change state for each measure of each track that gets built initially when Reaticulate launches and then updates itself every time MIDI data on a track changes. I think there's a hash compare function that will tell you when a MIDI change occurs on a track. That way, after the initial table is built, you'd only ever need to chase program changes on one track at a time, and never on playback/record.
 
Reaticulate doesn't handle this case as nicely as it might.

The obvious way to deal with this is to use different groups for attack and release ornaments. The limitation here is that Reaper doesn't understand Reaticulate's notion of groups and so it'll only chase the most recent program change, regardless of the group. In practice, this means that you need to ensure the playhead is positioned before all relevant program changes to get proper playback.

I don't know how to solve this (so that chasing will Just Work across all groups regardless of playhead position). Implementing customized chasing behavior in Reaticulate is really daunting, and I'm not sure if it could be done performantly. The only implementation I can think of is, when transport switches to playing or recording, have Reaticulate enumerate every MIDI item under the playhead, crawling backwards looking for all program changes until all applicable groups are found. If anyone has better ideas I'd be interested. It's on my to-do list to prototype that and see how badly it sucks on large projects (or maybe be surprised to learn it doesn't).

In the meantime, one workaround is to use separate banks for attack and release, and on the track definition, map the banks onto different source channels, say channel 1 for attacks and channel 2 for releases. They can both still ultimately route to channel 1 (or whatever) where your patch is in Kontakt, but then the program changes for these two types of articulations will be on different channels in your MIDI item. Because of this, Reaper will chase them properly.

Hope any of that made sense. :)

And thanks for sharing those banks!

Hi Tack ,

That last bit sort of made sense. How do I get different channels on my Midi item though?

So say, I have bank 1 - attacks
bank 2 - releases
Do I configure these as normal or do I need to include some Midi channel info there?

Then do I add both banks on Midi Channel 1 in rearticulate? (I assume this is what numbers 1-16 at the top of the window mean).

Do I then need to route two Midi events to one kontakt instance and have attacks on one and releases on the other?
 
That last bit sort of made sense. How do I get different channels on my Midi item though?

Supposing you have your ISW patch in Kontakt set to channel 1, add the two banks to the track like so:
  • Bank 1 - Attacks: Ch 1 -> Ch 1
  • Bank 2 - Releases: Ch 2 -> Ch 1
Then do I add both banks on Midi Channel 1 in rearticulate? (I assume this is what numbers 1-16 at the top of the window mean).
The 1-16 buttons are to control what's called the default channel. That's documented here.

The default channel comes into play when you have the source channel for the banks (as they are configured on the current track) set to Omni. When set to Omni, this allows the user to have different source channels set to different articulations using the same bank. The page I linked to above describes this as well in more detail. (The default mapping of Omni -> Source works fine for most use-cases.)

But when you specifically map a bank to a particular source channel -- ch1 and ch2 in the above cases -- then the default channel buttons aren't relevant. When you insert an articulation from a bank that's mapped a specific channel, the program change event will always be assigned that specific source channel.


Do I then need to route two Midi events to one kontakt instance and have attacks on one and releases on the other?
No custom routing is needed. Sit your ISW patch on channel 1, and Reaticulate takes care of ensuring program changes on channel 2 (for releases) will be controlling the patch in Kontakt on channel 1.

All this can get a bit complicated, admittedly. My goal was to make things reasonably straightforward in the common case, but still make more advanced configurations and channel mappings possible.
 
I think just chasing program changes wouldn't hit performance too hard.
If it was just a matter of enumerating program changes, I think I'd agree. But I don't see a way to do that. I think I'd have to enumerate over all CC events (via MIDI_GetCC() which will also return program changes) which could include quite a large number of CCs used for regular MIDI performance, especially when your CC resolution is quite high. Hence my skepticism about this being able to be done efficiently.

for example, a table storing the program change state for each measure of each track that gets built initially when Reaticulate launches and then updates itself every time MIDI data on a track changes.
Hm, that's an interesting idea. Unfortunately as far as I can tell this would require continuously polling all MIDI items in the project all the time. Worse still, there doesn't seem to be any kind of timestamp metadata or other means of determining if the item changed since last poll, so it'd require enumerating all CC events on all MIDI items constantly.

Do you see another way?
 
If it was just a matter of enumerating program changes, I think I'd agree. But I don't see a way to do that. I think I'd have to enumerate over all CC events (via MIDI_GetCC() which will also return program changes) which could include quite a large number of CCs used for regular MIDI performance, especially when your CC resolution is quite high. Hence my skepticism about this being able to be done efficiently.


Hm, that's an interesting idea. Unfortunately as far as I can tell this would require continuously polling all MIDI items in the project all the time. Worse still, there doesn't seem to be any kind of timestamp metadata or other means of determining if the item changed since last poll, so it'd require enumerating all CC events on all MIDI items constantly.

Do you see another way?
If I understand the reaper.MIDI_GetHash and reaper.MIDI_GetTrackHash functions correctly (I've never actually used them for anything), you would take the hash value of each track periodically and check that value against the hash value that was returned at the last check. If the values differ, it means the MIDI data on that track has changed, so then you compare the new hash value of each take on the track to the old hash values of the takes to find the one that changed, then you crawl through the data on the changed take, then you update the program change table and record the takes' hash values so you can check against them in the future. The hashes should save you from having to evaluate the actual data until the data changes. You'd still have to evaluate track hashes continually, but that shouldn't impact performance.

Even large takes can be evaluated pretty quickly. I'm using an articulation system that reads/writes/interprets the literal MIDI keyswitch data, which involves a huge amount of MIDI processing that goes way beyond just stepping through MIDI events to see what type they are, and while it's not entirely lag free (which is fine because it's effectively a sophisticated editing macro that doesn't have to run on playback), the lag is negligible, and I expect that the lag involved in implementing chased program changes would be even less perceptible. And I think even a lot of the lag in my own code could be optimized out by properly caching data so I don't have to continually run expensive functions.
 
If I understand the reaper.MIDI_GetHash and reaper.MIDI_GetTrackHash functions correctly (I've never actually used them for anything)
Ah, good call. And those are quite speedy functions, clearly the hash value is cached internally.

I actually think your idea here would work to augment my original idea to make it efficient enough that it might be practical.

Chasing is still necessary on transport play/record though, because it's possible for the user to change articulations ad hoc without editing the MIDI item. This means the JSFX on each of the tracks would need to be updated with the programs to chase on each group on all 16 channels each time the edit cursor changes or MIDI data changes.

I've thought through the design and it's pretty complicated. So this will be a future thing for sure.
 
hm, strange - if I switch short to supershort from Cubase Expression map or just press keyswitch on midi keyboard, all works. If I switch same from Reaticulate - not works (but similar neighboring keyswitches works well) - what's wrong?
First, thanks for doing the video. It's quite useful. :)

I do see something weird from Reaticulate here in the MIDI log, where it seems to be duplicating the output events, once the right way (with both note-ons grouped together before note-offs) and once the wrong way (note-on, note-off, note-on, note-off). I've fixed some issues in loosely related areas, so it's possible the latest code will behave better here. If you're willing to try a prerelease, I plan to cut one later today.

Apart from that, I see a couple differences with what Cubase is doing:
  • Cubase's expression maps are deferring note-offs until the next articulation is activated. The way to reproduce this with Reaticulate is to use note-hold output event types rather than note.
  • Cubase is sending note 24+41 for super short and 24+42 for short. But your Reaticulate bank is sending 24+45 for super short and 24+46 for short.
It's possible changing the above two things will fix your problem, despite what does appear to be a bug in the note behavior (and I'd still be quite interested to know if the latest code behaves the same way).
 
First, thanks for doing the video. It's quite useful. :)

.

Tack, thank you! everything was easier:

It was my mistake - I wrote a wrong notes in Reaticulate list, 45 and 46 instead 41 and 42. It happens in the moment to translate note names to note numbers

Now all works OK without note hold mode.


If you're willing to try a prerelease, I plan to cut one later today.
Yes, it's very appreciate!
 

Attachments

  • From Reaticulate.JPEG
    From Reaticulate.JPEG
    37.4 KB · Views: 8
  • From Cubase.JPEG
    From Cubase.JPEG
    38 KB · Views: 5
Last edited:
Top Bottom