send /receive interference in M4L

Samuel Bowen's icon

I am trying to send multiple set of midi data to and from a M4L patch in Live. I want to be able to send midi data from two channels (currently), process that data and then send it on to multiple others.

I have tested this using Live's midi send but it mixes all the midi together into a single input. I tested this and the patch does work and I can split up the information using different octaves and velocities, however if i want to expand the number of channels going into the patch I would fast run out of space to do so.

So I wanted to use Max's s/r objects for a bit more precision. I switched my first channel over from Live's midi send to Max's and it worked no problem, but when I switched over the next channel there was some strange interference. I've named the sends and receives differently so they shouldn't be sending to each other and I've saved the "notein => pack -> s (name)" patches on the input channels separately so its not like I'm loading up two of the same by mistake.

Honestly, it sounds like lag and that the notes being sent are causing a stutter effect on each other as the system struggles to process it simultaneously, but the CPU usage is negligible. In fact i don't even have to connect the receive to the patch. As soon as the send patch is activated the everything gets desynced and lags. And then if i turn it off again the midi signals continue to lag and stutter and i have to restart max and live to get it work again.

Also sometimes if i play midi files on one channel, notes come through on the other's recieve. I don't think they are the other channel's notes, it seems almost like the notes from one channel are being delayed to match the rhythm of the other. Which is very strange.

I'm sorry i can't provide a clipboard patch but it really is just sending a receiving midi data between patches in Live. And the stuttering happens even if i disconnect but a couple of message boxes.

Andy Maskell's icon

Without seeing the patch it's a bit difficult to understand where this might be going wrong but it sounds as though you have a hidden loop somewhere that is recycling the same midi data back through the system. Have you been able to analyse the flow of midi data, either by "printing" incoming and outgoing data to the console or by using an external midi analyser, like Protocol, to monitor the flow of midi data between the connections? I also put plenty of bang and message objects in my code when I'm trying to analyse complex data and process flows.

Samuel Bowen's icon

Hi. Sorry for the delay. Thanks for your response. I've been trying to do just that.

So the patch is intended to function much like those kids keyboard that let you play any key and it just plays the next note in a melody. Melody information will be stored in lists read by zl.lookup and then midi notes will call the elements of the list. A midi file will be notes descending in order from 126 down to 0. (127 holds other information and is siphoned off in the patch) These values will then call up values from the list and be recombined with the velocity information before being output to midi channels in live. In short a live channel will play midi into this patch through send and recieve, this patch will modify the pitch data and then i will output to another live channel where it is played through an instrument. I know that live's midi sends are an easier way of doing this but i want to be able to have multiple inputs and outputs on the patches channel and Live's midi sends neither support sending to multiple different channels nor do they support using midi channels to differentiate the data.

There are a few oddities i've found. First of all the lag and rhythm issues generally start after I enable another track. e.g If I have two of these running in the same patch from different channels they seem to interfere with each other. I've even renamed my sends and receives apples and oranges to ensure this isn't human error. However, if i then turn one of these off again (stopping the midi input from one of the channels) the issue continues. I have put prints before and after the send object and it seems like the issue is between Live and M4L itself as there is no appreciable difference between the prints pre and post the S/R. It also starts sending the wrong notes. I can change the midi file playing and it will continue to play notes from the previous file with the new files rhythm. The rhythm is very inconsistent though with some notes landing on the note on, others on the note off and some in between.

The playhead in live is not stuttering but i can see the notes are being printed in time with the sound (out of time with what they should be) and not in time with the notes being played in M4Live.

Max Patch
Copy patch and select New From Clipboard in Max.

Andy Maskell's icon

There is an immediate thought that comes to mind. I'm assuming that you only want to manage the note messages in the MIDI stream. In your midi interface at the bottom, you are copying the midiin directly to the midiout. I don't know how Ableton handles this but as you are then feeding additional note messages back out to Ableton this could potentially form a loop where the notes keep endlessly repeating on themselves. I suggest you try using midiselect @notes all instead of midiparse as this only passes the unfiltered messages out of the right hand outlet and could prevent endless loop-back:

Samuel Bowen's icon

Thanks. Sorry for not explaining properly what this was for. I'm using midiparse to get the notes in a more usable format, though i suppose i could just as easily use notein. The midiout to the channel was purely to monitor the midi data in live for comparison against the midi data being spit out of M4L. The midi channel that this clump of code would be on has no outputs in Live, on the send in the patch. I will give it a go though.

Andy Maskell's icon

I'm still struggling to understand the routing here.

I take it that your keyboard is linked to one track in Ableton and that is the one one that is feeding this patch. Are you certain that you are handling both note on and note off messages properly? If you only want the key presses to trigger the next step in the tune and ignore the key releases then you could use stripnote to remove the unnecessary note off messages.

How are you getting the processed notes back into a different track in Ableton to play the instrument(s)?

And I'm not sure what the chunk of code on the left hand side of your patch is doing.

Unfortunately, I don't have a copy of Ableton on the computer I'm using at the moment so I'm a bit in the dark there.

Andy Maskell's icon

Ok, I've done a bit of meddling and I can understand what the left-hand chunk of code is doing (I think?) as I have created a clock of sorts to replace what I assume plugsync~ would be doing. I've had to bypass the zl.lookup objects as I don't have any data to link to the coll objects.

Now, the questions in my mind are:
1) As the coll objects are linked to disk files, is there anything going on in terms of disk activity that could be causing a delay there? I've only had reason to use coll objects with data embedded in the patch (@embed 1 option) rather than on disk so I'm not sure if your patch is causing a lot of disk overheads despite the apparent low CPU activity. For example, what's happening when the random intervention switches from 1 to 2 and back - does the coll get reloaded from disk every time or is the coll only loaded once when the patch loads?
2) Why are you processing note on and note off signals down two separate paths that appear to me to be doing exactly the same thing?
3) If your random function switches the gated output between a note on and note off it could potentially lead to "hung notes" in the deactivated stream.
4) Although you are sending the 4 melodychannel outputs separately, they all effectively end up going back to Live through an identical noteout - am I missing something there?
5) Is the output of plugsync~ triggered by beats or ticks (i.e. fractions of beats)?

Samuel Bowen's icon

1) Coll is storing the lists that are to be read by zl.lookup. My hope is that in the future coll will be able to change the file its reading to load new sets of lists, however right now its just static.
2) This is in response to the errors I've been having. I thought at one point that the delay after triggering a new midi file in Live was causing notes to be triggered on the note off rather than the noteon.
3) Hung notes could certainly be a problem and this is something i am also concerned about though it doesn't seem to be what is causing the problem as the stuttering and desync is far more widespread than i imagine this capable of causing.
4) Again my apologies for not explaining this correctly. These will need to be in seperate M4L patches on their own channels in live. This is to send the midi information from a channel with midi information (or multiple), to the channel with this main patch, and then on to a channel with an instrument (or multiple)
5) I believe plugsync uses the clock from Live and i am currently using the beats outputs from it.

Samuel Bowen's icon

I also now see what others have talked about regarding M4L not working properly while patches are open for editing.

Andy Maskell's icon

Well, I think you might have to work through things systematically in a way:

1) Copy the data loaded in your current coll into a replacement coll that is embeded in the patch (using coll <name> @embed 1) to eliminate any disk related issues.

2) Does the MIDI medley in your coll just have note numbers or is it a real MIDI track with note durations? Maybe ditch the note off pathway and use makenote to guarantee that each note on is followed by a corresponding note off, either with fixed note length or ones derived from the coll data.

3) Try putting the gate 2 at the bottom of each block near the top and have a separate pathway for each resultant MIDI stream. Although you might think that is unnecessary duplication, Max will only be processing one route at a time and it would guarantee that each route completes what it's doing irrespective of when the gate changes streams. Your code per se is absolutely not eating processor time.

4) You definitely need to eliminate notes going back into the same Live track as they came from unless you can be absolutely certain that Live treats Max patches as true "inserts", i.e. what you send back into the track will not be sent out again in an endless loop. I'd try sending each block's monitoring output to a separate track, as I think you are aiming to do.

5) I've set my clock to emulate beats in 4/4 so I think I got that right. Is there any way for you to upload one of your melody files so that I can add it into my version of your patch?

I've always wondered why M4L ended up getting "embedded" in Live. It's why I stuck with Cubase and bought the full version of Max 8 to run it - it gives almost infinite flexibility regarding connections and more control over what's flowing between the two. Cubase is definitely processor hungry but Max is incredibly efficient. My ginormous project rarely hits 0.2% of my CPU time. I also use copious virtual internal links with loopMIDI and external links with rtpMIDI to ensure that all the midi streams stay totally separated from one another but you can't really do that with M4L.