Proposition: solution for sysex...SOLVED!!!

Learn about building and using Max for Live devices.
hoffman2k
Posts: 14718
Joined: Tue Jun 15, 2004 6:40 pm
Location: Belgium
Contact:

Re: Proposition: solution for sysex...SOLVED!!!

Post by hoffman2k » Mon Mar 29, 2010 10:35 am

3dot... wrote:
ST8 wrote:send /ableton/selection int xoffset int yoffset int width int height
now.. how do we get inside racks/rack mixer params?...
That one requires help from Ableton. Currently we're piggy-backing on what already was there.
The speed at which it operates and the features available was all designed for controller scripts.
They opened a can of worms and we're those worms I suppose. Now we need deeper access, faster access and documentation to boot..
I personally can't wait to access racks with my Clip Mapper. But I'll have to..

hoffman2k
Posts: 14718
Joined: Tue Jun 15, 2004 6:40 pm
Location: Belgium
Contact:

Re: Proposition: solution for sysex...SOLVED!!!

Post by hoffman2k » Mon Mar 29, 2010 10:39 am

@ ST8, Hanz and Amounra,

You guys do realize Ableton is hiring, do you? :wink:

As far as I am aware, not even a handful of people at Ableton actually work on these scripts.
You hacked your way in, you know how the scripts work.
I realize you guys may already have jobs and do this in spare time. But maybe its time for a Berlin "vacation". :D

Pym
Posts: 3
Joined: Sun Mar 28, 2010 11:48 pm
Location: San Francisco
Contact:

Re: Proposition: solution for sysex...SOLVED!!!

Post by Pym » Mon Mar 29, 2010 7:35 pm

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

Hanz_Petrov
Posts: 119
Joined: Sat Feb 06, 2010 2:39 pm
Contact:

Re: Proposition: solution for sysex...SOLVED!!!

Post by Hanz_Petrov » Tue Mar 30, 2010 2:29 am

Hey guys, I think I've got it working now (well, the sysex out part at least).

Here's the python code:

Code: Select all

def max_to_midi(self, message): #takes a 'tosymbol' list from Max, such as "240 126 0 6 1 247"
    msg_str = str(message) #gets rid of the quotation marks which 'tosymbol' has added
    midi_msg = tuple(int(s) for s in msg_str.split()) #converts to a tuple  
    self._send_midi(midi_msg) #sends to controller
And my max patch looks like this:

Image

When I "uzi" it, the messages fire off at about 10ms each. A longer sysex string might slow it down a tad, but I haven't checked.

@amounra93: The [tosymbol] object was the missing link - thanks for that.

@chris/pym: Thanks again for sharing - I'd be happy to leave the rest to you (the hard part, that is ;)

@hoffman2k: I definitely fall into the "don't give up your day job" category. :)

Hanz
http://remotescripts.blogspot.com/ - an introduction to the Framework classes

amounra93
Posts: 432
Joined: Sat Jan 24, 2009 8:16 pm
Location: Arcata, CA
Contact:

Re: Proposition: solution for sysex...SOLVED!!!

Post by amounra93 » Tue Mar 30, 2010 3:58 am

@amounra93: The [tosymbol] object was the missing link - thanks for that.
I was hoping that would work. And, on the contrary, thank YOU. That should allow me to collapse all my Control_Surface needs into one very manageable script, with much lower latencies than I'm seeing right now. I might be bugging you a bit to figure out how to code the python portion later. Awesome work :) This thread just keeps getting better.


@hoffman thanks for the kind words, Berlin is pretty far away for me....I'll keep pushing forward and see what happens.

EDIT:: installed code, works great :) Now just have to figure out how to get channelized midi and sysex input from the script.
http://www.aumhaa.com for Monomod and other m4l goodies.

Hanz_Petrov
Posts: 119
Joined: Sat Feb 06, 2010 2:39 pm
Contact:

Re: Proposition: solution for sysex...SOLVED!!!

Post by Hanz_Petrov » Tue Mar 30, 2010 5:32 pm

amounra93 wrote:
installed code, works great :) Now just have to figure out how to get channelized midi and sysex input from the script.
For input, handle_sysex(self, midi_bytes) is probably a good place to start - I believe that this method should work in realtime. Seems to get called by receive_midi(self, midi_bytes) when receive_midi sees a sysex status byte (240). Do you absolutely need to get the sysex message into Max for Live, or can you handle it from within a script?

Hanz

p.s. Some of these MIDI handling methods seem to come from the MidiRemoteScript module, which is imported together with the Live module, in the ControlSurface script. Might be worth investigating the MidiRemoteScript module in more detail, to see what other funtions it contains...
http://remotescripts.blogspot.com/ - an introduction to the Framework classes

amounra93
Posts: 432
Joined: Sat Jan 24, 2009 8:16 pm
Location: Arcata, CA
Contact:

Re: Proposition: solution for sysex...SOLVED!!!

Post by amounra93 » Tue Mar 30, 2010 10:24 pm

I actually don't need to receive sysex at all. CC's and Notes will work, and I'm sure that won't be too difficult (the Launchpad script might also be a key, it has one control layer that handles everything coming and going to the 8x8_grid). But I'm going to investigate it anyway, since receiving raw data might be useful for others, and would basically replace the [midiin] and [midiout] functionality missing from M4L.

Currently I'm trying to finish a patch (new Max patch to replace the Remote25SL functionality, but really just a framework for the iPad, which I'm expecting Saturday), so I won't have time to play with the Python stuff till this weekend. Thanks for the hints, everything you mentioned makes sense and will give me a place to start when I get to it later this week. I'm sure I'll be in touch, but let me know if you come across anything else interesting.

Next project: an external to communicate directly with Automap. I looked over the SDK the other day, and it doesn't seem that terribly ambitious. I'm surprised nobody has done it yet. Maybe because there are no Automap users?
http://www.aumhaa.com for Monomod and other m4l goodies.

Post Reply