/* Modifications be John Kinkennon 3/27/18 * Added HWSERIAL commands to write to Serial Port 1. * Modified formatting for a serial enabled 2x16 LCD. * Based on the Teensy script MIDIInputFunctionsComplete. */ /* Receive Incoming USB 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. See InputFunctionsBasic for a smaller example using only the most common function. 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. */ #define HWSERIAL Serial1 unsigned char sysex[64]; int sx = 0; void setup() { Serial.begin(9600); HWSERIAL.begin(9600); delay(500); // wait for LCD to boot HWSERIAL.write(254); HWSERIAL.write(01); // Clear display usbMIDI.setHandleNoteOn(myNoteOn); usbMIDI.setHandleNoteOff(myNoteOff); usbMIDI.setHandleAfterTouchPoly(myAfterTouchPoly); usbMIDI.setHandleControlChange(myControlChange); usbMIDI.setHandleProgramChange(myProgramChange); usbMIDI.setHandleAfterTouchChannel(myAfterTouchChannel); usbMIDI.setHandlePitchChange(myPitchChange); // Only one of these System Exclusive handlers will actually be // used. See the comments below for the difference between them. usbMIDI.setHandleSystemExclusive(mySystemExclusiveChunk); usbMIDI.setHandleSystemExclusive(mySystemExclusive); usbMIDI.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame); usbMIDI.setHandleSongPosition(mySongPosition); usbMIDI.setHandleSongSelect(mySongSelect); usbMIDI.setHandleTuneRequest(myTuneRequest); usbMIDI.setHandleClock(myClock); usbMIDI.setHandleStart(myStart); usbMIDI.setHandleContinue(myContinue); usbMIDI.setHandleStop(myStop); usbMIDI.setHandleActiveSensing(myActiveSensing); usbMIDI.setHandleSystemReset(mySystemReset); // This generic System Real Time handler is only used if the // more specific ones are not set. usbMIDI.setHandleRealTimeSystem(myRealTimeSystem); } void loop() { // The handler functions are called when usbMIDI reads data. They // will not be called automatically. You must call usbMIDI.read() // regularly from loop() for usbMIDI to actually read incoming // data and run the handler functions as messages arrive. usbMIDI.read(); } void myNoteOn(byte channel, byte note, byte velocity) { // When using MIDIx4 or MIDIx16, usbMIDI.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); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Note On, ch="); HWSERIAL.print(channel, DEC); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("note="); HWSERIAL.print(note, DEC); HWSERIAL.print(", vel="); HWSERIAL.print(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); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Note Off, ch="); HWSERIAL.print(channel, DEC); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("note="); HWSERIAL.print(note, DEC); HWSERIAL.print(", vel="); HWSERIAL.print(velocity, DEC); } void myAfterTouchPoly(byte channel, byte note, byte velocity) { HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); Serial.print("AfterTouch Change, ch="); Serial.print(channel, DEC); Serial.print(", note="); Serial.print(note, DEC); Serial.print(", velocity="); Serial.println(velocity, DEC); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("AfterTouch, ch="); HWSERIAL.print(channel, DEC); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("note="); HWSERIAL.print(note, DEC); HWSERIAL.print(", vel="); HWSERIAL.print(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); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Cntrl Chg, ch="); HWSERIAL.print(channel, DEC); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("ctl="); HWSERIAL.print(control, DEC); HWSERIAL.print(", val="); HWSERIAL.print(value, DEC); } void myProgramChange(byte channel, byte program) { Serial.print("Program Change, ch="); Serial.print(channel, DEC); Serial.print(", program="); Serial.println(program, DEC); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Prog chg, ch="); HWSERIAL.print(channel, DEC); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("program="); HWSERIAL.print(program, DEC); } void myAfterTouchChannel(byte channel, byte pressure) { Serial.print("After Touch, ch="); Serial.print(channel, DEC); Serial.print(", pressure="); Serial.println(pressure, DEC); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("AfterTouch, ch="); HWSERIAL.print(channel, DEC); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("pressure="); HWSERIAL.print(pressure, DEC); } void myPitchChange(byte channel, int pitch) { Serial.print("Pitch Change, ch="); Serial.print(channel, DEC); Serial.print(", pitch="); Serial.println(pitch, DEC); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Pitch Chg, ch="); HWSERIAL.print(channel, DEC); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("pitch="); HWSERIAL.print(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 usbMIDI'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); // Fix the following to match a Hauptwerk SysEx to LCD int i; for (i = sx; i < length; i++) { sysex[sx++] = data[i]; } if (sx == 39) { for (i = 6; i < sx-1; i++) { HWSERIAL.write(sysex[i]); } } if (last) { sx = 0; for (i = 0; i < 64; i++) sysex[i] = 0; 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 usbMIDI. // 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); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Song Position"); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("beat="); HWSERIAL.print(beats, DEC); } void mySongSelect(byte songNumber) { Serial.print("Song Select, song="); Serial.println(songNumber, DEC); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Song Number"); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("song="); HWSERIAL.print(songNumber, DEC); } void myTuneRequest() { Serial.println("Tune Request"); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Tune Request"); } void myClock() { Serial.println("Clock"); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Clock"); } void myStart() { Serial.println("Start"); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Start"); } void myContinue() { Serial.println("Continue"); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Continue"); } void myStop() { Serial.println("Stop"); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Stop"); } void myActiveSensing() { Serial.println("Actvice Sensing"); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Active Sensing"); } void mySystemReset() { Serial.println("System Reset"); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("System Reset"); } void myRealTimeSystem(uint8_t realtimebyte) { Serial.print("Real Time Message, code="); Serial.println(realtimebyte, HEX); HWSERIAL.write(254); // Clear display, home cursor HWSERIAL.write(01); HWSERIAL.print("Real Time Message"); HWSERIAL.write(254); // Position curson to line 2 HWSERIAL.write(192); HWSERIAL.print("byte="); HWSERIAL.print(realtimebyte, DEC); } 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; } }