How to re-map incoming MPE channels to the order of arrival?

    MaxMSP

    Lars Kristian Lia's icon
    Lars Kristian Lia's icon
    Lars Kristian Lia
    Jan 21 2023 | 2:36 pm
    Hello,
    I found this thread https://cycling74.com/forums/how-to-route-incoming-midi-messages-by-midi-channel . I have a similar problem, though I want to be able to control any sound generator outside of MAX as well, like through Ableton Live or other software. I've read through the linked topic and maybe I don't understand completely, but I could not get this to work in my situation. I am fairly new to MAX.
    .what I want to figure out How do I «distribute» MIDI note information contained in a MIDI channel, based on what spot in a sequence of 16 steps it is activated? Example: If I trigger a note when first turning the controller on, it is assigned to the first spot in a sequence of 16 steps. The sequence moves through 1, 2, 3, etc.-16 and rounds robin. I have set it up to use [coll] instead of counter to decide which MIDI channel it is routed to, so that I can change the MIDI channel order throughout a performance. [counter] is used to keep track of the steps.
    The screenshot shows my setup without all the testing I have done, and description of what I'm trying to achieve:
    .context I also work with external MIDI devices that send data on multiple channels, like Neil in the other thread. I've analyzed multiple controllers MIDI channel selection behavior that makes for the polyphonic expression. Multiple manufacturers present it as a round-robin selection, but still they behave differently. Linnstruments MIDI channel selection behavior is different from every other MPE-controller that I´ve tested. I prefer how it works, and want to «force» other controllers like it to behave the same way. In my artistic practice I’ve made a digital instrument counterpart to the Linnstrument, and I want to figure this out to future proof my instrument.:)
    I appreciate any pointers! Thank you for the help. Let me know if there is something I could have explained better. Sincerely Lars K Lia https://www.instagram.com/larsklia/

    • Andy Maskell's icon
      Andy Maskell's icon
      Andy Maskell
      Jan 21 2023 | 7:57 pm
      Can you be a little more specific about your aims? Do you simply want to send each successive midi message to the next midi channel in a cycle, do you want to send each message type to a separate channel, or do you want to send all messages that arrive between one note and the next to go the same channel as the leading note? Or something else?
      Share
    • Lars Kristian Lia's icon
      Lars Kristian Lia's icon
      Lars Kristian Lia
      Jan 22 2023 | 11:44 am
      Hey Andy - thank you so much for reading my post and checking if you can help! I want to send each successive MIDI message to the next MIDI channel in a cycle. I think this is what I mean, english is not my main language.
      Example: .Event/movement 1 So if I trigger any note on my MIDI controller (with all continuous MIDI channel information connected to that note) and the controller decides it will assign the note to MIDI channel 6, then I want to be able to say to the note that "no, you were first in line, so I will place you in MIDI channel 1" with all the information connected to the note. The deciding factor should be the which notes are pressed first in a ascending order 1-16.
      .Event/movement 2 If i have released the note that was placed on MIDI channel 6 internally on the controller, and activate the same note again, it might assign itself to another MIDI channel or again to MIDI channel 6. Regardless of what channel it assigns itself to, this should in MAX now be moved to MIDI channel 2.
      If i triggered multiple notes - all notes should be able to play simultaneously.
      If this was just more confusing, I apologize. 😁 This may not be the right way to explain MIDI, but I hope it explains what I'm trying to achieve.
    • Source Audio's icon
      Source Audio's icon
      Source Audio
      Jan 22 2023 | 1:11 pm
      if you loose relation note number - note channel you will be in trouble. Unless you ignore note off messages and use makenote instead.
      then all other channel messages - pitch bend ? aftertouch ? polypressure ? etc If you know midi, then you know it travels as train composition Status byte, data taken this input: 144 46 100 145 48 120 208 66 224 0 100 129 48 30 160 46 100 what should your midi output look like ? 1- note On 46 100 > out chan1 2- note On 48 120 > out chan2 3- aftertouch > out chan ? 4- pitchbend > out chan ? 5- note off 46 > out chan ? 6- polypressure key 46 > out chan ? ----- this can work only if you use only note & polypressure, and ignore all other channel messages. than make pitch - channel reservations for each held note.
      all other channel messages could be routed to ? maybe send to all channels ?
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 22 2023 | 6:31 pm
      I see in your screenshot that you are using a Linnstrument. This device can already work in MPE mode and does everything you ask for, except the channel order which is kinda random in MPE.
      In case you don’t know how to set the Linnstrument to MPE: Manual, section "Getting Started" and look near the end of paragraph 2 for the line "If you have an MPE synth ..."
      You just need to find a method in Max that remaps the incoming Linnstrument channels to the order you want.
      Maybe your real question is "How to re-map incoming MPE channels to the order of arrival" ?
    • Lars Kristian Lia's icon
      Lars Kristian Lia's icon
      Lars Kristian Lia
      Jan 22 2023 | 8:07 pm
      Source Audio, thank you for your reply, though I am not sure if I got my needs presented well enough. My MIDI output should look like an ordinary MIDI output. I've routed it through IAC-driver.
      Thank you for your reply Peter, yes that is probably a good way to phrase my question "How to re-map incoming MPE channels to the order of arrival?". I will change the topic name.:) About MPE, yes the channel order is usually random, though Roger Linn with his Linnstrument has in fact made the MIDI channel selection behavior in ascending order. This is a "feature" I use in my digital instrument. With new controllers like the Osmose, and Erae coming out, I've been wanting to make those controllers also behave this way (MIDI channel selection).
      "You just need to find a method in Max that remaps the incoming <midi controllers> channels to the order you want." - Yes! You are absolutely right, though it was harder for me to figure out than I expected.
      So currently I am stuck is at the distribution process itself. I am working on linking the number of input, which goes 1-16 and round robin, to the MIDI channel of the incoming note and send the information further so it selects that information and send it along. It would be great if [midiselect]'s @ch attribute had the possibility of being changed with an incoming message. Please let me know if this actually should work, and I could have just been doing it wrong.
      Thank you for all your help!:)
    • Roman Thilenius's icon
      Roman Thilenius's icon
      Roman Thilenius
      Jan 22 2023 | 9:15 pm
      there are many diffrent ways how you could map MPE to custom channel round robin mechanisms, so it is hard to suggest an ideal way.
      but i dont see how you could find out if some y-axis value from the third key you pressed on the osmosis belongs to the third note, unless you treat the MPE data as MPE data.
      if i am not mistaken you want to build a synth in max and control it by the linnstrument via MPE. so why not use MPE style messages in max and directly send it in your poly~? i.e. use [mpeparse], not midiparse, and you should have those outlets you are looking for. of course the MPE design sucks a bit, but i guess it is doable to do [ - 1] to the MPE channels to end up with a proper 1-15 counting.
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 23 2023 | 12:59 am
      Maybe something like this gives you an idea:
      The input comes from a Roli Seaboard (MPE). I disassemble the midievent message and when the 4th byte (voice number) changes I replace it by the next value of a 2-16 counter. Then I put the message together again.
      Of course you can set the counter to 1-16, I just chose 2-16 to test the result with a software MPE synth. I still do not understand how this MPE thing keeps track of voice numbers. But the synth plays fine, although I expected my rude intervention to destroy the system.
      I don’t know what you are going to do with an MPE event, but the channels are set according to your request :-)
      Max Patcher
      In Max, select New From Clipboard.
      Show Text
      SORRY, THIS DOES NOT WORK. SEE SOURCE AUDIO’S EXPLANATION BELOW.
    • Roman Thilenius's icon
      Roman Thilenius's icon
      Roman Thilenius
      Jan 23 2023 | 3:37 am
      >> I still do not understand how this MPE thing keeps track of voice numbers.
      everything is simply sent with the respective channel. i.e. the controller has to take care of that.
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 23 2023 | 1:22 pm
      I searched several times for how the controller does this and found no information. But today, overnight, I understand it. MPE controllers have all sensors on each key. They could have introduced additional MIDI events like Poly Pitchbend and Poly Slide, but that wouldn't be compatible with anything. That's why the channel shuffling.
      A simple system, I'm just sometimes a bit slow ... :-)
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 23 2023 | 1:53 pm
      @Lars Kristian Lia Here is another version:
      SORRY, THIS DOES NOT WORK. SEE SOURCE AUDIO’S EXPLANATION BELOW.
    • Source Audio's icon
      Source Audio's icon
      Source Audio
      Jan 23 2023 | 3:07 pm
      this does not work. you should expect that holding 2 keys and pressing them to create per note aftertouch shoul keep that aftertouch linked to THAT 2 keys. but it will trigger the counter to cycle...
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 23 2023 | 4:14 pm
      Oops. You are right. Have not tested it properly. This may need dynamical mapping. I don’t know how to do that.
      Maybe someone else has an idea.
    • Roman Thilenius's icon
      Roman Thilenius's icon
      Roman Thilenius
      Jan 23 2023 | 6:08 pm
      @peter exactly. there are no hardware controllers where note-specific CCs can be created with something else than the key. only if you want to create MPE style controller data in a software you would have to care about the design. it is easy to get confused about what MPE does when looking at these keyboard controllers, as there always was key pressure.
      and the truth is, one could as well build a seaboard or continuum which used key pressure for Z and key pressure on channel 2 and 3 for X and Y. it would save you 13 channels while at the same time it would raise the max number of running notes from 15 to 128.
      which is why i think MPE in its current state is a failed system: there is no realistic application yet which could make use of all the things you could do with this type of messages. it is basically only used to have a second dimension of what is possible with key pressure.
    • Lars Kristian Lia's icon
      Lars Kristian Lia's icon
      Lars Kristian Lia
      Jan 23 2023 | 6:09 pm
      EDIT: I may have found a solution based on your input. Screenshot at the bottom of post. Hello everybody, Very interesting! The idea seemed simple, but I have understood I have to learn more - so I really appreciate all your input.
      I see I have to read up on status and data byte to understand this fully. But I'll be so bold and use this opportunity to ask about what you maybe consider basic stuff.😁 So mpeevent outputs the following information: - mpeevent 'number' 'number' 'MIDI channel' 'number' 'number' 'number' -
      If I want to unpack this - where do I find the aftertouch, pitch, and note on/off? Can anyone fill in what function each number has?
      @Roman Thilenius I see! I have made a sampler instrument where the MIDI channel is the deciding factor of what sample is played. So each MIDI channel is connected to their own set audio file.
      @Peter Ostry Great Peter! I will have to look more into this, even if it proved wrong for. From the other thread it seemed like [mpeevent] was the way to go, though I must admit i did not understand completely.
      If I can learn how to decode the message and be able to route it out into a [midiformat], this seems like a solution to look more into for me. A couple of objects I do not have so much experience with, so I will definitely read up on them.
      @SOURCE AUDIO I see! - very good demonstration video and explanation. EDIT: In an effort to explain how I saw it working, it seems I may have gotten on my way to a solution. I have not yet tested with my instrument, and it might be that I could clean it up a bit, and add more functions, but after testing it seems I have made a solution (your input really helped me along). Here it is:
      Lars
    • Roman Thilenius's icon
      Roman Thilenius's icon
      Roman Thilenius
      Jan 23 2023 | 6:12 pm
      before you distribute note-events on different patchcords you might want to write stuff in lists.
    • Lars Kristian Lia's icon
      Lars Kristian Lia's icon
      Lars Kristian Lia
      Jan 23 2023 | 6:15 pm
      @Roman Could you give an example if you have the time? Do you mean to clean up the patch, or for some other reason?
      I've heard I tend to take the long way round to my goals in MAX, so it wouldn't be surprising if there are better ways.
    • Roman Thilenius's icon
      Roman Thilenius's icon
      Roman Thilenius
      Jan 23 2023 | 11:35 pm
      i wrote that before your last post, so it was targeted not at this new patch. :)
      mostly for design reasons. indexes 1-16 for midi channels (or mpe channels, or poly voices) is a very easy to handle task to write everything into a list.
      the "running notes" list could look like "x 60 61 62 x x x x x x x x x x x x" where simply the position is the channel. when you have lists of known lenght you can then often do 90% of the further processing using zl and vexpr.
      back in the days i had to write my own, but nowadays zl.stream can serve as buffer for the last n inputs.
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 24 2023 | 8:04 am
      This version should work? It does here. With a Roli Seaboard, multiple simultaneous aftertouch, pitch bend and CC74 are fine.
      The MPE keyboard must be set to 15 channels and "Lower MPE Zone" (voice numbers 1-15). Otherwise the voice numbers are not correct for the patch.
      A named [coll] acts as a mapping table. With each new note the current voice number is stored in the [coll] along with a new channel number generated by a counter. After that, the 4th list element (voice number) of the mpeevent runs through this mapping and gets a new voice number. As long as any events with this voice number come in, the mapping remains.
      In the example the current content of the named coll can be checked in the jit.cellblock.
      Max Patcher
      In Max, select New From Clipboard.
      But ...
      @Lars Kristian Lia With this method you won't get 16 channels. MPE has only 15 and one master channel. [mpeparse] returns -1 as voice number for the master channel. You can't map that as a normal voice number, because hardly anything comes in there.
      I think for 16 channels you would have to set the keyboard/instrument to a single channel or to multichannel, but not to MPE.
      The advantage is that without MPE, there are no event groups tied to specific channels, so you can get by with a simpler patch. For example with something like this:
      The downside is that you can't play an MPE synth with it.
    • Source Audio's icon
      Source Audio's icon
      Source Audio
      Jan 24 2023 | 12:25 pm
      I see it simple: you use a note number or if you want mpe voice number to grab all other midi messages which that mpe source sends with it and assign them to a specific midi out channel 1 - 16. In - Out routing pairs. all good. Once note is off, that output channel is free to assign again. even after getting that simple task to work, you are left with set controller values per channel, which will get applied to any note that again gets assigned to that channel.
      Example : after playing for a while, we release a note assigned to ch 5, and leave that midi out channel 5 destination device with pitch bend 55, cc #11 at 80, and who knows what else. Next note assigned to channel 5 will get greeted with that . means on each note release one should reset all CCs & PBend
    • tyler mazaika's icon
      tyler mazaika's icon
      tyler mazaika
      Jan 24 2023 | 1:38 pm
      The scenario Source Audio describes, in my experience, is handled differently by different manufacturers. For instance, in Ableton's "Wavetable", the per-channel data from the previous note is all forgotten (or abandoned intentionally?). But in u-he Hive, it persists. I have no idea which implementation is more typical / canonical.
      With regards to voice/channel re-allocation, I would also mention that I don't think that assigning new voices on note-on in a round robin is optimal. Basically, I would think it's more important to track note-offs and then for new note-ons to choose the channel that was released furthest back in time. Otherwise you are more likely to have new note-ons choking earlier synthesizer voices that are in a long Release stage. But this seems likely to be another area that is really per-manufacturer specific.
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 24 2023 | 6:14 pm
      Source Audio I see it simple: you use a note number or if you want mpe voice number to grab all other midi messages which that mpe source sends with it and assign them to a specific midi out channel 1 - 16.
      In the second example, MPE to standard MIDI, I did exactly that, didn't I? Only that I didn't set each parse output individually to the desired channel, but the channel for all events. The combination [midiformat][midiparse] at the end is just a trick to get the new midievent for a synthesizer and generally "get back to normal". I do this quite often.
      If you talk about the first one, the MPE->MPE example, this does not work with individually channeled events. With single events on the new channel you would convert everything to standard MIDI and have to convert it back to MPE. But it may be that I missed something with the MPE objects, I practically never use them. Maybe a MIDI->MPE conversion is easier than my construction with the mpeevent. Anyway, I didn't see any other option than dynamic mapping with the [coll] after you exposed my first attempt as "not working".
      Source Audio Once note is off, that output channel is free to assign again.
      Releasing is not necessary. Eventually something will come on this channel and then it will be remapped. Nothing happens in between.
      Source Audio Next note assigned to channel 5 will get greeted with that . means on each note release one should reset all CCs & PBend
      Why? Now, I haven't tried what an MPE synth does when you set pitchbend and colleagues to zero after note-off while it's still sounding. Emotionally, I wouldn't do that.
      tyler mazaika "I don't think that assigning new voices on note-on in a round robin is optimal. Basically, I would think it's more important to track note-offs and then for new note-ons to choose the channel that was released furthest back in time."
      With my controller, I have never heard any problems with choppy notes that MPE could be responsible for.
      1. When I play without MPE, no one can tell me when to press the same key again. What's the difference there? At least with the Roli RISE 1, some number is assigned, as [urn] would do (perhaps musically a bit smarter). But I imagine you can do more with sophisticated programming than just playing the keyboard allows.
      2. (and contrary to what I said in #1) Shouldn't that be regulated by the synth? If the synth's polyphony is higher than 15, I hope it can handle duplicate channels with and without MPE.
    • Roman Thilenius's icon
      Roman Thilenius's icon
      Roman Thilenius
      Jan 24 2023 | 7:38 pm
      when you use an MPE controller with an MPE VST you should be fine with midiin->prepend midievent->vst~ and then do your settings on either side, but not via max programming.
      maybe this is a dead end, but i was just thinking that when you want to implement a custom method how to reach a VST plug-in´s multi mode from an MPE input, why not just use midiin and work on the raw midi bytes? eventually this leads to more straightforward methods than the use of midiparse / mpeparse type of objects.
    • tyler mazaika's icon
      tyler mazaika's icon
      tyler mazaika
      Jan 24 2023 | 8:29 pm
      @Peter re #2: Yes, I agree that should be regulated by the synth. Basically though it still opens up a can of worms of "how does each manufacturer prefer it?" and I think it's very niche and ill-defined. Because you can definitely imagine that someone wants to be able to taper the Pitch Bend, for instance, on a released note's channel, while also needing that channel for a new note's Pitch Bend.
      It sounds like your setup isn't having voice allocation issues (great!), and perhaps I'm just sensitive to this because Live does unintuitive things with MPE channels that cannot be reasonably worked around.
    • Peter Ostry's icon
      Peter Ostry's icon
      Peter Ostry
      Jan 24 2023 | 10:46 pm
      Roman Thilenius Don't hit me, I'm just the messenger :-) I don't manipulate MPE streams myself. I play with the Seaboard to suitable synths and that's it. But the original question here was how to make a controlled sequence out of random MIDI channels. The patch is not really complicated. Remove all the gimmicks and comments and there is not much left.
      As for working with raw MIDI - I couldn't do that because I don't understand raw MIDI. But if you think it's easier to analyze each packet from an MPE controller, manipulate it and pass it on in the right context as MPE again, then that would be the better method.
      Or someone calls the controller manufacturer and tells them to assign the channels in order. It is not clear to me anyway why the channels are random and I don't see any such suggestion in the MPE specification. In my case it seems to be just a strange idea of Roli. tyler mazaika I hope that the voice allocation is ok. I don't work with Live, just testet in Max with a couple of software MPE synths (Falcon, Bazille, Kaivo, Equator).