Version 4, last updated by richdrich at April 17, 2008 08:19 UTC
NOTES Catching MIDI events
[ I've written this up in note form for now, partly because I needed to persist the info somewhere. The context of this is that I'm trying to build an app that will map (some) MIDI control changes into Python function calls. For instance, I'd like to have down/up buttons that move between tunes (in a DJ setup) that might have been loaded into multiple tracks and scenes. ]
Dataflow
Midi events flow as follows through Live:
The musician turns a knob or hits a key on the MIDI device. This translates into a midi message (see http://www.midi.org/about-midi/table1.shtml).
Messages mostly split into Note and Control types.
The message can then be delivered to a script to handle. This script is the one set up under "Control Surface" in the Preferences/Midi dialog, next to the "Input Device", which is the midi device being handled. [What happens in handling multiple devices with one script?]
The script *must* elect to receive messages from the particular knob/key. This is done by setting up the Midi Map in a call to the build_midi_map member function of the API handler class (this module is instantiated from the __init__.py file in each API folder) such as LiveTelnet. build_midi_map calls the following functions to request input from a control:
Live.MidiMap.forward_midi_cc(self.handle(), midi_map_handle, channel, cc)
This 'forwards" a Control Change (CC) message to the receive_midi function. Ableton uses the term "forward" to mean "pass to a Python routine. (Map, I think, means to apply directly to a parameter in the system, but I haven't investigated that yet)
Live.MidiMap.forward_midi_note(self.handle(), midi_map_handle, channel, key)
This does the same forwarding function for a key hit.
When a message has been forwarded as above, it gets sent to the receive_midi function as an array of bytes. My code to display the first two of these bytes (inside LiveTelnet) looks like:
<span style="font-family: Courier New;">def receive_midi(self, midi_bytes):<br />
if self.telnetConnection:<br />
self.telnetConnection.send("***receive_midi(" + str(midi_bytes[0]) + "," + str(midi_bytes[1]) + ")\n");</span>
Code that runs here has access to the full Live model and can do anything it wants. Which is how clever control software like Novation Automap work (I think).