Skip to content

Instantly share code, notes, and snippets.

@todbot
Created March 10, 2020 22:42
Show Gist options
  • Save todbot/7f05268ed3c5201c163a3e269d2c2d64 to your computer and use it in GitHub Desktop.
Save todbot/7f05268ed3c5201c163a3e269d2c2d64 to your computer and use it in GitHub Desktop.
Demonstrate MIDI message loss by comparing received note-on vs note-off messages
/*
*******************************************************************************
* USB-MIDI dump utility
* Copyright (C) 2013-2017 Yuuichi Akagawa
*
* for use with USB Host Shield 2.0 from Circuitsathome.com
* https://github.com/felis/USB_Host_Shield_2.0
*
* This is sample program. Do not expect perfect behavior.
*******************************************************************************
*/
/*
* Demonstrate MIDI message loss by comparing received note-on vs note-off messages
* To use: connect MIDI keyboard and serial monitor, hit many keys, see note-on vs note-off mismatch
*/
#include <usbh_midi.h>
#include <usbhub.h>
//// On SAMD boards where the native USB port is also the serial console, use
//// Serial1 for the serial console. This applies to all SAMD boards except for
//// Arduino Zero and M0 boards.
#if (USB_VID==0x2341 && defined(ARDUINO_SAMD_ZERO)) || (USB_VID==0x2a03 && defined(ARDUINO_SAM_ZERO))
#define SerialDebug SERIAL_PORT_MONITOR
#else
#define SerialDebug Serial1
#endif
USBHost UsbH;
USBHub Hub(&UsbH);
USBH_MIDI Midi(&UsbH);
void MIDI_poll();
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime);
uint16_t pid, vid;
char buf[128]; // must hold full bufMidi as str plus metainfo
void setup()
{
vid = pid = 0;
SerialDebug.begin(115200);
if (UsbH.Init()) {
SerialDebug.println("USB host did not start");
while (1); //halt
}
delay( 200 );
}
void loop()
{
UsbH.Task();
//uint32_t t1 = (uint32_t)micros();
if ( Midi ) {
MIDI_poll();
}
}
int noteon_count = 0;
int noteoff_count = 0;
// parse out the multiple 4-byte USB-MIDI events inside the 64-byte USB packet
// display count of note on msgs vs note off msgs
void MIDI_parse(uint8_t* bufMidi)
{
for( int i=0; i<64; i+=4 ) { // stride of 4, all USB-MIDI are 4-bytes
uint8_t cn = bufMidi[i] >> 4; // cable number
uint8_t cin = bufMidi[i] & 0x0f; // code index number
uint8_t* midiMsg = bufMidi+i+1; // actual midi msg (1-3 bytes)
if( midiMsg[0] == 0x90 ) { noteon_count++; } // note on
if( midiMsg[0] == 0x80 ) { noteoff_count++; } // note off
}
sprintf(buf, "note on:%d note off:%d", noteon_count, noteoff_count);
SerialDebug.println(buf);
}
// Poll USB MIDI Controler and send to serial MIDI
void MIDI_poll()
{
uint8_t bufMidi[64];
uint16_t rcvd;
memset(bufMidi,0, sizeof(bufMidi)); // clear out in case rcvd lies
if (Midi.idVendor() != vid || Midi.idProduct() != pid) {
vid = Midi.idVendor();
pid = Midi.idProduct();
sprintf(buf, "VID:%04X, PID:%04X", vid, pid);
SerialDebug.println(buf);
}
if (Midi.RecvData(&rcvd, bufMidi) == 0 ) {
uint32_t time = (uint32_t)millis();
// Split variable to prevent warnings on the ESP8266 platform
sprintf(buf, "%04X%04X: ", (uint16_t)(time >> 16), (uint16_t)(time & 0xFFFF));
SerialDebug.print(buf);
SerialDebug.print(rcvd);
SerialDebug.print(':');
for (int i = 0; i < 64; i++) {
sprintf(buf, "%02X", bufMidi[i]);
SerialDebug.print(buf);
}
SerialDebug.println();
MIDI_parse(bufMidi);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment