Monday, August 29, 2011

How To Deal With Real Time MIDI Beat Clock Data in Teensyduino

The Teensy is an affordable, compact and easy-to-use microcontroller development board. Part of the attraction of Teensy is the Teensyduino add-on for the Arduino software environment, which adds support for the Teensy board. One of the strengths of Teensy and Teensyduino is the ability to have the Teensy board appear as a USB HID MIDI device. This allows for the creation of interfaces and projects that register as native USB MIDI devices on the major operating systems.

Currently, the usbMIDI.read() function in Teensyduino reads a range of standard MIDI commands (sent from the computer host to the Teensy board), such as note on, note off, continuous controllers etc. However, there is no support for detecting and dealing with MIDI sync signals (also known as MIDI beat clock and real time system bytes).

I've edited the Teensyduino package to include a function made for dealing with real time system bytes. Thanks to Paul Stoffregen for his fantastic work with the Teensy board, and for his help in pushing me in the right direction with this. My edited files can be found here: http://milkcrate.com.au/_other/downloads/other/TeensyduinoRealTimeClockUpdate_20110829/

To add the functions to the Teensyduino code, simply right-click on the Arduino application and select "Show Package Contents". Copy and replace the files from the link above to Contents > Resources > Java > hardware > teensy > cores > usb_midi.

This will add a new handle (setHandleRealTimeSystem()) and a new function (RealTimeSystem()) that can be used in conjunction with usbMIDI.read() to receive MIDI beat clock data. To use the new code, set up a MIDI input sketch as you would normally with Teensyduino. Then:

1) add:
usbMIDI.setHandleRealTimeSystem(RealTimeSystem);
to void setup()

2) add a new function to the sketch:
void RealTimeSystem(byte realtimebyte) {
}

In the new function in (2) above, the byte realtimebyte is used for the MIDI beat clock data. The following bytes indicate which MIDI beat clock bytes have been received.

clock tick byte (at 24 pulses per quarter note) = 248;
start byte = 250;
continue byte = 251;
stop byte = 252;

Below is a working example, with code and a demo video. The LED that is part of the Teensy board lights up for every quarter note of sync data that is received via the USB cable.





// Teensyduino MIDI Beat Clock Example
// by Sebastian Tomczak
// 29 August 2011

byte counter;
byte CLOCK = 248;
byte START = 250;
byte CONTINUE = 251;
byte STOP = 252;

void setup() {
Serial.begin(31250);
pinMode(11, OUTPUT);
digitalWrite(11, HIGH);
usbMIDI.setHandleRealTimeSystem(RealTimeSystem);
}

void loop() {
usbMIDI.read();

}

void RealTimeSystem(byte realtimebyte) {
if(realtimebyte == 248) {
counter++;
if(counter == 24) {
counter = 0;
digitalWrite(11, HIGH);
}

if(counter == 12) {
digitalWrite(11, LOW);
}
}

if(realtimebyte == START || realtimebyte == CONTINUE) {
counter = 0;
digitalWrite(11, HIGH);
}

if(realtimebyte == STOP) {
digitalWrite(11, LOW);
}

}










If you have already edited usb_midi/usb_api.h and usb_midi/usb_api.cpp, then please see the following to check the code that I have changed and added.


12 comments:

Anonymous said...

this is awesome, I've been doing stuff in gcc w/out arduino specifically to access real time clock info.. why isnt this merged into the default usb_midi core? also, I am pretty sure you posted the wrong files, they appear to be from the usb_hid core folder, not the usb_midi one. I would LOVE you if you posted the usb_midi files patched as you described :)

Anonymous said...

When I try to verify the sketch in Arduino I get the message:

'usbMIDI' was not declared in this scope

Do you have any ideas as to why this is occurring?

Sebastian Tomczak said...

Hi there,

1) Are you using a Teensy board? Do you have a Teensy board selected in Arduino?

2) Do you have the MIDI type selected for the Teensy board?

3) Do you have the update installed that I posted in this blog post?

Anonymous said...

Yes I am using the Teensy 2.0 board and I have it selected in Arduino, I also have the MIDI type selected. I'm not sure what update you're talking about but as far as I know I followed this tutorial exactly.

Thank you for getting back to me.

Sebastian Tomczak said...

Hi there,
Seems like I had the wrong version of usb_api.cpp and usb_api.h uploaded - sorry about that!

Please re-download those two files and install them as per the blog post - hopefully that will solve the problem.

Anonymous said...

Hey,
I have re downloaded the files however it doesn't seem to have changed anything, I am still getting the message from Arduino.
When I looked over your usb_api.h and the usb_api.cpp file and compared them to the pictures at the bottom of this blog post they do not appear to be the same.
Can you check over the files once more?

Tyla said...

hey, im new to all this stuff and when i tryed doing this tutorial i got this... help???


sketch_nov23b:0: error: expected constructor, destructor, or type conversion before '.' token
sketch_nov23b:1: error: expected constructor, destructor, or type conversion before 'void'
sketch_nov23b:2: error: 'clock' does not name a type
sketch_nov23b:3: error: 'start' does not name a type
sketch_nov23b:4: error: expected unqualified-id before 'continue'
sketch_nov23b:5: error: 'stop' does not name a type
sketch_nov23b.cpp: In function 'void setup()':
sketch_nov23b:15: error: 'usbMIDI' was not declared in this scope
sketch_nov23b.cpp: In function 'void loop()':
sketch_nov23b:19: error: 'usbMIDI' was not declared in this scope

Cyb3rnator said...

heyy guys im having some real problems coding this, is there anyone with enough patience to give me a hand, i just want the gameboy to start when i press start on ableton, but it only keeps in sync if i selct sync when ableton is already playing.... please can anyone help me? my email is, Tyla-joe@hotmail.com
hit me up??

Cyb3rnator said...

heyy guys im having some real problems coding this, is there anyone with enough patience to give me a hand, i just want the gameboy to start when i press start on ableton, but it only keeps in sync if i selct sync when ableton is already playing.... please can anyone help me? my email is, Tyla-joe@hotmail.com
hit me up??

StĂȘ said...

Hi Sebastian,

I'm developing a tap tempo with the Teensy + + 2.0, but I'm having problems with reading and sending midi messages. Do you have any idea how to tap tempo function with the sending of messages?
I can read the clock, but I can not send the time it was generated through the tap (button). In which case, the idea would be to average the last 5 or 6 taps, and update the midi clock.

Thank you,

Nick said...

Hi Seb,

After looking at you modified teensy code, i've a quick question.
It seems that you added also a new type when you use usbMidi.getType
the type 8 which is also realtime message ?

I'm right ?

Nick said...

Hi Seb,

After looking at you modified teensy code, i've a quick question.
It seems that you added also a new type when you use usbMidi.getType
the type 8 which is also realtime message ?

I'm right ?