Go Down

Topic: Leonardo direct MIDI USB (Read 29602 times) previous topic - next topic


I think teensy has a board with MIDI driver embedded


Unfortunately, to add support for MIDI you have to hack in the Arduino core files. I've hacked in a MIDI-USB implementation in an alternative set of core files, which is available at https://github.com/rkistner/arcore. The MIDI-USB protocol is fairly simple (once you get around the USB interface descriptors), and the implementation is quite similar to CDC (I based my implementation off that).

In the long run it might be better if we could use an existing stack with MIDI support, but it seemed complicated to replace Arduino's USB stack with another one.

I've been working with arcore for a few days and so far it seems to be working nicely.

Here's an example sketch that lets you send MIDI from the host (PC or Mac) and the Arduino will mirror that back out to an external device.  The nice thing about using arcore is that it's all in the application space, the bootloader can be anything you like.  Arcore does eat some application space, whereas most of the LUFA bootloaders fit in the same sized booloader partition and don't encroach.


Code: [Select]
// USB MIDI -> USB Serial Bridge
// Disaster Area Designs LLC
// http://www.disasterareadesigns.com
// Using rkistner's arcore modifications
// https://github.com/rkistner/arcore

void setup() {

  // Initialize UART serial port, pins 0 and 1
  // at correct baud rate for MIDI transmission


void loop() {
    while(MIDIUSB.available() > 0) {
    // USB MIDI core interprets USB MIDI and passes out MIDIEvents when a completed message is received
    MIDIEvent e;
    e = MIDIUSB.read();
    // Flush out queue to make sure we don't hang on to incomplete messages
    // MIDIEvents are "structs," with 4 members:
    // type, m1, m2, m3.
    // All MIDI messages consist of at least one byte.
    // We need to pass the first byte out to the serial port.
    // Not all MIDI messages have all 3 data bytes
    // So we use the contents of the MIDIEvent to test and make
    // sure we only send out the required number of bytes.
    switch (e.type) {
      // single-byte messages
      case 0x5:
      case 0xF:
      // two-byte messages
      case 0x2:
      case 0x6:
      case 0xC:
      case 0xD:
      // all other valid messages are three-byte

If you wanted to use the UART on the Arduino to send MIDI back to the host, you'd have to test based on the message type and pre-pend the USB message type.

A USB MIDI event is a little more complicated than the old-style serial MIDI message.  It is a 32-bit message, with any unused bits padded with zeroes.  Serial MIDI messages are of varying length, which kind of stinks if you're trying to read them in.

The first byte of USB MIDI consists of a 4 bit "cable number," and a 4-byte "code index number."  The cable number is similar to the MIDI channel, except that it indicates the virtual MIDI interface that's part of the USB device.  The arcore MIDI device has a cable number of 0x00.

The code index number is next, and it indicates the message type.

Generally these are the same as the first bits of the serial message codes, for example MIDI CC is code index 0xB, and the serial message is 0xBn, where "n" is the MIDI channel.  The code index numbers also indicate how many bytes are present in the message.  Anything after the indicated number of bytes can be safely discarded, since they're padding rather than real data.

arcore packs this code index number into the "type" member of the MIDIEvent struct.  You can access it at any time by reading in an available MIDIEvent and then using the member.  See the code above for an example.

The next three bytes are the MIDI message.  Not all three bytes will always be needed, but passing zeroes to a connected device that doesn't expect them will mess things up so we need to not send them.

Interestingly, you can still send messages on any of the 16 MIDI channels per cable over USB.  arcore just uses the one cable, but in theory you could implement more cables for more interfaces if you needed them.


I'm not sure this is related to this post

Can it identify itself as a MIDI device to a PC?


Now available for testing:

Only works with 32u4 (leonardo/micro) and is activated by default. Select one of the USB-Cores, but no HID will work.
I really need feedback about this, I just made it recognize by the PC but had no chance to test it yet.


Go Up