Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: How to forward raw MIDI bytes to USB MIDI?

  1. #1
    Junior Member
    Join Date
    Jun 2021
    Posts
    14

    How to forward raw MIDI bytes to USB MIDI?

    I'm working on a pair of devices that send (Mini Pro + NRF24L01) and receive (Teensy + NRF24L01) raw MIDI bytes from the source device. Currently, I don't even care about what kind of MIDI message it is, I just want to forward it to USB MIDI. There will be no Sysex messages coming in from the source device. I'm not quite sure about running status though - the source might be sending messages with running status.

    Teensy's documentation says:

    A generic send function is also available, primarily meant for use to forward messages between Serial (5 pin DIN) MIDI or USB Host MIDI.
    usbMIDI.send(type, data1, data2, channel)
    To use this function, I would need to parse the MIDI message.

    I have looked at the Interface_3x3 example and it uses SerialMIDI library to read and parse the incoming data:
    Code:
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
    
    if (MIDI1.read()) {
        // get a MIDI IN1 (Serial) message
        byte type = MIDI1.getType();
        byte channel = MIDI1.getChannel();
        byte data1 = MIDI1.getData1();
        byte data2 = MIDI1.getData2();
    
        usbMIDI.send(type, data1, data2, channel, 0);
    Is there any way to feed the raw bytes into serialMIDI? Should I use a serial port with TX+RX connected, send raw bytes to it, and read from it using serialMIDI? Seems somewhat overkill to me. Or should I use some other library that's capable of collecting raw bytes and parsing them?

  2. #2
    Junior Member
    Join Date
    Jun 2021
    Posts
    14
    I think I finally found something; sharing it in case it might be useful to others. It turns out I can reuse Control Surface MIDI library parser alone. It's a bit confusingly named SerialMIDI_Parser but actually, it is not linked to a serial port at all, it just accumulates bytes in a serial manner and tries to extract messages.

    Code:
    SerialMIDI_Parser parser;
    
    // in the loop:
    
        // feed the payload bytes and try to parse the message out, if possible
        MIDIReadEvent event = MIDIReadEvent::NO_MESSAGE;
    
        // in my case, payload is known to always contain a single MIDI message only
        for (uint8_t pl = 0; pl < payload.length; pl ++)
        {
            event = parser.parse(payload.message[pl]);
        }
        payload.usedLength = 0; // to prevent consuming the same data in the next iteration until we receive new bytes in the payload
    
        // only a single message is expected in the payload, so we can process it outside the "for" loop
        if (event == MIDIReadEvent::CHANNEL_MESSAGE)
        {
            usbMidi.send(parser.getChannelMessage());
        } 
        else if (event == MIDIReadEvent::REALTIME_MESSAGE)
        {
            usbMidi.send(parser.getRealTimeMessage());
        } 
        
        // MIDI Controllers should discard incoming MIDI messages.
        // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
        // update reads the messages internally and discards them if we don't have any processing callbacks set
        usbMidi.update();
    It looks naive but seems to work well enough. If there are better ways to do it, I will appreciate your suggestions. I somehow could not find a similar reusable byte-accumulating-parser in the default Teensy USB MIDI libraries.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    26,799
    Quote Originally Posted by progmars View Post
    Is there any way to feed the raw bytes into serialMIDI? Should I use a serial port with TX+RX connected, send raw bytes to it, and read from it using serialMIDI? Seems somewhat overkill to me.
    It's not overkill at all. The Interface_3x3 example is the correct way.

    The actual data format used by USB MIDI is not the same as traditional Serial MIDI. Messages are aligned to 32 bit boundaries with virtual cable/port info added and a redundant copy of the message type bits. Sysex messages are encoded in a special way too. So you can't just copy the raw bytes between Serial MIDI and USB MIDI.

    Teensy USB MIDI isn't designed to give you access to the raw data bytes at the USB bulk packet level. It uses the same API (or as similar as I could make it) to the widely used MIDI library. But if it did give raw data access, you would need to use the special 32 bit fields format specific to USB MIDI. A different set of bytes are needed to represent the same MIDI messages.

  4. #4
    Junior Member
    Join Date
    Jun 2021
    Posts
    14
    Yes, I suspected that USB MIDI protocol has its specifics and it would not work with direct pass-through of "old style" serial MIDI bytes. I hoped there was a way to tell USB MIDI API "Here are raw bytes of serial MIDI without separated status & channel; please interpret them as necessary to extract a proper MIDI message and then send it to USB MIDI according to its protocol."

    At least I got it working with the Control Surface library, although it's larg-ish and includes lots of stuff that I don't actually need. All I needed was an accumulating MIDI parser. Teensy's MIDI also has something similar, but it is not exposed as an API, because, as you said, to be compatible with other popular MIDI APIs.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •