Go Down

Topic: Convert USB MIDI to recognizable MIDI format (Read 527 times) previous topic - next topic

Dr-Zee

Dec 10, 2020, 05:53 pm Last Edit: Dec 10, 2020, 07:18 pm by Dr-Zee
I have a USB host shield on an Arduino Leonardo, powered with 5v via the USB on the Leonardo.
The shield is connected to a piano's USB MIDI out.

I'm trying to isolate a couple parameters of the incoming midi data to control a peripheral. I'm having difficulty dumping and observing the MIDI data in a meaningful way.
Using the USBH_MIDI_dump example in the USB_Host_Shield_2.0 library, I can register key down and up events, and using the bidirectional_converter example, even send random/mystery data to the piano.

Here is the portion of the MIDI_dump sketch I think is most relevant.
Code: [Select]

 if (Midi.RecvData( &rcvd,  bufMidi) == 0 ) {
    uint32_t time = (uint32_t)millis();
    sprintf(buf, "%04X%04X: ", (uint16_t)(time >> 16), (uint16_t)(time & 0xFFFF)); // Split variable to prevent warnings on the ESP8266 platform
    Serial.print(buf);
    Serial.print(rcvd);
    Serial.print(':');
    for (int i = 0; i < 64; i++) {
      sprintf(buf, " %02X", bufMidi[i]);
      Serial.print(buf);
    }
    Serial.println("");
  }


Here we check if MIDI was received, iterate through it, split it and prints it in a way that I think is meant to be more easily readable. Regardless, I don't understand the data that's output. Is there a conversion I need to do on the received data? As it is, I'm unable to parse or manipulate the data because I'm ignorant of what it is.

Below is the data returned for a key down and key up event.

Code: [Select]

0000363F: 4: 09 90 18 4D 00 00 00 08 82 05 22 01 00 01 01 02 00 01 02 71 10 A4 00 00 40 00 00 00 00 08 82 05 22 01 00 01 01 02 00 01 04 01 00 A0 0F CB 10 43 04 03 03 B3 0F FF 20 00 00 B5 B6 35 57 00 04 50
000036AF: 4: 08 80 18 66 00 00 00 08 82 05 22 01 00 01 01 02 00 01 02 71 10 A4 00 00 40 00 00 00 00 08 82 05 22 01 00 01 01 02 00 01 04 01 00 A0 0F CB 10 43 04 03 03 B3 0F FF 20 00 00 B5 B6 35 57 00 04 50


Or for the USB_MIDI_converter example, if I dump the data being output via the serial port,
Code: [Select]
 do {
    if ( (size = Midi.RecvData(outBuf)) > 0 ) {
      //MIDI Output
      _MIDI_SERIAL_PORT.write(outBuf, size);
    }
  } while (size > 0);


every key press returns
Code: [Select]

121 3



Of the USB MIDI libraries I've tried, these USB_Host_Shield_2.0 MIDI examples are the only one's that I've had some success with. They receive and send some form of midi data.

Searching around, most people posting about using the shield aren't interested in decoding or manipulating MIDI in from a source, so I haven't found resources about this particular issue.

Any guidance is very appreciated. Thank you.

PieterP

MIDI.RecvData writes the number of bytes it read to the rcvd variable. You're printing the entire buffer, which is meaningless, you should only print bytes 0 through rcvd-1:

Code: [Select]
   for (int i = 0; i < rcvd; i++) {
      sprintf(buf, " %02X", bufMidi[i]);
      Serial.print(buf);
    }


So the valid data from your experiment is:
Code: [Select]
0000363F: 4: 09 90 18 4D
000036AF: 4: 08 80 18 66

To interpret this data, you'll have to read the MIDI USB spec: https://www.midi.org/specifications/midi-transports-specifications/usb

A first byte of 09 means that the cable number for this message is 0 (CN = 0) and that the message is a MIDI Note On Channel Message (CIN = 9).
The second byte of 90 means that it is a MIDI Note On message on channel 1.
The third byte of 18 is the note number (24 semitones from the lowest note).
The fourth byte of 4D is the velocity.

Pieter

Dr-Zee

#2
Dec 10, 2020, 07:20 pm Last Edit: Dec 10, 2020, 07:44 pm by Dr-Zee
MIDI.RecvData writes the number of bytes it read to the rcvd variable. You're printing the entire buffer, which is meaningless, you should only print bytes 0 through rcvd-1:

Code: [Select]
    for (int i = 0; i < rcvd; i++) {
      sprintf(buf, " %02X", bufMidi[i]);
      Serial.print(buf);
    }


So the valid data from your experiment is:
Code: [Select]
0000363F: 4: 09 90 18 4D
000036AF: 4: 08 80 18 66

To interpret this data, you'll have to read the MIDI USB spec: https://www.midi.org/specifications/midi-transports-specifications/usb

A first byte of 09 means that the cable number for this message is 0 (CN = 0) and that the message is a MIDI Note On Channel Message (CIN = 9).
The second byte of 90 means that it is a MIDI Note On message on channel 1.
The third byte of 18 is the note number (24 semitones from the lowest note).
The fourth byte of 4D is the velocity.

Pieter
Thank you so much. This is wildly helpful.
It's 24 semitones? Wouldn't it be 4 semitones on an 88 key keyboard? I thought key 21 was A0
Regardless, up next will be figuring out how why it registered a key that doesn't exist.
Thanks again.

PieterP

It's 24 semitones? Wouldn't it be 4 semitones on an 88 key keyboard? I thought key 21 was A0
Regardless, up next will be figuring out how why it registered a key that doesn't exist.
1816 = 2410
The lowest MIDI note is C-1. Note 24 is two octaves higher, so C1.

Go Up