Hey Hanz, first off thanks a ton for the blog post on the LiveAPI usage! Helped me a ton navigating through things and getting something basically running. I'll try and add some info on my blog as well to help get people up to speed.
I'm working on getting a LiveAPI script running that does Sysex translation for the Mopho/Tetra and have been running into the same problem. It looks like the best way to get it to work is specifically filter out all the Sysex that is interesting and forward it as CC/Note messages to ableton and vice versa. The Python script does all the interpretation of the Sysex and simply forwards all other information directly onto the script itself using midi_send.
Sending or receiving Sysex to Ableton through M4L by sending raw MIDI is pretty much useless since it all gets filtered out. A 3 byte string could be useful if we chained them together but it sounds like the kind of thing that could mess up the internal communications of Ableton or cause some weird problems we can't troubleshoot easily.
Now that I have NRPN translation working I'm thinking we can create a series of NRPNs (say starting at index=10,000 which I doubt very many devices use) that are used only to trigger and receive Sysex commands from the device.
So the synth sends a Sysex message for "Refresh display" and the value of "DISPLAY_ON" to MIDI, which is sent from the MIDI interface into Ableton. Ableton sends the Sysex message to the MIDI Remote Device script of the device(s) that are receiving the message. The Python script receives the Sysex message and double checks to make sure that the device ID is the same as the one it expects. If it is, it's from the correct synth and we parse the received Sysex data. The Python script looks at the next few bytes and determines it's a "Refresh display" message and looks in a hash table seeing that "Refresh Display" coincides to NRPN #10,002. It then determines the value of the "Refresh Display" command from the next Sysex bytes is DISPLAY_ON=1. So we send an NRPN message of Index=10002 and Value=1 out the Python script to the Ableton device. The Ableton device (or M4L patch) sees the NRPN message and has to re-interpret it as a "Refresh Display" command with value DISPLAY_ON.
In the same vein, if the Ableton device wants to send a "Refresh Display" command with value DISPLAY_OFF=0 back to the synth, it will have to do it in reverse. The device (or M4L patch or whatever) sends an NRPN message of Index=10002 and Value=0 to the MIDI output. The Python script picks up the CC messages and must interpret them as a special value. Since we have control over the order of the NRPN message the Python script would only have to look for an NRPN MSB message that was the one it's looking for. When it sees that particular CC message it waits for the next 3 to form a full NRPN message then interprets that and sends out the correct Sysex message to the Synth.
A translation layer isn't perfect but at least it would allow Sysex messages to be sent and receievd in realtime, which is the one issue I have with the UDP method
Hopefully that sort of answered your question but to get it directly... a Python 'tuple' as you described could be any type of MIDI message. The Python script will have to look for it and can save/disassemble/reassemble the messages into whatever it wants. Sending Sysex directly from M4L is just asking for trouble.
Hanz_Petrov wrote:Hey guys,
I've been fooling around a bit with the sysex thing, and I've found two ways to get sysex data to a control surface using only Max for Live and a Framework-based python script. Unfortunately, neither way seems quite satisfactory (and only one works properly).
1. Define the sysex as a tuple in the script and set up a method which fires it to the controller, using self._send_midi(SYSEX_MESSAGE).
This is the python code:
Code: Select all
SYSEX_INQUIRY = (240, 126, 0, 6, 1, 247)
def send_sysex(self):
self._send_midi(SYSEX_INQUIRY)
From Max, a "call send_sysex" message sent to a live.object with a ControlSurface path will trigger the message.
When I "uzi" this on a Standard MMC Device Enquiry string (240 126 0 6 1 247), the messages fire at under 10ms. From the MIDI-OX log:
Code: Select all
4987907 1 9 240 Buffer: 6 Bytes System Exclusive SYSX: 240 126 0 6 1 247
4987913 1 9 240 Buffer: 6 Bytes System Exclusive SYSX: 240 126 0 6 1 247
4987922 1 9 240 Buffer: 6 Bytes System Exclusive SYSX: 240 126 0 6 1 247
4987929 1 9 240 Buffer: 6 Bytes System Exclusive SYSX: 240 126 0 6 1 247
4987934 1 9 240 Buffer: 6 Bytes System Exclusive SYSX: 240 126 0 6 1 247
The downside is that the sysex messages reside in the python script - only the instruction to fire the message comes from Max.
2. Send the sysex via a Max for Live function call directly to the script. This only seems to work partially - perhaps because of my limited Max skills. For some reason, I don't seem to be able to call a controller script function which takes more than 3 parameters. I can set up call a
send_midi(self, status_byts, data_byte1, data_byte2): function in the script and pass it, say, "240 126 0" from Max, and a very short sysex message will come through(!), but if I add any more argumnents to the function, it gives me an error. So: does anyone know how to define a python
tuple in Max, to be used as an argument for a script function?
Hanz
Chris aka. Pym
Dave Smith Instruments