Define a key and enumerate value using [dict.pack] ?

srs's icon

Is it possible to define a key and enumerate a value based on unique keys using [dict.pack] ?

I have sysex data coming in from an Erae interface which has a unique id for each gesture and I need to store these in a dictionary based on this id, and then assign a midi channel to each new key-value entry.

This video shows the data coming in displayed using dict.view:

Screen Recording 2025-05-26 at 12.42.53.mov

I need to put this data into a nested dictionary using the id as the key for each sub-dictionary, and then assign a midi channel value that is enumerated as each new id is received. The dictionary example below is closed to what is should look like, but I can't count unique ids to assign each dictionary its own midi channel.

Does anyone know if something like this is even possible using dictionaries?

Has anyone used dictionaries to store incoming data streams in this way?

TFL's icon

Here's how you could set the id as the dict key:

This assumes /id comes first before other OSC messages.

Also, I removed @triggers 0 1 2 3 from your [dict.pack], as you can probably handle message ordering in your sysex-to-osc conversion. You probably really need only one trigger, placed on the latest received data (here it would be /x).

To make things simpler, you could even send all data in one OSC message, or even build your dictionary where you receive your sysex and send a serialized version of it through OSC, then you would just need a [dict.deserialize]

srs's icon

Thanks TFL! This is really helpful and does exactly what I am trying to do with the id as a key.

This next question is a bit of a long shot, but do you have any advice on assigning a midi channel in the sub-dictionary for each contact. If I have an /action message that is 0 for each new contact, it feels like I can use this to iterate through midi channels but it keeps getting the channel assignment confused.

TFL's icon

Your example won't work because [int] isn't filled with any value, so it will always output 0. Instead, I would directly plug the output of [counter] to the ch: inlet of your [dict.pack]. But again, there might be timing issue depending on how you convert sysex messages coming from your erae device to osc messages addressed to Max.

I don't know how these erae devices work, so what comes next is based on assumptions!

If I understand correctly, you want to dedicate one MIDI channel per id, and whenever a new id pops up, it comes with an action 0. Problem is, you are limited to 16 MIDI channels (or 8 in your case, from 2 to 9), and your logic will attribute a midi channel to the 8 last new ids, but I guess this won't necessarily match the actual currently active ids. For example let's say you have data coming from id 111 for which MIDI channel 1 is assigned. Then you have 10 new incoming ids from 112 to 121, meaning that only ids 114 to 121 will have a MIDI channel assigned, as follow:

id ----- ch.

111 ----- 1

112 ----- 2

113 ----- 3

114 ----- 4

115 ----- 5

116 ----- 6

117 ----- 7

118 ----- 8

119 ----- 9

120 ----- 1

121 ----- 2

But if your id 111 is still alive and comes back here, a new midi channel will get assigned to it (3), different from its previous one (1). So depending on what you want to do with that, you might need to think about a different prioritization logic, or even different routing logic.

Which brings me to more questions. Right now it seems that you are doing the following:

Erae --(sysex)--> ???? --(osc)--> Max --(midi)--> ????

Is there any reason for all these steps? Can the final receptor (the last '????') only receive MIDI?

Is there any reason why you can't do

Erae --(sysex)--> ???? --(midi)--> ????

or even

Erae --(sysex)--> Max --(midi)--> ????

srs's icon

Yes, those assumptions are spot on. Thanks for the deep dive into this problem!

The workflow looks like this:

Erae --(sysex)--> Python --(osc)--> Max --(mpe midi) --> Ableton Max devices

The reason for this is that there currently isn't any thing in Max that works with the Erae sysex data. I'm using the Erae python implementation supplied by Embodme which unpacks the data into usable values (https://gitlab.com/embodme/erae_api_sysex)

I think somewhere in your approach is a potential solution as it seems to be about getting the routing logic right. There is an /action value of 2 for the release of a contact which could release the midi channel (with a maximum of 8 or 10 for each finger action)

If the osc message order is always id then xyz then action, it might work. I'll test it later and report back.

Thanks again for your help!