MIDI Channel Rotate

Is it possible to set the Sensel to MIDI channel rotate all the time when using MPE?

At the moment, if I lift a note, and play a new note, it repeats the same MIDI channel. It would be better if for each note it incremented to the next available channel… at least for my general use.

The main reason for this is playing presets in MPE mode that weren’t designed for MPE specifically. If those presets have a long release time envelope, then my next note will also control the level of the previous note (still ringing) and you get a bit of a mess. Rotating 16 channels all the time greatly reduces the chance of this happening.

Could at least be a preference option?

cheers
Dan

We can consider it as an option. For the most part, MPE synths seem to have this handled correctly since their voice allocation happens independent of channel. However, I can see if you are are using multiple monophonic instruments to create a polyphonic instrument, such “round robin” behavior would be better. This is how Live 11 handles it’s voice number in MPE, for what it’s worth, and passes those numbers as channels when using the External instrument device.

1 Like

Thank you for your reply Peter. Indeed, I haven’t had any trouble with soft synths with a dedicated MPE mode, but I’m scripting Kontakt for MPE and using the MIDI channels to sort out the voice allocation.

Aha. In that case, you could probably shim something similar in the script to Live’s round robin, and rely on that voice count/allocation rather than the MIDI channel. Count note-ons and mod it by 15.

I can do that easy enough with the note on/off data… I can’t seem to find a way to untangle the CCs without using the MIDI channel though.

Good point. My off the cuff coding is worthless!
You can bank on data coming in in a predictable fashion. The first message from a contact is Pitchbend. For example, a quick tap gives me:

14:43:41.256	From Sensel Morph	Pitch Wheel	2	0
14:43:41.256	From Sensel Morph	Control	2	74	17
14:43:41.256	From Sensel Morph	Channel Pressure	2	62
14:43:41.256	From Sensel Morph	Note On	2	60	44
14:43:41.264	From Sensel Morph	Pitch Wheel	2	0
14:43:41.264	From Sensel Morph	Control	2	74	17
14:43:41.264	From Sensel Morph	Channel Pressure	2	61
14:43:41.272	From Sensel Morph	Pitch Wheel	2	0
14:43:41.272	From Sensel Morph	Control	2	74	17
14:43:41.272	From Sensel Morph	Channel Pressure	2	63
14:43:41.280	From Sensel Morph	Pitch Wheel	2	0

You’ll have to do some parsing of MIDI streams for this. You can look for “new” bend messages by looking at the channel, if it’s different from the number stored as “mostRecentCH” then increment your voice number and direct all messages on that channel to the new voice number and store a new “mostRecentCH”.

Something like that. No doubt it would get a bit more complicated, but it seems solvable since there is a very reliable pattern.

The problem is that the MIDI channel doesn’t change though :slight_smile: If I play a new note, with no other notes held, it repeats the same MIDI channel — this is the root of my problem.

Ok, how’s this - increment your voice number using note-off? It’s the last message in a stream of data for any contact.

1 Like

That’s both the problem and the solution.

I’m not as familiar with Kontakt, but I can build a quick demo in Max. Maybe some of it will translate.

(I haven’t actually tested this code. Hopefully, it works? Fingers crossed!)

This looks quite similar to something I tried this morning… basically using the MIDI channel as an index to look up a voice allocation map. Changing which voice channel is assigned to each MIDI channel at any note off or note on.

This resulted in ringing notes though, because pressure 0 would arrive AFTER the note off on the same channel as the note off a millisecond ago, etc. … by then my script has updated the voice allocation because of the note off. (Kontakt might be re-ordering MIDI data because Peter says above the note off should be the last thing, so not sure about that).

It’d all be so simple if Morph round robin’d the MIDI channels like the Linnstrument. :wink:

Don’t worry about aftertouch yet. Filter it out if you have to so you can focus on the stuck notes.

I’m sure you tested this far:

  • Press a note. It is routed to channel 3.
  • Release that note. It turns off, on channel 3.

But here’s where things are more touchy:

  • Press a note. It is routed to channel 4.
  • Press a second note. It is routed to channel 5.
  • Release the second note. You should get your note off on channel 5.
  • Release the first note. You should get your note off on channel 4.

Press and release chords in various note orders, and just watch the resulting data. Do the note off channels all match their note ons?

I’d wager they do not.

If you look at my max screenshot, I tried to spell out the timing.

  • Incoming MIDI messages are sent down two paths, in a specific order.

  • The first copy goes down a path to the channel offset decider.

That path creates a list, where each entry is like “when you see channel 2, make that 7.”

  • When that operation completes, the second path takes its copy to be offset and played.

That path takes every message, and says “hey, I’ve got some data for channel 2”, checks the list, and sees that those should be on channel 7 now, and makes the change.

It is critical that the list entry for a given channel not change until the note on that channel ends.

So, that’s what the first path is all about - establishing the right timing.

(I’ll break that down next.)

So, back to that first path…

We’re splitting this path further, into 15 blocks now. 1 for each channel. They’ll merge back in a minute, but we need to track each channel separately. So, let’s look at one block.

Within each block, we’re going to need note data and pitch bend. I filtered out everything else.)

There’s a gate. It’s either open or closed, and when it’s closed, nothing can get through it. Pitch bend is sent through that gate, because pitch bend is always the first bit of data received.

But before it reaches the gate, a bit of logic happens. Each bend message triggers two events, in a specific order. First, they try to send through the gate. Then, they close the gate, if the gate was open. So only the first message goes through.

The gate is initially open, or the first note wouldn’t work. Once triggered, it’s almost always closed. The one thing that re-opens it is a note off message on this channel…

So, when a pad is pressed, the first message received goes through that gate, and nothing else does until that note is released. When another message goes through, we know it’s a new press.

Good so far?

When a message passes through the gate, it triggers the channel number that this block represents to be output from that block.

So, each time you press a pad on channel 3, you get a “3” out of the “3” block, and nothing out of the other blocks.

(When that works, clone out all that code to make your other blocks. The only thing that should change from one instance to the next is what channel you’re filtering down to, and which number is output at the end.)

So, that’s the overall timing.

Beneath those blocks, you receive the channel number from each press, and those numbers trigger two events, in this order:

First, increment a counter, and make note of its output.

Second, pair your channel number with the newly received output of your counter, and put those in the list.

For the example above, we know the press was received on channel 2, and the counter tells us our next round robin channel is 7, so we add “2, 7” to our list.

And that’s it.

Don’t worry, I understand your logic, but the bug remains.

They are not stuck notes really, as I mentioned in my first post, these are release envelopes.

The problem is that the aftertouch comes AFTER the note off, at least in Kontakt it does.