/* USB MIDI Sync Slave Box Monitor * * This example demonstrates how to create a * MIDI hid compilant slave clock box with * monitor support using oled displays * * Making use of a 16 usceconds timer to * handle MIDI input to avoid jitter on clock * * You need the following libraries to make it work * - u8g2 * - uClock * * This example make use of drift values (1, 4) * respectively for internal and external drift reference. * This example was tested on a macbook * running ableton live 9 as master clock * * This example code is in the public domain. */ #include // // BPM Clock support // #include U8X8 * u8x8; IntervalTimer teensyTimer; // MIDI clock, start, stop, note on and note off byte definitions - based on MIDI 1.0 Standards. #define MIDI_CLOCK 0xF8 #define MIDI_START 0xFA #define MIDI_STOP 0xFC char bpm_str[4]; float bpm = 126; uint8_t bpm_blink_timer = 1; uint8_t clock_state = 1; void handle_bpm_led(uint32_t * tick) { // BPM led indicator if ( !(*tick % (96)) || (*tick == 1) ) { // first compass step will flash longer bpm_blink_timer = 8; digitalWrite(LED_BUILTIN, HIGH); } else if ( !(*tick % (24)) ) { // each quarter led on digitalWrite(LED_BUILTIN, HIGH); } else if ( !(*tick % bpm_blink_timer) ) { // get led off digitalWrite(LED_BUILTIN, LOW); bpm_blink_timer = 1; } } // Internal clock handlers void ClockOut96PPQN(uint32_t * tick) { // Send MIDI_CLOCK to external gears usbMIDI.sendRealTime(MIDI_CLOCK); handle_bpm_led(tick); } void onClockStart() { usbMIDI.sendRealTime(MIDI_START); } void onClockStop() { usbMIDI.sendRealTime(MIDI_STOP); digitalWrite(LED_BUILTIN, LOW); } // External clock handlers void onExternalClock() { uClock.clockMe(); } void onExternalStart() { uClock.start(); } void onExternalStop() { uClock.stop(); } void setup() { // A led to count bpms pinMode(LED_BUILTIN, OUTPUT); // // MIDI setup // usbMIDI.begin(); usbMIDI.setHandleClock(onExternalClock); usbMIDI.setHandleStart(onExternalStart); usbMIDI.setHandleStop(onExternalStop); // // OLED setup // Please check you oled model to correctly init him // u8x8 = new U8X8_SH1106_128X64_NONAME_HW_I2C(U8X8_PIN_NONE); u8x8->begin(); u8x8->setFont(u8x8_font_pressstart2p_r); u8x8->clear(); u8x8->drawUTF8(0, 0, "uClock"); // // uClock Setup // // Setup our clock system // drift for USB Teensy uClock.setDrift(0, 4); uClock.init(); uClock.setClock96PPQNOutput(ClockOut96PPQN); // For MIDI Sync Start and Stop uClock.setOnClockStartOutput(onClockStart); uClock.setOnClockStopOutput(onClockStop); uClock.setMode(uClock.EXTERNAL_CLOCK); // make use of 16us timer to handle midi input sync teensyTimer.begin(handleMidiInput, 16); teensyTimer.priority(80); } void handleMidiInput() { while (usbMIDI.read()) { } } void printBpm(float _bpm, uint8_t col, uint8_t line) { int b = (int)_bpm; int c = (int)((_bpm-b)*10); itoa(b, bpm_str, 10); if (b > 99) { u8x8->drawUTF8(col, line, bpm_str); } else { bpm_str[2] = "\0"; u8x8->drawUTF8(col, line, " "); u8x8->drawUTF8(col+1, line, bpm_str); } u8x8->drawUTF8(col+3, line, "."); itoa(c, bpm_str, 10); u8x8->drawUTF8(col+4, line, bpm_str); u8x8->drawUTF8(col+5, line, "bpm"); } void loop() { if (bpm != uClock.getTempo()) { bpm = uClock.getTempo(); printBpm(bpm, 8, 7); } if (clock_state != uClock.state) { clock_state = uClock.state; if (clock_state >= 1) { u8x8->drawUTF8(0, 7, "playing"); } else { u8x8->drawUTF8(0, 7, "stoped "); } } }