How to implement Launchpad double-buffering with M4L API

    Aug 31 2010 | 11:00 pm
    Can anyone point me to any documentation of how to use the M4L API to implement double-buffering on the Launchpad?
    I've followed Michael Chenetz's tutorials and been able to implement bi-directional control/updating of my sequencer/Launchpad. That works pretty well.
    But I'm stumped for how to use the M4L.api route to trigger double-buffering and switch between buffers.
    Can anyone help me?

    • Aug 31 2010 | 11:10 pm
      Doesn't work that way, as far as I know (and I know pretty far). The best you could do working through the api would be to use the sysex solution that we came up with months back to get MIDI directly to the Launchpad.
      But, keep in mind that accessing the Launchpad through the API means you are working in the low-priority thread...which is kind of defeating the purpose of using the double-buffering, I think.
      If you want to use double-buffering, I'm pretty sure that you will have to connect the input and output port of the MIDI track that you have your plugin on.
      Someone please correct me if I'm wrong, I'd love to get this working in an intelligent manner as well.
    • Sep 01 2010 | 7:35 am
      Thanks Amounra.
      I'm not very familiar with the threading issues in Max. Is there a good overview of the architecture from this perspective?
      In principle I don't think it should matter that the Live API works via a lower priority thread. It's not that the updates happen any faster with double-buffering but that, from the users perspective, they all happen instantly because all they see is the flip from one buffer to the other.
      I'm kind of perplexed if the API doesn't give you a way to access this functionality. I might have to take Novations sequencer apart a little more carefully to be sure they're not doing it. I guess I can also drop them a line.
      Also I will cross my fingers that my 3rd device mode doesn't actually need it...
    • Sep 01 2010 | 7:55 am
      Although I can't find any evidence of double-buffering in Novation StepSeq I have, anyway, sent a message to Novation support to see if I can track down whomever built it, maybe they will be able to figure it out.
      I also posted to the Ableton M4L forum last night but no replies there.
    • Sep 01 2010 | 9:07 am
      In fact I don't think double-buffering is going to help me.
      My first two device modes aren't linked to the transport they just respond to button matrix pushes or changes to an individual control. Updating the entire button matrix works fine for this although I did observe that "stroking" a row or column of buttons (rather than deliberately pushing each button in turn) could cause issues with the updates interlacing.
      However taking this approach to the "live" view of the device (updating at 1/16th note intervals) seems to vastly overwhelm the Launchpad with data which the M4L API dutifully buffers up. It took about 6 minutes, from the point where I stopped the sequencer, for the Launchpad to stop updating itself. For a while I thought I'd broken it's little brain.
      I guess I'm going to have to start managing the state of the Launchpad and only sending changes rather than updating the full matrix. That'll make my patch considerably more complex but, I guess, will push my Max skills along a little.
    • Sep 01 2010 | 9:31 am
      I feel your pain. Try doing stuff like that on an iPad, where instead of a serial usb connection, you are left to the infinitely slower Wifi connection.
      I filter out sending unnecessary changes to the API in a bunch of different places...I don't have too much trouble with lag anymore, its even managable on the iPad. Here is some code that, if you put on the other side of a matrixctl, will prevent sending messages to the launchpad that don't need to be sent (e.g., a cell is already turned off, you don't need to tell it to turn off again).
      I've been coding all night and its bed-time, take a look and if you need more explanation of how it works, I'll try to explain more then when I have a clear head.
      Basically, I use the patch as an abstract: save it in your search path and then you can just type in mc_change, it will automagically come up just like any other max object. Use it as a filter in between whatever your sending to your API objects. If you bang it, it will send everything (its set up for a 256, but you can easily change it).
      You might want to check out my patches for the launchpad, I've already worked a lot of this stuff out, all you have to do is send them grid coordinates and key's from the mode buttons.
    • Sep 01 2010 | 12:40 pm
      Re-reading the Launchpad programmers reference over lunch I took more note of the USB1 imposed limit of 400 messages per second. A quick napkin calculation shows that, at a tempo of 136bpm, I was attempting update the entire Launch 9.06 times per second for a total of 580 messages per second, leaving the Launchpad falling further and further behind.
      I could make an argument that the Launchpad driver (or M4L API, wherever the buffering is occurring) would be better discarding messages if they are accruing too fast, rather than cheerfully buffering and sending them along for minutes at a time.
      But this absolutely means I need to follow your lead and adopt a strategy of keeping the current matrix state in the patch and only updating changed buttons, rather than sending the entire button matrix on each update.
      I don't have Max handy so I can't check out your patch yet. I wonder what the best approach to storing the state is? My first though is coll except that it's not 2D so I'd have to do some massaging of indexes. Maybe something in Jitter? I've never used it but I am aware it deals with matrices. Or would it be overkill?
      Kind regards,
      p.s. There's no link in your profile, where can I find your Launchpad patches?
    • Sep 01 2010 | 7:08 pm
      Hi guys,
      In the standard Launchpad control interface I didn't find a way to switch between the two states either. Sometimes the Launchpad seems to show the not-controlled state for a short period of time, less then a second. This low speed of the MIDI connection should definately be forbidden in 2010. Novation does not give a reason and makes no excuse for it.
      They only mention a way to update at double speed, which is still quite slow. Blinking/flashing of leds seems to be possible which these 'advanced' MIDI commands. But the use these power options doesn't seem to be possible in he standard control surface mode.
      It has crossed my mind that a native MIDI connection could open possibilities for blinking and better responsiveness. Perhaps I will write an interface to make use of the advanced MIDI commands.
      I think the buttons react quite sluggish. The Launchpad is not suited for frantic control action. It's no Trigger Finger. I'm not impressed by the software that comes with the Launchpad. Novation missed a chance.
      I wrote a drum sequencer for the Launchpad. Sluggish action and slow responce does not hinder that to much, so I still like my Launchpad.
    • Sep 01 2010 | 7:36 pm
      I'm not sure that it has to be sluggish. Have you seen the demo videos for Katapult?
      At a guess they are doing direct MIDI and either double-buffering or using the fast-update method described in the Launchpad programmers reference. That method reduces the amount of data required to be sent by something in the order of 60%.
      If the control surface API isn't cutting it then maybe we need a new, Launchpad specific, API. However the MIDI routing issues with Max for Live devices suggests to me that this might be tricky to pull.
    • Sep 01 2010 | 8:37 pm
      Just for the record, it is possible to send sysex via Live, which would allow you to do the double buffering thing. Its not "easy", but its not that hard either. I used it when we first came up with it to send LCD data to my Remote25 script.
      I don't know about franticness....trying to use the launchpad as a drum trigger seems silly to me, since there is no velocity sensitivity (I think if anything, this is where Novation went wrong, but I know why: pricepoint). It was built as a clip controller, and a cheap alternative to a monome, which space it fills nicely. I have my own issues with it, but I will say this:
      It is still the closest thing to an RGB grid controller that has been released into the wild, and that's a shame.
      I think its also important to be aware of what other processes are running within m4l. I made a lot of effort in the Monomod patches to prevent repeating uneccessary data to eliminate lagging feedback, then found out a lot of the lag was due to other things going on in m4l's lo-priority thread.
      There will be a new revision out in the next several days with unified support for all control surfaces in a single patch, a lot of new features, more stability etc etc. Also some new monome patches that I've ported, and a couple of my own.
      Cheers :)
    • Sep 01 2010 | 9:56 pm
      I don't really know much about the underpinnings of the Live API upon which, I assume, the M4L API is built. I also don't know anything about SysEx messages. Is the B0 message a Sysex message?
      I actually think the Rapid LED update method is probably more use than the double-buffering. But this requires sending MIDI on channel 3 which, again, I understand to be a problem. But I never tried it, maybe it works.
      Are we shooting in the dark here? I kind of feel like there is a missing manual from either Live or Cycling'74.
      p.s. Thanks for the link, I'll check monomod out.
    • Sep 01 2010 | 10:57 pm
      No, its there....or, anyway, its out there. You just have to know how to read Python. The LiveAPI access to the "control_surfaces" scripts is doing nothing more than providing a way in Max to access the already available Python scripts. Yes, it should be documented better (or at all), but honestly, they hadn't planned on releasing this portion of the software with m4l v1 anyway, from my understanding; I still feel very lucky to have it, even though it is incomplete.
      In essense, the documentation is the Python scripts themselves. My only wish is that the current scripts' source was available to us from Ableton. Then it would be less like shooting in the dark.
      On the other hand, the info is out there, you just have to search for it a bit. The LiveAPI community was doing the same thing for a couple of years before m4l actually hit.
      Not sure about B0. Every message, in essence, is a sysex message. Normally a standard MIDI note message is three bytes long: status, note, duration. "Sysex" in this context just means that the data is longer than three bytes, and the status byte is different. Live filters out these types of messages, but they can be sent through a modified Python control_surface script via the API (in fact, you can send any kind of MIDI message that way, and theoretically, receive it: I never got that far, simply because I didn't need the capability of receiving from anything, but I think its possible).
      I should mention that there is another way of doing this sort of thing without the API: broc @ Ableton forums came up with a way of sending MIDI directly from a m4l instrument using a ~vst embedded in the plugin. It works extremely well. You can access external ports or use a virtual port. There are several free plugs out there that support this sort of thing. Check the forums @Ableton for those posts, it was recent.
      I will agree with everyone in as much that the LPD isn't the best thing for rapid feedback: e.g. I wouldn't use it for a meter bridge. On the other hand, it will work fine if only 4 led's are changing at a time, which seems like is what is going on in the Katapult video, but I just glanced at it. But its more than adequate for controlling every monome patch I've ever used, @ up to 32n intervals @250bpm I don't get any lag. I think the trick is filtering out unnecessary data: buffer before sending.
    • Sep 02 2010 | 11:07 pm
      Okay I have addressed the problem with fast updates using the same approach as you. I'm using two 8x8 Jitter matrices.
      On each update I generate matrix A with the desired state of the button matrix. I then compare it with matrix B and send an output to the Launchpad for every cell that is different. Finally I copy matrix A into matrix B ready for the next update.
      It seems to be working well so far although some of the "movements" are not smooth from one button to the next. This might be a factor of updates running at 16th note rate @ 136bpm. Not sure.
    • Sep 02 2010 | 11:20 pm
      I used that approach with my first implementation of the engine for my plugin worked well enough, but caused a bunch of (I think buffer overrun) related crashes, I never did get to the bottom of it.
      It may have been due to accessing the jit.objects through js, or it may have been been something else entirely. Either way, it works till it doesn't work.
      You should be fine with two 8x8 matrixes...that's not asking a lot. I generally don't have any problems using the mc_change object with a lot of changes happening @ up to 300bpm 32nt. When I was using jitter objects, I ended up with a lot of lag when I asked it to do anything over 160bpm @ 16n. There was a lot more calculations going on in my situatin though.
      Glad you got it figured out :)
    • Sep 03 2010 | 8:06 am
      What's 'mc_change' ?
      I couldn't find anything in the help & when I googled it I ended up with this thread as the only relevant hit :)
      In terms of what I am doing I don't think there's anything challenging. Calculate 64 colours based on some simple comparisons, Iterate 64 button values making comparisons, output a few messages.
      My current machine is a 2007 MacBookPro 2.4GHz so not entirely useless, I'd hope that, unless Max is very inefficient, it should cope with that at the tempo/division I am working with.
      But that brings up an interesting issue. Are there any profiling tools in Max? How can I calculate how long it takes a patch to run?
    • Sep 03 2010 | 8:23 am
      mc_change is the patch I posted above...I guess you wouldn't know what it was called since I sent as compressed. Did you try it out?
      I'm running a macbook 2.2...I doubt there is much difference as far as performance. What I was doing was a lot more cpu intensive...basically recalculating the matrix 8 times per beat for two different jitter matrixes, and copying the results for each calculation. Plus my grid was 256, not 64. You will probably be fine for what you are doing.
      I am as I write looking up info to find out how to convert js stuff easily (or not...that's what I'm trying to find out) over to Java, so I might have some speadier solutions for this kind of stuff in the future.
      Another problem I find with the iPad is the Wifi bottleneck (as I've mentioned, I think)...I have another js that works as a buffer/speedlim, i.e. it buffers any data over a certain threshhold per timer interval and then doles it out in a delayed manner. I'm going to try to port it over to Java, and if I don't have too much trouble with it, I'll do the same for mc_change. It seems like two useful patches the community could use (and I could definitely use) for grid interaction, and I think that timing wise it might benefit from being in a compiled language.
      Don't know about profiling tools, myself. I usually just isolate certain processes in patchers by themselves and keep an eye on OSX's activity monitor. I'm sure there are more efficient and accurate ways, though...I'd be interested to know what you find out in that regard.