From 91e46961d9b0141403c84d342f3c0c09b28e91e4 Mon Sep 17 00:00:00 2001 From: midilab Date: Tue, 27 Oct 2020 12:05:02 -0400 Subject: [PATCH] Added 2 examples for teensy as USB MIDI clock slave and master --- .../TeensyUsbMasterMidiClock.ino | 76 +++++++++++++++ .../TeensyUsbSlaveMidiClock.ino | 95 +++++++++++++++++++ src/uClock.cpp | 6 +- 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino create mode 100644 examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino diff --git a/examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino b/examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino new file mode 100644 index 0000000..436a8dd --- /dev/null +++ b/examples/TeensyUsbMasterMidiClock/TeensyUsbMasterMidiClock.ino @@ -0,0 +1,76 @@ +/* USB MIDI Sync Box + * + * This example demonstrates how to change the USB MIDI + * device name on Teensy LC and 3.x. When creating more + * that one MIDI device, custom names are much easier to + * use when selecting each device in MIDI software on + * your PC or Mac. The custom name is in the "name.c" tab. + * + * Windows and Macintosh systems often cache USB info. + * After changing the name, you may need to test on a + * different computer to observe the new name, or take + * steps to get your operating system to "forget" the + * cached info. (TODO: wanted... can anyone contribute + * instructions for these systems) + * + * You must select MIDI from the "Tools > USB Type" menu + * + * This example code is in the public domain. + */ + +#include + +uint8_t bpm_blink_timer = 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(usbMIDI.Clock); + handle_bpm_led(tick); +} + +void onClockStart() { + usbMIDI.sendRealTime(usbMIDI.Start); +} + +void onClockStop() { + usbMIDI.sendRealTime(usbMIDI.Stop); +} + +void setup() { + // A led to count bpms + pinMode(LED_BUILTIN, OUTPUT); + + // Setup our clock system + // drift for USB Teensy + uClock.setDrift(1); + // Inits the clock + uClock.init(); + // Set the callback function for the clock output to send MIDI Sync message. + uClock.setClock96PPQNOutput(ClockOut96PPQN); + // Set the callback function for MIDI Start and Stop messages. + uClock.setOnClockStartOutput(onClockStart); + uClock.setOnClockStopOutput(onClockStop); + // Set the clock BPM to 126 BPM + uClock.setTempo(126); + // Starts the clock, tick-tac-tick-tac... + uClock.start(); +} + +// Do it whatever to interface with Clock.stop(), Clock.start(), Clock.setTempo() and integrate your environment... +void loop() { + +} diff --git a/examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino b/examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino new file mode 100644 index 0000000..1fde0b8 --- /dev/null +++ b/examples/TeensyUsbSlaveMidiClock/TeensyUsbSlaveMidiClock.ino @@ -0,0 +1,95 @@ +/* USB MIDI Sync Slave Box + * + * This example demonstrates how to change the USB MIDI + * device name on Teensy LC and 3.x. When creating more + * that one MIDI device, custom names are much easier to + * use when selecting each device in MIDI software on + * your PC or Mac. The custom name is in the "name.c" tab. + * + * Windows and Macintosh systems often cache USB info. + * After changing the name, you may need to test on a + * different computer to observe the new name, or take + * steps to get your operating system to "forget" the + * cached info. (TODO: wanted... can anyone contribute + * instructions for these systems) + * + * You must select MIDI from the "Tools > USB Type" menu + * + * This example code is in the public domain. + */ + +#include + +uint8_t bpm_blink_timer = 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 on other port? + //usbMIDI.sendRealTime(usbMIDI.Clock); + handle_bpm_led(tick); +} + +void onClockStart() { + //usbMIDI.sendRealTime(usbMIDI.Start); +} + +void onClockStop() { + //usbMIDI.sendRealTime(usbMIDI.Stop); +} + +// 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); + + // Setup realtime midi event handlers + usbMIDI.setHandleClock(onExternalClock); + usbMIDI.setHandleStart(onExternalStart); + usbMIDI.setHandleStop(onExternalStop); + + // Setup our clock system + // drift for USB Teensy + uClock.setDrift(1); + // Inits the clock + uClock.init(); + // Set the callback function for the clock output to send MIDI Sync message. + uClock.setClock96PPQNOutput(ClockOut96PPQN); + // Set the callback function for MIDI Start and Stop messages. + uClock.setOnClockStartOutput(onClockStart); + uClock.setOnClockStopOutput(onClockStop); + // set to external sync mode + uClock.setMode(1); +} + +void loop() { + // Grab all midi data as fast as we can! + while (usbMIDI.read()) {} +} diff --git a/src/uClock.cpp b/src/uClock.cpp index 2641dcd..ddeca4b 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -185,7 +185,11 @@ void uClockClass::setTempo(uint16_t bpm) uint16_t uClockClass::getTempo() { if (mode == EXTERNAL_CLOCK) { - tempo = (156250 / interval); + uint16_t external_interval; + ATOMIC( + external_interval = interval; + ) + tempo = (156250 / external_interval); } return tempo; }