I just finished a new system for midi routing this week. It works surprisingly well, and allowed me to greatly simplify my code (and may be useful to people writing large applications with midi-learn functions). So I thought I would sing the praises of the Value class here, an ask a few questions:
OLD SYSTEM (centralized):
Previously I had midi routing via a centralized midiCallback which checked the midi against a list of known matches, and then either acted immediately (for model level, high priority stuff - changes to volumes, states, start/stop recording, etc.), or added the message to a list of recent incoming commands that were regularly polled by the UI elements (since some midi messages were mapped just to alter UI elements in one way or another … and of course, you can’t do that on the high priority midiCallback).
NEW SYSTEM (decentralized, and using Value objects):
I got thinking last week that if the overhead for a midiCallback wasn’t high, perhaps it would be appropriate to make every object which responds to midi have it’s own midiCallback. I started by writing an abstract MidiLearner class that kept a list of the midiMessage it would respond to … along with a virtual function to define what the object should do when midi was matched.
I implemented this class for the sliders / buttons and separately for the more complicated custom objects and voila!
Now I have individual sliders and buttons running midiCallbacks and checking the incoming stream against their own list of commands, and then responding by setValue (in the case of sliders), and triggerClick (for buttons). Since TriggerClick is asyncronous, and setValue is fast enough for the midi thread … this is a remarkably easy way to have dynamic midi routing to a very large number of objects with no appreciable delay (I’ve got a couple hundred sliders / knobs / buttons and other objects all responding to incoming midi).
The icing on the cake here is that since button states and slider values are both represented as Value objects (which are reference counted, and so several can safely reference the same underlying value), you can use the referTo() method to set the slider value to something like an audio volume, pan or some other custom Value object.
This means that incoming midi can alter a Value object - and since that object has the same underlying reference as several other Value objects, a ValueChanged() message is released and several changes may actually occur (including the UI slider actually moving). This is a thread safe and easy way to control you’re UI and underlying data structures without a single callback being written (woohoo … Jules, you make this too easy).
Anyway, I hav no specific questions - since it seems to have worked fine. I was expecting more gotcha’s to come up … and am still holding my breath to see if something comes up in the next few days that is too slow for executing on the midi thread … but really, this seems to have solved a bunch of problems and allowed me to remove nearly every slider callback and changeMessage in my system.
I’m a little curious how the ValueChanged() callback is so fast and thread safe (unlike, say, the message thread); but will leave that for now, and look deeper later.