Sending Sysex messages to a midi controller


#1

Hi,
I have a Novation Launch Control who’s LED’s I am trying to control. Based on the documentation for the controller, I should be able to turn my first button red with the following sysex messages:

240, 0, 32, 41, 2, 10, 120, 8, 0, 15, 247

When I first start my SC server, I do a:

MIDIClient.init

… Which gives me this:

MIDI Sources:

MIDIEndPoint("System", "Timer")

MIDIEndPoint("System", "Announce")

MIDIEndPoint("Midi Through", "Midi Through Port-0")

MIDIEndPoint("Launch Control", "Launch Control MIDI 1")

MIDIEndPoint("io|2", "io|2 MIDI 1")

MIDIEndPoint("SuperCollider", "out0")

MIDIEndPoint("SuperCollider", "out1")

MIDIEndPoint("SuperCollider", "out2")

MIDI Destinations:

MIDIEndPoint("Midi Through", "Midi Through Port-0")

MIDIEndPoint("Launch Control", "Launch Control MIDI 1")

MIDIEndPoint("io|2", "io|2 MIDI 1")

MIDIEndPoint("SuperCollider", "in0")

MIDIEndPoint("SuperCollider", "in1")

MIDIEndPoint("SuperCollider", "in2")

MIDIEndPoint("SuperCollider", "in3")

MIDIEndPoint("SuperCollider", "in4")

So my novation is listed in the destinations, I then try the following code to turn on the red LED based on the documentation:

var lc; lc = MIDIOut.newByName("Launch Control","Launch Control MIDI 1"); lc.sysex(Int8Array[ 0xF0, 0, 32, 41, 2, 10, 120, 8, 0, 15, 0xF7 ]);

I’ve also tried the following, based on the documentation saying the latency being set above zero creates problems in linux:
var lc; lc = MIDIOut.newByName("Launch Control","Launch Control MIDI 1"); lc.latency = 0; lc.sysex(Int8Array[ 0xF0, 0, 32, 41, 2, 10, 120, 8, 0, 15, 0xF7 ]);

And finally I’ve tried removing the beginning and end sysex flags like so:
var lc; lc = MIDIOut.newByName("Launch Control","Launch Control MIDI 1"); lc.sysex(Int8Array[ 0, 32, 41, 2, 10, 120, 8, 0, 15 ]);

I recieve no errors, and the device does nothing. I don’t think it’s my device, can anyone see something wrong with my code? I am new to supercollider


#2

Most likely there’s a problem with the contents of the sysex.
You definitely need to keep the 0xf0 and 0xf7.

In one document I found online (but maybe it’s not the same controller you have), I saw a difference in one of the bytes in the sysex (where you use 10, the document uses 0x11=17).


#3

Ok,
Thanks for letting me know that I need those sysex headers and enders.
First off, I have a launchcontrol (not XL). I’ve posted the MIDI reference which refers to my actual device:

I tried your above code anyway (since mine did not work) to no avail. I’ve also cycled through the factory template button over 7 times, running the command each time (to make sure that the device is on the template being defined by the sysex message)

Am I suppose to be doing any aconnect stuff after launching SuperCollider? The fact that SuperCollider is reporting the device on the MIDIOut.init command, I assumed that SuperCollider is automatically interacting with the midi device. But I have to use aconnect on other programs, so let me know if I need to do any of that action.


#4

Ok, so in the attempt to debug, I tried to see if SuperCollider would read any input. I’ve tried the following line of code:
var lc; lc = MIDIIn.connectAll(true); lc.noteOn({ arg uid, midich, keynum, velocity; "some midi messages came in".postln; });

After waiting a second, the console prints this (consistent with the “verbose mode” thing described in the documentation):

MIDI Sources:
MIDIEndPoint("System", "Timer")
MIDIEndPoint("System", "Announce")
MIDIEndPoint("Midi Through", "Midi Through Port-0")
MIDIEndPoint("Launch Control", "Launch Control MIDI 1")
MIDIEndPoint("io|2", "io|2 MIDI 1")
MIDIEndPoint("2PedalPiano1.0", "2PedalPiano1.0 MIDI 1")
MIDIEndPoint("SuperCollider", "out0")
MIDIEndPoint("SuperCollider", "out1")
MIDIEndPoint("SuperCollider", "out2")
MIDIEndPoint("SuperCollider", "out3")
MIDI Destinations:
MIDIEndPoint("Midi Through", "Midi Through Port-0")
MIDIEndPoint("Launch Control", "Launch Control MIDI 1")
MIDIEndPoint("io|2", "io|2 MIDI 1")
MIDIEndPoint("2PedalPiano1.0", "2PedalPiano1.0 MIDI 1")
MIDIEndPoint("SuperCollider", "in0")
MIDIEndPoint("SuperCollider", "in1")
MIDIEndPoint("SuperCollider", "in2")
MIDIEndPoint("SuperCollider", "in3")
MIDIEndPoint("SuperCollider", "in4")
MIDIEndPoint("SuperCollider", "in5")
-> nil

If I press any of the pad buttons on the Launch Control I get nothing. Furthermore, I also tried hitting notes on my “2PedalPiano1.0”, and got nothing (I have used that piano many times on other software on the same system). Assuming that I typed the code correctly, it seems to me that SuperCollider is not communicating at all with any of my midi devices, despite being able to list the names correctly of my device. Do I need to do some aconnect stuff?


#5

OK,
Update: I got the standard midi input to work from both my midi keyboard and the Novation launch control. I was using the command line sclang, and didn’t have the proper server boot and midiclient initialization in the code block.
Here is my current code:

s.waitForBoot{ 
    var lc, on;
    MIDIClient.init;
    lc = MIDIOut.newByName("Launch Control","Launch Control MIDI 1");
    lc.connect;
    lc.sysex(Int8Array[ 240, 0, 32, 41, 2, 10, 120, 8, 0, 15, 247 ]);
    MIDIIn.connectAll;
    on = MIDIFunc.noteOn({ |veloc, num, chan, src|
	    "Some midi note was pressed".postln;
    });	
}

So, upon running this, the midi input stuff sends the messages it’s suppose to on my keyboard and launch control. However, the systemex message is still not lighting up the button as it is suppose to. You can see that I’ve added lc.connect, I am not sure that is necessary, but I am trying everything I can. Anyone see anything wrong with this code, or anything missing? I will keep posting updates until I find a resolution, in the event that more people on the internet can’t find a solution and can use google to find my (hopefully) eventual resolution.


#6

Unfortunately, newByName does not work as documented on Linux , see:

https://www.listarc.bham.ac.uk/lists/sc-users/msg61046.html

So use MIDIOut(0) (for example) to open up the port that ALSA calls “SuperCollider:out0”. Then you can either use the connect method as shown in the above link or use aconnect (or a GUI like Catia) to link this port to your hardware in ALSA. I don’t know for sure that this is your problem, but give it a try.


#7

John,
Very useful information! I will try these methods when I get home tonight and post the results. Is there any way to petition to have the help docs changed? I am willing to fork the repo, change the relevant help files, and make a push request if I have to, because this had me trapped with no way out for at least a week.


#8

There is an open issue with discussion at https://github.com/supercollider/supercollider/issues/3805 - if you want to dive in there, I’m sure it would be useful.

Might want to look at https://github.com/supercollider/supercollider/blob/develop/CONTRIBUTING.md if you haven’t already.


#9

Ok, I think I am getting closer. I am somewhat confused between the consistency of what your saying and the link posted above. You mention this:

So use MIDIOut(0) (for example) to open up the port that ALSA calls “SuperCollider:out0”

In my situation, SuperCollider:out0 is not what I am trying to get at, and it sounds like the link is saying for all n in MIDIOut(n), none will reach endpoint “Launch Control”, “Launch Control MIDI 1”. I see how I could just connect to SuperCollider:out0 and then use aconnect outside of supercollider to route that to my launch control. But, I’d like to know what you mean by this other “connect method as shown in the above link” that you mention, and I will resort to aconnect if all else fails. The link says this:

…there must be a connection to a destination. You can do it one
of two ways: m = MIDIOut(0, MIDIClient.destinations[2].uid);

I interpreted that to mean that somehow I could get the uid for my destination named “Launch Control”, and pass that as a second parameter. I tried this like so, (sucessfully getting the uid), but the sysex message doesn’t appear to be doing anything:

    var lc, on, lc_uid;
    MIDIClient.init;
    MIDIClient.destinations.do({ arg destination, index;
            destination.name.postln;
            if(destination.name == "Launch Control MIDI 1", { lc_uid = destination.uid;  ("LC uid is "+lc_uid).postln; }, {  });
    });

    lc = MIDIOut(0, lc_uid);
    lc.latency = 0;
    lc.sysex(Int8Array[ 240, 0, 32, 41, 2, 10, 120, 8, 0, 15, 247 ]);

I also tried replacing MIDIClient.destinations with MIDIClient.sources, because of this statement in your provided link: “MIDIClient.destinations has nothing to do with it.”

Is there anyway at all to try and access these named devices inside SuperCollider itself? Or am I going to have to conjure up some bash scripting judo to have aconnect do the work after supercollider launches? (I will if I have to, but seems to be the least elegant solution if there is another way)


#10

I got it to work!!! See the following code:

    MIDIClient.init;
    MIDIClient.destinations.do({ arg destination, index;
            if(destination.name == "Launch Control MIDI 1", { lc_pi = index; ("LC index is "+lc_pi).postln; }, {  });
    });
    lc = MIDIOut(0);
    lc.connect( lc_pi );
    lc.latency = 0;
    lc.sysex(Int8Array[ 240, 0, 32, 41, 2, 10, 120, 8, 0, 15, 247 ]);

Sure enough, I run this and my little pad button turns red. Note that this code is alot like .newByName(), but working on linux. I don’t want to specify an index number, because I have 4 usb ports, and I don’t know if SC is going to register the device in the slot the same everytime. Instead, I search through destinations for the name, and pull the index number. What I didn’t understand is that the first paramater of MIDIOut just needs to be 0 every time, then specify the index in connect.
Hooray!


#11

Congratulations! Glad things got resolved :slight_smile: