/* Receive Incoming USB Host MIDI using functions. As usbMIDI reads incoming messages, handler functions are run. See the InputRead example for the non-function alterative. This very long example demonstrates all possible handler functions. Most applications need only some of these. This example is meant to allow easy copy-and-paste of the desired functions. Use the Arduino Serial Monitor to view the messages as Teensy receives them by USB MIDI You must select MIDI from the "Tools > USB Type" menu This example code is in the public domain. */ #include USBHost myusb; USBHub hub1(myusb); USBHub hub2(myusb); MIDIDevice midi1(myusb); void setup() { Serial.begin(115200); // Wait 1.5 seconds before turning on USB Host. If connected USB devices // use too much power, Teensy at least completes USB enumeration, which // makes isolating the power issue easier. delay(1500); Serial.println("USB Host InputFunctions example"); delay(10); myusb.begin(); midi1.setHandleNoteOn(myNoteOn); midi1.setHandleNoteOff(myNoteOff); midi1.setHandleAfterTouchPoly(myAfterTouchPoly); midi1.setHandleControlChange(myControlChange); midi1.setHandleProgramChange(myProgramChange); midi1.setHandleAfterTouchChannel(myAfterTouchChannel); midi1.setHandlePitchChange(myPitchChange); // Only one of these System Exclusive handlers will actually be // used. See the comments below for the difference between them. midi1.setHandleSystemExclusive(mySystemExclusiveChunk); midi1.setHandleSystemExclusive(mySystemExclusive); midi1.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame); midi1.setHandleSongPosition(mySongPosition); midi1.setHandleSongSelect(mySongSelect); midi1.setHandleTuneRequest(myTuneRequest); midi1.setHandleClock(myClock); midi1.setHandleStart(myStart); midi1.setHandleContinue(myContinue); midi1.setHandleStop(myStop); midi1.setHandleActiveSensing(myActiveSensing); midi1.setHandleSystemReset(mySystemReset); // This generic System Real Time handler is only used if the // more specific ones are not set. midi1.setHandleRealTimeSystem(myRealTimeSystem); } void loop() { // The handler functions are called when midi1 reads data. They // will not be called automatically. You must call midi1.read() // regularly from loop() for midi1 to actually read incoming // data and run the handler functions as messages arrive. myusb.Task(); midi1.read(); } void myNoteOn(byte channel, byte note, byte velocity) { // When a USB device with multiple virtual cables is used, // midi1.getCable() can be used to read which of the virtual // MIDI cables received this message. Serial.print("Note On, ch="); Serial.print(channel, DEC); Serial.print(", note="); Serial.print(note, DEC); Serial.print(", velocity="); Serial.println(velocity, DEC); } void myNoteOff(byte channel, byte note, byte velocity) { Serial.print("Note Off, ch="); Serial.print(channel, DEC); Serial.print(", note="); Serial.print(note, DEC); Serial.print(", velocity="); Serial.println(velocity, DEC); } void myAfterTouchPoly(byte channel, byte note, byte velocity) { Serial.print("AfterTouch Change, ch="); Serial.print(channel, DEC); Serial.print(", note="); Serial.print(note, DEC); Serial.print(", velocity="); Serial.println(velocity, DEC); } void myControlChange(byte channel, byte control, byte value) { Serial.print("Control Change, ch="); Serial.print(channel, DEC); Serial.print(", control="); Serial.print(control, DEC); Serial.print(", value="); Serial.println(value, DEC); } void myProgramChange(byte channel, byte program) { Serial.print("Program Change, ch="); Serial.print(channel, DEC); Serial.print(", program="); Serial.println(program, DEC); } void myAfterTouchChannel(byte channel, byte pressure) { Serial.print("After Touch, ch="); Serial.print(channel, DEC); Serial.print(", pressure="); Serial.println(pressure, DEC); } void myPitchChange(byte channel, int pitch) { Serial.print("Pitch Change, ch="); Serial.print(channel, DEC); Serial.print(", pitch="); Serial.println(pitch, DEC); } // This 3-input System Exclusive function is more complex, but allows you to // process very large messages which do not fully fit within the midi1's // internal buffer. Large messages are given to you in chunks, with the // 3rd parameter to tell you which is the last chunk. This function is // a Teensy extension, not available in the Arduino MIDI library. // void mySystemExclusiveChunk(const byte *data, uint16_t length, bool last) { Serial.print("SysEx Message: "); printBytes(data, length); if (last) { Serial.println(" (end)"); } else { Serial.println(" (to be continued)"); } } // This simpler 2-input System Exclusive function can only receive messages // up to the size of the internal buffer. Larger messages are truncated, with // no way to receive the data which did not fit in the buffer. If both types // of SysEx functions are set, the 3-input version will be called by midi1. // void mySystemExclusive(byte *data, unsigned int length) { Serial.print("SysEx Message: "); printBytes(data, length); Serial.println(); } void myTimeCodeQuarterFrame(byte data) { static char SMPTE[8]={'0','0','0','0','0','0','0','0'}; static byte fps=0; byte index = data >> 4; byte number = data & 15; if (index == 7) { fps = (number >> 1) & 3; number = number & 1; } if (index < 8 || number < 10) { SMPTE[index] = number + '0'; Serial.print("TimeCode: "); // perhaps only print when index == 7 Serial.print(SMPTE[7]); Serial.print(SMPTE[6]); Serial.print(':'); Serial.print(SMPTE[5]); Serial.print(SMPTE[4]); Serial.print(':'); Serial.print(SMPTE[3]); Serial.print(SMPTE[2]); Serial.print('.'); Serial.print(SMPTE[1]); // perhaps add 2 to compensate for MIDI latency? Serial.print(SMPTE[0]); switch (fps) { case 0: Serial.println(" 24 fps"); break; case 1: Serial.println(" 25 fps"); break; case 2: Serial.println(" 29.97 fps"); break; case 3: Serial.println(" 30 fps"); break; } } else { Serial.print("TimeCode: invalid data = "); Serial.println(data, HEX); } } void mySongPosition(uint16_t beats) { Serial.print("Song Position, beat="); Serial.println(beats); } void mySongSelect(byte songNumber) { Serial.print("Song Select, song="); Serial.println(songNumber, DEC); } void myTuneRequest() { Serial.println("Tune Request"); } void myClock() { Serial.println("Clock"); } void myStart() { Serial.println("Start"); } void myContinue() { Serial.println("Continue"); } void myStop() { Serial.println("Stop"); } void myActiveSensing() { Serial.println("Actvice Sensing"); } void mySystemReset() { Serial.println("System Reset"); } void myRealTimeSystem(uint8_t realtimebyte) { Serial.print("Real Time Message, code="); Serial.println(realtimebyte, HEX); } void printBytes(const byte *data, unsigned int size) { while (size > 0) { byte b = *data++; if (b < 16) Serial.print('0'); Serial.print(b, HEX); if (size > 1) Serial.print(' '); size = size - 1; } }