Tuesday, May 16, 2017

Teensy 3.6 Basics - Receiving MIDI CC

The Teensyduino add-on for Arduino allows the Teensy 3.6 to easily read MIDI messages such as notes and control changes over USB. A computer or other USB-enabled device sends a MIDI message, and then the Teensy received the message, and can perform a given set of actions based on the contents of that message. 

For example, Ableton Live sends a control message for controller 1, value 127 and channel 1 to the Teensy. Note that MIDI has 128 controllers per channel, across all 16 channels. The value range is 0 - 127. 

The code on the Teensy can then read the USB MIDI bus, recognise that a control message has been received, filter just the channel 1 messages, filter just the messages that have a control number of 127 and so on, and then set the modulation amount of an oscillator based on the incoming controller value. 

The examples presented here provide a very basic structure that can be added to, modified and extended. Nonetheless, this is illustrative of receiving control messages and then responding in some way. 

Consider how control messages can be mapped to different hardware and software components, as there are many possibilities. To read more information about this, please see the Teensyduino documentation here: https://www.pjrc.com/teensy/td_midi.html

Hardware Setup

There is no hardware setup, as the onboard LED is used as a response to incoming MIDI data. 

Software Setup
A DAW must be configured so that the Teensy is an output device for note and control data. 

With Ableton Live, go to the Link MIDI preferences panel, and set Track, Sync and Remote MIDI In for the Teensy to OFF, Sync MIDI Out for the Teensy to OFF and Track and Remote MIDI Out for the Teensy to ON, as shown below. 

Using a MIDI track (without a virtual instrument), set the output to the Teensy, as shown below. 

Any note or control data sent from this track will now be received by the Teensy. To read and then respond to the data, the Teensy code must contain three components. 

The first is that the main loop() function should contain usbMIDI.read() in order to read any incoming data from the USB port. 

The second is that the setup() function should contain a usbMIDI.setHandleControlChange(OnCC) function.

The argument used for usbMIDI.setHandleControlChange() points to a user-defined function, and could have any name at all. usbMIDI.setHandleControlChange() connects the receiving of control messages with a particular function that is executed whenever a note message is received. 

The third component is that for every argument used in a setHandle function, there must exist a corresponding user-defined function that takes a particular form depending on the type of MIDI data received. 

To read more information about this, please see the Teensyduino documentation here: https://www.pjrc.com/teensy/td_midi.html

Every time a new control message is received by usbMIDI.read(), the function that is defined as the argument set by usbMIDI.setHandleControlChange() then processes the control message. The order of arguments of the user-defined function must be channel, controller number, controller value. 

Example 1 - Turn LED On for CC Values Above 64
The Teensy receives control data. If the control value is above 64, then the LED is turned on. 

Example 2 - Turn On LED for Controller Number 1, Turn Off LED for Controller Number 2
The Teensy receives control data. If the message is from controller 1, then the LED is turned on.  If the message is from controller 2, then the LED is turned off. 

Receiving and responding to MIDI CC values can be very useful for controlling light values, RGB values, motors, movement, hardware synths, etc. 


JohnDavidLloyd said...

Hey! This is so great, your other blog post helped me figure out the midi output to midi. Now I have a problem,

How would I be able to make the CC values change with PWM?
0-127 as 0 is no light, and 127 is maximum brightness.

Would love to know how to do this! My research so far has got me lost. Thank you for any help!

Sebastian Tomczak said...

Hi JohnDavidLloyd,
Do you mean use a MIDI CC value sent from a computer to then control the PWM duty of an LED?

If so - please have a look at this example:

int LED = 13; // variable for LED pin
int LED_PWM_pin = 2;

void setup() {
usbMIDI.setHandleControlChange(OnCC); // set handle for MIDI continuous controller messages
pinMode(LED, OUTPUT); // set LED pin to output

void loop() {
usbMIDI.read(); // read the USB MIDI bus every loop

// this function is called whenever a MIDI continuous controller messahe is received
// the function is executed using the received message bytes of channel, controller and value corresponding to the variable names below
// for example, a modulation wheel message the first channel with a half value will be called with OnCC(1, 1, 64);
// messaged can be filtered by controller value

void OnCC(byte channel, byte controller, byte value) {
if(controller == 1) {
analogWrite(LED_PWM_pin, value);