The ddwMIDI Quark provides two main ways of working with MIDI information:
- Sockets and controllers
- Respond to MIDI note and controller data.
- MIDIRecBuf and MIDIBufManager
- Record, store and manipulate MIDI note data.
This document is intended to cover the main usage patterns. Implementation details may be found in the class references, linked in the text below.
Why another responder hierarchy?
The standard MIDI responders (MIDIFunc, MIDIdef) are organized around the incoming message type. The ddwMIDI responders are organized around what you want to do with the information. For example, if you want to play notes using a MIDI keyboard:
- Standard MIDI responders: Create MIDIFuncs or MIDIdefs, one for note-on messages and another for note-off, containing functions to handle the note onset and release logic.
- ddwMIDI responders: Create a Voicer to play the notes, and a VoicerMIDISocket to connect MIDI messages to the Voicer.
For another example, ddwChucklib can trigger processes using note-on messages. MTSocket makes the connection. Thus, the class of the responder explains how the incoming messages will behave (while, in the standard MIDI responders, you would have to inspect a function definition -- error prone, to say the least).
ddwMIDI responders divide into two categories:
- Sockets
- Sockets handle note-on and note-off messages. Every socket is expected to respond to both on and off messages; that is, there is no need to create separate responders for them.
- AbstractMIDISocket is the parent of all MIDI sockets. If you need a custom socket, inherit from this class.
- BasicMIDISocket installs two functions (note-on and note-off), to handle any logic you like. The functions are passed
|note, velocity|
as arguments. - VoicerMIDISocket directs note-on and note-off messages to a Voicer. The Voicer handles node allocation and voice-stealing.
- MIDIThruSocket passes note messages to another MIDI channel, with optional pre-processing. The forwarded messages are sent through MIDIIn, so they can be received by MIDIFunc/MIDIdef as well as other ddwMIDI responders.
- MIDI2OSCSocket transmits note messages over OSC to SuperCollider running on a remote machine. Not extensively tested.
- MIDIRecSocket records note data into a MIDIRecBuf.
- Controllers
- Controllers handle continuous-control, pitch-bend and aftertouch messages.
- AbstractMIDIControl is the parent of all MIDI controller classes.
- BasicMIDIControl installs a function. The function receives
|value, divisor, ccnum|
as arguments. - VoicerMIDIController connects control messages to a VoicerGlobalControl, which represents a control input that should apply to all synths played by the Voicer.
- VoicerSusPedal makes a Voicer respond to the sustain footswitch.
- MixerMIDIControl connects control messages to a MixerChannel's level control.
- MIDIThruControl passes note messages to another MIDI channel.
- MIDI2OSCControl transmits note messages over OSC to SuperCollider running on a remote machine. Not extensively tested.
In ddwMIDI, specify the source of incoming messages in the following ways:
OBJECT | MEANING |
nil | Default MIDI device, channel 0 |
Integer | Channel number, assuming default MIDI device |
\omni | Default MIDI device, any channel |
Array [device, channel] | The specified device and channel |
Array [device, \omni] | The specified device, any channel |
Array [\all, channel] | Any device, given channel |
Array [\all, \omni] | Any device, any channel |
Notes:
- SuperCollider indexes MIDI channels as 0-15. Most devices index them 1-16. If you specify channel 0 in SC, expect to use channel 1 on the device.
- Devices are identified by the integer index into
MIDIPort.sources
. Device 0 is the first in this array, and so on. Normally this is copied from MIDIClient.sources
upon the first use of any socket or controller. - The default MIDI device is index 0 in
MIDIPort.sources
. By default, this is the first device listed by MIDIClient.sources
. You can override the default device, by initializing MIDIPort explicitly: MIDIPort.init([defaultDeviceIndex])
. This assumes you know the index into the MIDIClient.sources
array. Typically, then, you will initialize MIDIClient first, and search the array for the device you want. See Selecting a default MIDI device.
Controller numbers may be specified as follows:
OBJECT | MEANING |
Integer | The controller number itself |
\pb | Pitch-bend wheel |
\touch | Aftertouch |
\omni | Any controller |
\ptouch | Poly-aftertouch |
CControl instance | Encapsulate a physical control and an attached button |
Time doesn't permit a full explanation of CControl in this draft. Soon...
NOTE: By default, continuous controllers do not respond until the incoming controller value either comes close to, or crosses, the existing value. This is to prevent the value in SuperCollider from jumping suddenly to a physical controller value that may be quite distant. You can disable this behavior globally by setting AbstractMIDIControl.syncByDefault = false
. It is currently not supported to choose this behavior per responder.
To be written later.