MIDIClient.init;
The functionality of MKtl relies on descriptions of the devices to be used. For many controllers, there are already descriptions available, but your preferred device may not be among them.
This tutorial first shows simple examples of MIDI interfaces, by emulating them within SuperCollider, and then describes how to create a description file for your interface.
In this section we will go through the different types of MIDI messages for communicating element states from a MIDI-device to SuperCollider and show how to write a description for them.
There are a number of different types of MIDI messages:
To try out the examples below even without a physical device at hand, we will use SuperColliders own MIDI input and output.
Find all MIDI devices and do the MIDI initialisation (implicitely within the MKtl implementation):
On OSX, this should now show something like this in the post window:
The following code creates a (virtual) MIDI loopback connection between ~midiOut
and ~midiIn
and stores information on your setup in ~idInfo
:
MIDI note messages were originally designed for piano keys on a MIDI keyboard. However, in many MIDI controllers they are used to report on states of elements like buttons or drum pads.
MIDI noteOn
messages have a note number defining which key was pressed, and a velocity value defining the speed or intensity with which it was pressed. A typical mapping for velocity would be the amplitude of a sound such that it gets louder with the amount of energy applied to press the corresponding key.
When the key is lifted again (i.e. the note is released), a noteOff
message is sent. It again features a note number and a velocity value. By interpreting this velocity as the release speed, a resonable mapping would be stretching the release time of sound's envelope). Instead of a noteOff
, many MIDI devices send a noteOn
message with velocity 0
, which is officially supported, and many MIDI toolkits translate this into a noteOff 0 message.
SuperCollider allows turning this translation on and off if desired
For details, see https://github.com/supercollider/supercollider/issues/1483 and https://github.com/supercollider/supercollider/pull/1488
As a first example, we now create an MKtl containing exactly one MKtlElement that responds to a noteOn
event. For mapping its velocity we use the spec: \midiVel
identifier, which tells the system to normalise the raw value range of velocity values (0
to 127
) to values between 0
and 1
.
As a second example, we show how to make an element that responds to a noteOff
message:
To get noteOn and noteOff actions separately, one can make separate elements, and here one can declare shared properties for both elements with full flexibility, like this:
The \groupType
key allows concisely defining the following combinations of noteOn, noteOff and touch by a single name, and building them correctly:
tag: | description: | noteOn: | noteOff: | touch: | comment |
\noteOnTrig | trigger pad | 127 | - | - | |
\noteOnVel | trig pad w/ vel. | 1-127 | - | - | |
\noteOnOff | piano key w/ on vel. | 1-127 | 0 | - | default |
\noteOnOffBut | button on/off | 127 | 0 | - | |
\noteOnOffVel | pad/key w/ off vel. | 1-127 | 1-127 | - | rare |
\noteOnOffTouch | pad/key w/ polytouch | 1-127 | 0 | 0-127 | semi-rare |
\noteOnOffVelTouch | pad/key w/ off vel and touch | 1-127 | 1-127 | 1-127 | very rare |
See Tutorials/Using groupType in MKtlDescs for a full discussion. As a first example, here is how to make a
MIDI control messages are typically sent out by knobs, sliders or pedals on a device, but in some cases also buttons or built-in sensors.
Modality has support for 14 bit MIDI.
14 bit midi is achieved by combining two midi CC's into one. They are offset by 32 steps in their cc numbers which means that a sending device may send the first part of it on midi cc 16, and then the rest at midi cc 48.
In Modality, you only need to specify the first "lower" midi cc channel and then Modality will handle the rest of it for you. To use this functionality, specify the midiMsgType key in your description as \cc14 and optionally your spec as \midiCC14 like so:
MIDI pitch bend messages are sent out by MIDI keyboards - usually a control in the shape of a wheel that flips back to its center position left of the keyboard. On some of the mini keyboards that you can find, the pitch bend message is implemented via buttons on the device in the same location.
Aftertouch is the pressure that is on a piano key after the initial pressing (which is translated to note velocity as explained above). The MIDI protocol implements aftertouch in two ways:
Basic Aftertouch, also called channel pressure, has a single aftertouch value per midi channel, which is usually applied to all notes playing on that channel. Tis is the more common touch implementation in hardware controllers. In SC, this is called \touch
.
PolyTouch, or polyphonic aftertouch, allows an individual aftertouch value for every currently playing note. In SC, this is called \polyTouch
.
MIDI program change messages are typically sent when a device is changing the patch that is played on the synthesizer. They can be implemented by buttons, or knobs.
In this section we will go through all the different types of MIDI messages that may be sent out and show how to write a description for that element.
Typical use of MIDI output on controllers would be controlling the LEDs on the device that indicate the current mode of the instrument that you are building, or telling motorized faders the values/positions they should move to.
But you could also create an MKtl that connects to a hardware synthesizer - or another software program, and use the Modality toolkit to send the control messages to it.
Which MIDI messages a controller reacts to can be found out from the controller's manual. Alternatively, you could just send it a bunch of different messages and see what happens. Apart from system exclusive messages, this should be safe to do - system exclusive messages can be used for uploading new firmware or changing firmware mode, so don't just experiment with that, without properly informing yourself first.
First, find your device in the list posted by the following code and assign the MKtl to a variable.
Now, turn on the explore mode and move every element on your controller. Make sure to go through all of them and move them in all their degrees of freedom.
When done, create a raw description file which you will edit and review in the next step.
MIDIExplorer.compile
and copy the code from the post window manually to a new file.We now have a file that contains all the raw data we need for the description file, and that already works as a full desc file. However, it is worth spending time on editing it for for semantic clarity, by better element names, and good grouping.
Detailed background info sources:
Steps for editing desc files:
We go thru the process step by step with raw data that may have come from the MKtl().explore
as mentioned above. It contains information of a device with three knobs:
\knob
, it registers as \slider
. This is because only a cc value is coming in, and it does not state what kind of hardware element is producing it.Edit the raw elements by giving them better names (assuming buttons are labeled A, B, C); and put them in a named group:
In case there are two columns of 3 knobs each, the flat list of 6 knobs would become a hierarchical structure like this:
\noteOn, \noteOff, \polyTouch
is still missing in this tutorial. Several existing desc files do that already, e.g. see:
If you are happy with the generated document, save it with a meaningful name to the user folder for descriptions, which is here:
The filename should be "<company-devicename-extra-info>", and must end in ".desc.scd"
. After adding a new desc file, please do
You are highly welcome to contribute your desc files to modality! Especially when they are generally useful (i.e. not for a selfmade or customized device that only you have), you can save it to the defaultFolder, and submit a pull request at github, or mail it to the modality list.
To test your new description file, restart SuperCollider and follow instructions in Modality Tutorial.
/// ... To be updated using the MIDIMonitor class when finished ... ///
In the simple case, your MIDI device creates a single MIDI source port, by which it sends MIDI to the computer, and optionally a MIDI destination port by which you can send MIDI messages to it. In this case you only need to define the name of the MIDI device, as it shows up when you do MKtl.find
.
If several devices of the same kind are connected, MKtl.find(\midi) will propose all of them as possible MKtls to choose, e.g. two nanoKontrol2s:
Some MIDI devices use multiple MIDI ports, and MKtl treats these as separate devices for which you can make independent MKtls. E.g. the Steinberg CMC-PD or the QuNexus do this. For such devices, you can make separate descriptions for each port number, and you specify the port number in the description: You then make a Dictionary of the idInfo
with the field name
with the name of the device (as it shows up after MKtl.find
), and then define the srcPortIndex
and/or the destPortIndex
; if either one is not specified, it takes the first one.
Some MIDI devices can be configured to special modes, eo one can e.g. set their LEDs to specific values, or generally, activate everything one wants to use. This is done by sending special messages (usually long and cryptic sysex). You can define these and other special messages in the specialMessages
field of the device description. For MIDI such a message has to be an Array of messages, and message begins with the type of MIDI message (as you would send it with MIDIOut) and then the parameters to be sent.
For example: to configure the nanoKONTROL2 to a mode where one can access its LEDs from outside, one sends it a series of sysex messages. Some manufacturers do not document such technical details, and the messages in the nanoKONTROL2 desc file are simply exact reproductions of the messages the Korg KONTROL editor sends to the device when enabling external led control (which we found in a code base of someone else again). If your device responds special messages to tune its behavior, you can find out what they are from the manual, by monitoring its configuration software, or get the info from someone who found this out and documented it (online, forums etc.)
If the device expects control messages, it would look like this: