ChucK

Working with MIDI

by Adam Tindale

Adding a MIDI controller is a great way to add variety to your ChucK patches. Conversely, ChucK offers a simple and powerful way to utilize a MIDI controller for making music.

The first thing to do when working with MIDI is to make sure that ChucK sees all of your devices. You can do this by using the --probe start flag. Like this:

%>chuck --probe

ChucK will display a list of the connected audio and MIDI devices and their reference ID. We will assume that your controller is found to have and ID of 0. First, we must open a connection between ChucK and the port. We can accomplish this by creating a MidiIn object and then connecting it to a port.

//create object
MidiIn min;

//connect to port 0
min.open(0);

If you want to send MIDI out of ChucK you use the MidiOut object and then open a port.

//create object
MidiOut mout;

//connect to port 0
mout.open(0);

When opening ports it is suggested that you check whether the .open function returns properly. In some situations it doesn’t make any sense for the shred to live on if there is no MIDI data available to be sent along. You can check the return value of the .open function and then exit the shred using the me keyword with the exit() function.

MidiIn min;
min.open( 0 ) => int AmIOpen;

if( !AmIOpen ) { me.exit(); }

We can do this in fewer lines of code. We can put the min.open(0) in the condition of the if statement. This way min.open will return true or false (which is represented as ints with a value of 1 or 0). The ! will give the opposite return value of min.open. Now the statement will mean if min.open doesn’t return true then exit. Yeah?

if( !min.open(0) ) { me.exit(); }

Getting MIDI

In order to receive any of the juicy data you are piping into ChucK we need to ceate a MidiMsg ob ject. This ob ject is used to hold data that can be input into ChucK or output to a MIDI port. Unless you are high skilled at managing the state of these messages (or you enjoy the headache you get from debugging) it is recommended that you create a minimum of one MidiMsg for each port you are using.

What we need to do is get the data from the MidiIn ob ject into a message that we can use inside of ChucK. The MidiMsg ob ject is just a container with three slots: data1, data2 and data3. We fill these slots up by putting our message in the .recv( MidiMsg ) function of a MidiIn object. MidiIn keeps its messages in a queue so that you can poll it for messages and it will keep giving messages until it is empty. The .recv( MidiMsg ) function returns true and false so we can put it in a while loop and it will continue to run through the loop until there are no more messages left.

// check for messages every 10 milliseconds
while(10::ms => now){
  while( min.recv(msg) ){
    <<<msg.data1,msg.data2,msg.data3,"MIDI Message">>>;
  }
}

The Event system makes life a little easier and also makes sure that MIDI input is dealt with as soon as ChucK receives it. All that has to be done is to ChucK the MidiIn object to now and it will wait until a message is received to go further in the program.

while(true){
  // Use the MIDI Event from MidiIn
  min => now;
  while( min.recv(msg) ){
    <<<msg.data1,msg.data2,msg.data3,"MIDI Message">>>;
  }
}

Midi Output

If you have a synthesizer that you want to trigger from ChucK you can send MIDI messages to it simply. All you have to do is have a MidiMsg that will serve as the container for your data and then you will hand it to MidiOut using the .send( MidiMsg ) function.

MidiOut mout;
MidiMsg msg;
// check if port is open
if( !mout.open( 0 ) ) me.exit();

// fill the message with data
144 => msg.data1;
52 => msg.data2;
100 => msg.data3;
// bugs after this point can be sent
// to the manufacturer of your synth
mout.send( msg );