Input needed! Underlying issue with scheduler, UI & midi

davidestevens's icon

As I begin to contemplate a major rebuild of my software, with the intent of making it more robust, and efficient, there are two fundamentals and probably related issues that I would really appreciate some input on.
(Retina MacBook Pro, latest OSX, latest Max)

Here are the two issues, both of which I've only had since I moved to Max 6.

1. One of my controller input systems is 4 infrared sensors connected via an eobody box and USB, and into Max via either [midiin] or [ctrlin] (I've tried with both).
Normally I would have both Scheduler in Overdrive, and In Audio Interrupt on - that's what I always did up to and including Max 5, on the (admittedly hazy) assumption that for optimal performance of the UI, control input, and audio processing, this was the best setting (and then adjusting the vector settings to get the best performance compromise).
With the move to Max 6, I discovered that once the controller input/conditioning patcher was running in the context of the full "app", the controller input failed. (Input from the sensors was either not "getting through" or was perhaps "clogging up". Probably the latter, as turning off dsp caused a sudden flow of midi data). Asking about this on the forum, I was told that turning off Scheduler in Audio Interrupt was the thing to try, and indeed this did fix that issue (though I didn't unfortunately get an explanation as to why this would be so, and why it wasn't an issue in Max 5).
If I load _only the controller input/conditioning patcher and run it with Scheduler in Audio Interrupt ON, (and dsp on), then it works. It's only in the full app that things get literally sticky.
(Overall dsp load with the full app running is generally around 30-40% though - much better in v6.1 than it was in 6.0.)

2. Turning Audio Interrupt off seems to have the effect of making the UI much less responsive. The worst aspect of this is with [umenu].
What happens is that I click on a umenu to (eg) select a new buffer, or synth voice. The menu opens and I scroll to and click on the item it want, and then.... Nothing. Probably 6 out of 10 times the menu stays open for 15-30 seconds, and then closes without anything changing (ie I still have the previous voice/buffer selected). At first I thought this might be down to the drivers for the Wacom pad I use, but though switching to using the trackpad on my MacBook Pro changed the odds slightly in my favour, selecting a menu item is still very slow and doesn't always work (it now fails maybe 45% of the time).
Attempting to bypass this sluggishness, I created an off-screen set of MIRA umenus linked to the main onscreen ones. This led to a very interesting problem (not). With the app running, I can select a new voice on my iPad, the umenu in Max changes BUT the new voice isn't actually loaded. It's as if I'm sending a "set" message to the visible umenu (but I'm not - I just checked. I don't know if it's relevant, but the MIRA connected umenus are at the top level of the app, while the main umenus are in bpatchers).

The app isn't really that complicated - 4 bpatchers each containing a sample player, fluidsynth, and vst synth bpatcher. Plus 2 bpatchers with sample players only.
Controller ins are USB midi (direct from the eobody, and via Osculator for Bluetooth sensors) and hi (a dancemat).
Sensor response is important, so I currently have both IO and Signal Vector sizes set to 128.
I've gone through all of the subpatchers making sure that right to left ordering follows signal flow (both control and audio), and there's liberal use of [trigger]. I've even arranged all the bpatchers and subpatchers at the top level in right to left/top to bottom order in the hope that that will also make some difference.

Turning Audio Interrupt back on seems to make the UI respond properly, so it seems to me that this all boils down to...
"Why isn't midi input working properly with Audio Interrupt turned on? Why has this changed from Max 5 to Max 6? And what can be done to fix it!?"

If you've read this far, thank you for taking the time. And if you have useful input on this, you will be my hero forever (well, probably at least until Max 7) :-)

jvkr's icon

Can't really thoroughly answer your question, but I can share my solution for the midi issue. A while ago I turned a small and simple patch into a standalone that just receives incoming midi and sends it to an ip address. Which ip address, depends on the channel that the midi is received on. In this way I was able to route different controllers on the same physical device to two different local applications (max5 and max6). At the receiving end I have a udpreceive and midiparse object. Even if the main patch becomes really busy, the handling of midi never suffers, meaning no buffers that run over.

Generally speaking I have the impression that to have a single hub for midi is preferable. I could imagine that different ctlin objects for instance, deal with all midi events and filter out only those midi commands that apply according to its arguments. Although I am not quite sure about this.

Another thing, recently I ran into sluggishness trouble due to a (quite large) waveform~ object. This object will refresh every 500ms by default, also, I suppose, when there is nothing to refresh. The buftime message helped me to deal with this. You don't really mention it, but I imagine you use this object. Alternatively waveform drawing can be done with jitter.

Again, generally speaking, keeping the interface simple in terms of ui objects that need refresh or redraw helps. As an aside, I noticed that different ui objects have a different feel in such circumstances; a live.dial much better than a regular dial.

And yeah, Wacom; such a great tool with max, but sometimes so troublesome...

davidestevens's icon

@jvkr - great! thanks for the input.

udp - Interesting - I'll give it a try. Do you think it makes any difference if the midi stream is parsed in the standalone or at the receive end?
Presumably the reason you were using different IP addresses was to get the information into two separate patches. That wouldn't be necessary if all the data is going into the one Max6 patch, would it? Or would you set up several udpreceive objects with different ports, so that the midi is channelised before sending it from the standalone?

waveform~ - hmm, I actually have only 1 of those in this patch. I used to have one inside each sample player, but decided that I didn't really need them there during one major redesign/rebuild a couple of years back. So I now have just the one in the sample recorder module. But I wasn't familiar with the buftime message, so I'll check that out too.
I've been thinking about how I could simplify my UI even further, but I'm not sure how much more I could do without totally changing the character of the interface (and maybe making it difficult for me to see what's going on during a workshop). Is there information anywhere about which objects might be requiring a lot of redrawing? And is it the case that offscreen UI objects don't get redrawn/refreshed whilst they're offscreen? (Either off screen at the top level, or inside unopened patchers?)

thanks again...

jvkr's icon

Concerning parsing midi, I don't think it would make a lot of difference (multiple or one udpreceives). But then again, trying out the different schemes is probably best.

Concerning the interface, the issue you described before with the umenu object sounds familiar, and also I am using Mira to interact with them. It would be possible to think of different schemes instead of a menu, for instance a listing of options.

In order to decide which objects are cheapest, it is of course best to simply monitor differences in cpu load in Activity Monitor. The bpatcher object by default is transparent, meaning that two graphical layers are combined. It could be that turning of transparency already saves some cpu. When you use Mira, it would be possible to simply hide those objects in the patch, so that they don't have to be redrawn.

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

Your question triggered me to dive a little deeper into this issue of cpu 'wasted' on graphics, of which I had a hunch, but no concrete data. So I build a patch with a few typical UI objects that are redrawn, and an option to hide everything, in order to monitor the difference. This patch requires the shell object. The results are much more dramatic than I had expected. In max 6.1.6 hiding everything graphical, reduces the cpu load to less than a quarter. In max 5 the difference is less dramatic. It seems it is good policy to be careful with the GUI.

davidestevens's icon

Good grief! I can't pretend to know what exactly what the shell command is doing (it seems to provide very different results to the CPU meter inside the Audio Status window), but the difference from hiding just those few objects is extraordinary. Do you think C74 is aware of this?

"It seems it is good policy to be careful with the GUI." Which I find slightly ironic given that it seems that a fairly large part of what Max 6 is about is improved UI. Ok - I'll do some serious rethinking of the front facing part of my patch - maybe move more controls into off-screen subpatchers that I only open when absolutely necessary, and change the bpatchers to patcher bg colour rather than transparent.

thanks again jvkr

davidestevens's icon

@jvkr I was just trying out the effect of hiding UI objects and non-transparent bpatchers using the patch you posted above. When I close the patch, Max locks up. Presumably that's something to do with the shell command? Does it need releasing before quitting Max?

jvkr's icon

The shell top command reports total cpu load of max (audio, scheduler, jitter, graphics etc.). The Activity Monitor is sort of a nice user interface around this command, it gives the same information. You can also type top in Terminal and monitor cpu usage. I can't explain the crash, but you see there are other ways to monitor load.

The values for cpu load might need to be given context. Also my contribution to this tread maybe made it veer off from the original subject, apologies for that. Hope someone else can contribute.

Lee's icon

i think it's generally understood that the UI objects take up CPU - it's why you're always advised not to use any UI objects in a patch if you don't need them

i went through the process of making the majority of my UI stuff hideable on user request a few months ago for this very reason.

cheers

davidestevens's icon

Thanks for all of that jvkr.

And although the original questions haven't been answered yet, I now have a workaround that seems to be working well. I can't try the whole system as the sensors & interfaces are in storage till the next workshop, but I have the software running with a midi controller as input, with Scheduler in Audio Interrupt on (so the interface is much more responsive) and the controllers seem to be arriving without clogging. So while it would be nice to have everything inside on patch, I can live with the separate standalone for controller input (I just have to add the extra step to my memory banks :-) )

davidestevens's icon

@Lee. Yes, but the thing is I need a lot of that stuff immediately accessible when I'm running a workshop as I don't want to waste time opening sub patchers and looking for the UI object I need right then. I used to do that a lot more, and it could get a bit embarrassing when I decided to change something and spent several moments trying to remember where that particular thing was.(Operating the software is not my primary concern during a workshop!) That's why I brought most of the options I need to keep an eye on onto the front page again.
Having said that, I'm going to have another look at what I _really need to have on hand.
And having said _that, being able to have Schedular in Audio Interrupt back on has made things much snappier.