To start - focus on the Multiball object only. The other sliders and buttons ar ejust to make the user experience nicer. If you always wanted to send 2 octaves on MIDI channel 1 starting at C4 in legato mode, none of the other controls would be necessary.
It is good to know/understand the MIDI protocol so you have an understanding of MIDI messages in general. For example, note OFF can be sent in 2 ways - either by sending a separate Note OFF message or by sending a note ON with velocity of 0. The second way ends up being slightly faster since the receiving device is only processing a single type of MIDI message.
Next is to think about what needs to be done. Moving a Multiball generates changes in x,y, and possibly z. X and Y are coordinates and z is touched/brightness. You know that to generate a MIDI note that starts and stops requires 2 messages, so you can either try to make the x/y/z do the job or use a script since each variable (x/y/z) can only send one message. My general tendency is to use a script since I have more control over everything that happens. Sometimes for simple stuff (like using a fader to send a MIDI CC message), doing it all in the object without a script is fine. Usually though a script tends to be the better answer.
Scripts can be triggered on a change or invoked manually. Usually you want something to be done automatically every time there’s a change. Most of the scripts in the example are called on an “any” change. Basically whenever the x value changes at all. Note that if x doesn’t change, nothing happens. You can test this by dragging the multiball to the far left or right edge and then carefully moving it from top to bottom. Since x isn’t changing (only y) no new notes are generated.
Inside the multiball is where the bulk of the action occurs. Since MIDI requires a note on and off, I need to make sure I shut off the old note as well as playing the new note. Therefore I need to hold onto the old note and I use a local variable inside the object to store the last note I played. I set it to -1 to start since that is never going to be a valid note value and it’s easy to check and not send a note off if it’s -1. I also reset that lastNote variable when I change things with the sliders (not sure if I coded that into all 3 sliders or just the baseOcatve one). The theory is that when a user changes the configuration, everything should reset to a known state. This is one area that’s not fully coded here. Especially when changing MIDI channels, you don’t want to have hanging notes on the old channel, so cleanup should be done before the new channel is set.
Anyway, back to the multiball. Inside that script I check to see if the note has changed once I figure out what note is being triggered. The x and y values are very detailed and you don’t necessarily want a note (the same note) coming out for every minimal position change. The code at the top of the script scales the multiball area to fit into how many octaves you set. As you found out, the less octaves, the farther you have to move left or right to generate a new note. This would be the area of code where I’d insert more code to deal with various scales. Once you have the base note in the correct octave range at the correct offset, you could do additional work to fit it into a particular scale.
Next we determine if this note is different than the last one and if so, turn off the old and send out the new. With some minor changes, this script could be adapted to send out 1,2,3 or more notes depending on how many fingers are touching/controlling the balls.
The rest of the objects and their minor scripts basically do housekeeping and work around some Lemur eccentricities. For example, the Monitor object displays whatever you send to it (used for MIDI channel and number of octaves). However, if you send a string with quotes, you get exactly that, so if I tried to send ‘C-1’ to a monitor, it would show ‘C-1’ instead of C-1. I need to use a text object and then call setattribute() function to set the Text object content.
I use global variables for MIDI channel, base octave, etc just to keep them together and make it clear they could be used by all the objects/scripts.