MPE isn’t necessary to start a unison voice on another channel. You could just start a unison voice on another channel. If it’s MPE, other rules come into play.
Again, I gave a very specific example: In MPE, channel 1 is global. If you receive a CC on channel 1, that applies to all 15 voices. And if you receive a note on channel 1, as stupid as this is, it’s a fifteen voice unison. Obviously, you should idiot-proof against that on the synth end, but we can’t count on everyone doing so because it’s expected behavior.
Fortunately, we are talking about this exclusively for non-default modes.
Something like a guitar layout, for example.
And in that example, I would probablly want every row on a different MIDI channel to begin with. There’s no overlap on any given string, so that handles the conflict transparently and the channels have meaning.
–
Me, I’d probably divide the grid into zones of four columns. And I explicitly want each of those controlling a different instrument, so once again, each zone gets it’s own MIDI channel, the conflicts are handled organically, and channels have meaning.
–
Something generative (otomata, game of life, etc), we should also handle on a case by case basis.
Let’s consider polygomé.
I see several choices, some more useful than others…
(brace yourselves…)
Option 1: single channel "piano style"
- If a note is active, pressing it again does nothing.
Option 1A: single channel "crazy pianist"
- If a note is active, new attacks are not sounded, but we keep track of how many fingers are on that key, and the note doesn’t release until that number is zero.
Option 2: single channel "one string"
- ignore duplicates if they occur simultaneously. If one of those voices occurs after the other, end the first note and reattack.
A very big side note here:
It’s less obvious that this should be handled at the app level and not on some global layer. But it should be handled by the app. Because the app can cleanly end that note without having to blindly suppress an unwanted note off event later. Making this global would either risk stuck notes, or creating unwanted gaps.
With any of those approaches, the big plus is simplicity – the user doesn’t require any multi-channel support on the synth end. They could use these on any synth.
Option 3: multi-channel "arbitrary"
- If only one note is active, that’s on channel 1. If an overlap occurs, the unison note sounds a channel higher.
Pro: a user can choose to ignore duplicates by filtering their input to receive only channel one.
Con: a user could be confused by unexpected notes popping up on another channel at seemingly random intervals, because channel selection wasn’t intent driven.
Option 4: "phrases"
- When one key is pressed, all notes originating from that press are on channel 1. press a second key, and each note generated as a result are on channel 2. If you press a third note, you’re playing three melodies, cleanly separated onto three channels. (Don’t shift higher channels down when a note is released. Just start new melodies on the lowest unclaimed channel)
Pro: the user can choose how they handle polyphony. Should these melodic lines play on different instruments? Same instrument, lower velocity? Multiple instances of the same synth without any changes? All of that - it’s none of our business.
Con: the user might have preferred one of the single-channel options.
I like supporting many options, but I don’t like having to configure them every time we load a patch.
I like @zebra’s suggestion to have program change nessages select between apps, or modes, but I think I want those to be more dynamic.
Like… a ridiculous JSON file full of configuration data. Maybe I want to use six of my 128 presets on one app in various configurations, so I never have to touch those menus again. It’s a thought.
(Using Teensy 3.6’s built in SD reader for that is probably overkill, but the option to pull the card out and edit a text file is appealing.)