/* USB MIDI Sync Slave Box Monitor * * This example demonstrates how to create a * MIDI slave clock box with * monitor support using oled display * * MIDI in must be provided via an opto-isolator to pin RX/D0 * on an Arduino Uno. * * You need the following libraries to make it work * - Midi Library * - u8g2 * - uClock * This example code is in the public domain. * * Code by midilab contact@midilab.co * Example modified by Jackson Devices contact@jacksondevices.com */ #include #include // // BPM Clock support // #include MIDI_CREATE_DEFAULT_INSTANCE(); U8X8 * u8x8; // 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 float bpm = 126.0; uint8_t bpm_blink_timer = 1; uint8_t clock_state = 1; uint8_t clock_mode = 0; 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 MIDI.sendRealTime(MIDI_CLOCK); handle_bpm_led(tick); } void onClockStart() { MIDI.sendRealTime(MIDI_START); } void onClockStop() { MIDI.sendRealTime(MIDI_STOP); digitalWrite(LED_BUILTIN, LOW); } // External clock handlers void onExternalClock() { uClock.clockMe(); } void onExternalStart() { uClock.start(); } void onExternalStop() { uClock.stop(); digitalWrite(LED_BUILTIN, LOW); } void setup() { // // MIDI setup // // Initiate MIDI communications, listen to all channels, disable soft MIDI thru MIDI.begin(); MIDI.turnThruOff(); MIDI.setHandleClock(onExternalClock); MIDI.setHandleStart(onExternalStart); MIDI.setHandleStop(onExternalStop); // An led to display MIDI reception pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // // OLED setup // Please check you oled model to correctly init him // The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp // //u8x8 = new U8X8_SH1106_128X64_NONAME_HW_I2C(U8X8_PIN_NONE); u8x8 = new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE); u8x8->begin(); u8x8->setFont(u8x8_font_pressstart2p_r); u8x8->clear(); u8x8->setFlipMode(true); u8x8->drawUTF8(0, 0, "uClock"); // // uClock Setup // uClock.init(); uClock.setClock96PPQNOutput(ClockOut96PPQN); // For MIDI Sync Start and Stop uClock.setOnClockStartOutput(onClockStart); uClock.setOnClockStopOutput(onClockStop); uClock.setMode(uClock.EXTERNAL_CLOCK); //uClock.setTempo(136.5); //uClock.start(); } void loop() { while(MIDI.read()) {} // DO NOT ADD MORE PROCESS HERE AT THE COST OF LOSING CLOCK SYNC // Since arduino make use of Serial RX interruption we need to // read Serial as fast as we can on the loop if (bpm != uClock.getTempo()) { bpm = uClock.getTempo(); u8x8->drawUTF8(8, 7, String(bpm, 1).c_str()); u8x8->drawUTF8(8 + 5, 7, "BPM"); // clear display ghost number for 2 digit // coming from 3 digit bpm changes if (bpm < 100) { u8x8->drawUTF8(8 + 4, 7, " "); } } if (clock_state != uClock.state) { clock_state = uClock.state; if (clock_state >= 1) { u8x8->drawUTF8(0, 7, "Playing"); } else { u8x8->drawUTF8(0, 7, "Stopped "); } } if (clock_mode != uClock.getMode()) { clock_mode = uClock.getMode(); if (clock_mode == uClock.EXTERNAL_CLOCK) { u8x8->drawUTF8(10, 0, "Slave "); } else { u8x8->drawUTF8(10, 0, "Master"); } } }