Some help needed with programming a "choose 1 out of n" display for program changes

Tags: #<Tag:0x00007f9785908b60>

I have a keyboard with a bank of LED lights that I want to use for program change events (I use program changes to move between States in Cantabile.

The behavior I’m trying to get is the following -
On song load, illuminate lights 1 to n where n = $(SongPartCount). If $(SongPartCount) = 0 then no lights should go on. The first light will have a different color (say green) from the remaining lights (say blue) to indicate that it is selected.

On pressing another button, that button is then illuminated green and the previous light turned blue and the song state gets changed.

Has anyone written anything that can do the logic needed for the “song load” part. Or knows a VST that can handle this? Essentially the logic is
for n in 1 to 9
if n <= $(SongPartCount)
light[n].color = (n == 1 ? green : blue)
light[n].color = off

Not sure there’s anything in Cantabile that will handle this as is, but perhaps I can tweak something to make it work. What kind of MIDI events do you need to send to illuminate the buttons the different colors/off.

CC events. The 9 LED bank has lights with CC numbers 37-45. The CC value determines the color.

ok, let me think about this.

Anyone else have suggestions?

I’ve done a sort of similar thing with sysex to control the lights on my Keylab 88. I use note numbers on the pads to select different rack states then use states to send the colours (sysex messages) to the pads. The way I’ve set it up is that each pad has a rack whose rack states correspond to the colour of each pad, then at the song level, each song state corresponds to a different set of pad colours.
It wouldn’t use the automatic logic that @Ivan is wanting, but since you have the song states (parts) already, it’s just a matter of adding the pad control racks to the song and setting them up per state…

I’m not at the computer right now but when I am, I’ll post some screenshots that will make it easier to understand than my lengthy ramble above.


That should be easy to do with ReaJS. Essentially, you’ll need to use a SongState->OnLoad binding to send a MIDI command to it that contains $(SongPartCount), e.g. as a CC or SysEx, then use ReaJS to run your little script above

Just the JS script language takes a bit of getting used to…



Hi Torsten - doing this in JS might be the best approach, because I can then easily add on additional functionality. Two questions - 1) how do send a MIDI command to it that contains $(SongPartCount). I tried entering a binding into Cantabile looking like “Song Onload 0ms ‘reajs 1 - MIDI In’ Ch: 1 Controller 0 $(SongPartCount)” but Cantabile replaced the last field with a 0 because bindings like those don’t support variables. 2) I couldn’t locate a user guide for ReaJS - the RealEffectsGuide includes all the other effects but not this one. Is there such a guide? If so, could you send me a link.

I do what @Toaster does for my Keylab MKII. I just have a binding for every state of every button. So with 8 buttons I have 80 bindings; 10 of which that react to each button push.

Hi Tom and Toaster -
What I’m looking for is a bit different - some of my songs have multiple states, some do not, so what I’m hoping to do is illuminate buttons automatically on the keyboard based on $(SongPartCount). I could use the approach you’re suggesting by having Song OnLoad send a MIDI message back to a loopback port as though someone had pushed a button on the keyboard, but when I try to use $(SongPartCount) as a variable in the MIDI message, either as a note or as a CC, it gets replaced immediately by a 0.

You don’t have to use a loopback, just use a On Song load binding to set the state of the lights when the song loads…


But how do I test the value of $(SongPartCount)? I can do a “on song load send CC 37 0”, for example, to the first light, but what if I want to say “if $(SongPartCount) is 0 send CC 37 0; else send CC 37 40”? That’s the problem I’m running into.

Use a SysEx expression - these can use variables. Simple example here - this binding sends the number of the loaded state as a string whenever the state changes:

Then, inside ReaJS, you use the function midirecv_buf to get the sysex message, then extract the string, convert it to a number and then deal with that as you like…

There is a nice manual for the JSFX language here:



1 Like

@Torsten 's method is, no doubt cleverer than mine…

I’m gigging all weekend, but if you can’t get what you want, I’ll show you what I’ve done and see if that works for you…


Hi Torsten,
I’m getting closer, but running into a problem that might have a simple answer.

If I use a statement such as
(recvlen=midirecv(0, msg1, msg23) > 0) ?
(midisend(0, 0x90, 69, 127));
everything works quite fine. The code sees an incoming note, and replaces it with the output I selected. It does not see sysex by design, and so passes it through.

But if I do
(recvlen=midirecv_buf(0, buf, 1000) > 0) ?
(midisend(0, 0x90, 69, 127));
then it sees neither a sysex sent to it nor does it see a note sent to it (the note gets passed through rather than processed). Any idea why this isn’t working? Does buf need to be defined specially so that the statement recognizes it as a buffer. I also tried midirecv_str but that fails as well.

Thanks in advance for your help with this. Its a great solution.

I found a workaround, so if there isn’t a quick solution I can use the workaround. The workaround is to use a Cantabile sysex to CC conversion filter.

Little known trick… you don’t have to send sys-ex events with sys-ex bindings. You can also encode regular short midi messages too. And, you can send multiple messages with the one binding.


  • 0xB0 = Channel 1 CC Event
  • 81 = CC Number 81
  • int(SongPartCount) converts the song part count from string to integer
  • 0xB0 = Channel 1 CC Event
  • 82 = CC Number 82
  • int(SongPart) converts the current song part number from string to integer

ie: CC81 is the number of states, CC82 is the current state.

So if you were to step through a song with three states, you’d see this:

You can route that directly into reajs and then do your scripting there.

Does that help?


I wasn’t able to read the messages with reajs - they still came across as sysex messages, but the sysex to CC converter did the trick. Everything is now working perfectly. I use a song onload to trigger CC121 with SongPartCount as an argument, and State change to trigger CC122 with the SongPart as an argument. The keyboard sends CC’s 37 to 45 if I want to manually change the song part - the new part is shows as orange until the part actually updates. Thanks to everyone who helped. If anyone is interested in doing something similar with a programmable keyboard, this is the code I put into the reajs module -