skip navigational linksPJRC
Shopping Cart Checkout Shipping Cost Download Website
Home MP3 Player 8051 Tools All Projects PJRC Store Site Map
You are here: Teensy Teensyduino USB MIDI Search PJRC

PJRC Store
Teensy, $16
Teensy Pins, $19
Teensy++, $24
Teensy++ Pins, $27
USB Cable, $4
Teensy
Main Page
Getting Started
How-To Tips
Code Library
Projects
Teensyduino
Reference

Using USB MIDI

When you select "MIDI" from the Tools->USB Type menu, the Teensy becomes a USB MIDI (Musical Instrument Digital Interface) device, capable of sending and receiving MIDI messages.

MIDI can be used for non-music applications, such a controlling a large number of lights from a PC. Environments like Puredata and Max/MSP can give you access to MIDI for almost any purpose. MIDI is optimized to simultaneously transmit and receive large numbers of short messages with minimal delay.

Teensyduino implements a "class compliant" MIDI device, which can work with the built-in drivers on all major operating systems.

Transmitting Messages

These functions allow you to transmit all of the standard MIDI messages.

  usbMIDI.sendNoteOn(note, velocity, channel)
  usbMIDI.sendNoteOff(note, velocity, channel)
  usbMIDI.sendPolyPressure(note, pressure, channel)
  usbMIDI.sendControlChange(control, value, channel)
  usbMIDI.sendProgramChange(program, channel)
  usbMIDI.sendAfterTouch(pressure, channel)
  usbMIDI.sendPitchBend(value, channel)
  usbMIDI.sendSysEx(length, array)

MIDI messages are grouped together into USB packets. Up to 16 messages can transmit at once! They are held for a brief time, not more than 1 ms, to facilitate grouping. You can use the send_now() function to immediately allow any buffered messagse to transmit

  usbMIDI.send_now()

USB bandwidth is shared among devices. Usually there is very little delay, unless other USB devices are using all the available USB bandwidth.

Transmit Examples

Philip Cunningham's MIDI Controller reads 6 knobs and sends Control Change messages.

Arcade Button MIDI Controller (instructables)

This simple sketch shows how to use the Bounce library together with MIDI. A longer example can be found in File > Examples > Teensy > USB_MIDI > Buttons.

#include <Bounce.h>  // Bounce library makes button change detection easy
const int channel = 1;

Bounce button1 = Bounce(1, 5);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5);  // which is appropriate for good
Bounce button3 = Bounce(3, 5);  // quality mechanical pushbuttons
void setup() {
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
}

void loop() {
  button1.update();
  button2.update();
  button3.update();
  // Note On messages when each button is pressed
  if (button1.fallingEdge()) {
    usbMIDI.sendNoteOn(60, 99, channel);  // 60 = C4
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendNoteOn(61, 99, channel);  // 61 = C#4
  }
  if (button3.fallingEdge()) {
    usbMIDI.sendNoteOn(62, 99, channel);  // 62 = D4
  }
  // Note Off messages when each button is released
  if (button1.risingEdge()) {
    usbMIDI.sendNoteOff(60, 0, channel);  // 60 = C4
  }
  if (button2.risingEdge()) {
    usbMIDI.sendNoteOff(61, 0, channel);  // 61 = C#4
  }
  if (button3.risingEdge()) {
    usbMIDI.sendNoteOff(62, 0, channel);  // 62 = D4
  }
}

Transmit Issues

When using MIDI-OX on Windows, together with a sketch that transmits but never receives, open only the input device. From the menu Options > MIDI Devices, select "USB Audio Device" in the MIDI Inputs box. Do NOT select "USB Audio Device" in the MIDI Outputs box. Uncheck the "Automatically attach Inputs to Outputs during selection" box, then click OK.

Receiving Messages with Read & Callback Functions

The easiest way to receive MIDI messages is with functions that are automatically called when each type of message is received. Usually you would create one or more of these:

  void NoteOn(byte channel, byte note, byte velocity)
  void NoteOff(byte channel, byte note, byte velocity)
  void VelocityChange(byte channel, byte note, byte velocity)
  void ControlChange(byte channel, byte control, byte value)
  void ProgramChange(byte channel, byte program)
  void AfterTouch(byte channel, byte pressure)
  void PitchChange(byte channel, int pitch)

For each function you create, you must use the corresponding "setHandle" functions to tell usbMIDI to call it when that message type is read.

  usbMIDI.setHandleNoteOff(NoteOff)
  usbMIDI.setHandleNoteOn(NoteOn)
  usbMIDI.setHandleVelocityChange(VelocityChange)
  usbMIDI.setHandleControlChange(ControlChange)
  usbMIDI.setHandleProgramChange(ProgramChange)
  usbMIDI.setHandleAfterTouch(AfterTouch)
  usbMIDI.setHandlePitchChange(PitchChange)

Once everything is set up, you then need the "read" function to actually read data. The callback functions are only called when you use read. There are 2 choices for read:

  usbMIDI.read();         // All Channels

If you give a specific channel number to read, messages to other channels are ignored, which is easier than having to check the channel number in your callback function.

  usbMIDI.read(channel);  // One Specific Channel (1 to 16)

TODO: simple example program

Receiving Messages with Read & Query Functions

Instead of callback functions, you can also check the return value from read(). When it returns true, a new message has arrived. The "get" functions allow you to access information about the most recently received MIDI message.
  usbMIDI.getType()

The types are: 0 = Note Off, 1 = Note On, 2 = Velocity Change, 3 = Control Change, 4 = Program Change, 5 = After Touch, 6 = Pitch Bend, 7 = System Exclusive

  usbMIDI.getChannel()
The getChannel function gives you the channel number, from 1 to 16. If you requested only a specific channel when calling read, there is no need to use this.
  usbMIDI.getData1()
  usbMIDI.getData2()
The actual message data can be accessed with getData1 and getData2.
  usbMIDI.getSysExArray()
For system exclusive messages, the message data is available as an array. Use getData1 to find the number of bytes stored in the array.

Drum Machine Example

TODO: this section....