From 5dc12a7c1a8707474b6fda3515dee35f2acbdf9b Mon Sep 17 00:00:00 2001 From: doctea Date: Wed, 26 Mar 2025 00:12:12 +0000 Subject: [PATCH 01/21] enable to pause clock and then continue playing from where we left off --- src/uClock.cpp | 15 +++++++++++++-- src/uClock.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 9f27935..0fc802d 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -183,13 +183,24 @@ void uClockClass::stop() } } +void uClockClass::continue_playing() { + if (state == PAUSED) { + start_timer = millis(); + if (mode == INTERNAL_CLOCK) { + state = STARTED; + } else { + state = STARTING; + } + } +} + void uClockClass::pause() { if (mode == INTERNAL_CLOCK) { if (state == PAUSED) { - start(); + continue_playing(); } else { - stop(); + state = PAUSED; } } } diff --git a/src/uClock.h b/src/uClock.h index df1a08d..e7bfd49 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -127,6 +127,7 @@ class uClockClass { void start(); void stop(); void pause(); + void continue_playing(); void setTempo(float bpm); float getTempo(); From 88e108657a724f4caee85341be2e901e88e13884 Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Fri, 11 Apr 2025 23:47:02 +0100 Subject: [PATCH 02/21] (untested) add user callbacks for 'pause' and 'continue' --- src/uClock.cpp | 6 ++++++ src/uClock.h | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/uClock.cpp b/src/uClock.cpp index 0fc802d..ee8f114 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -191,6 +191,9 @@ void uClockClass::continue_playing() { } else { state = STARTING; } + if (onClockContinueCallback) { + onClockContinueCallback(); + } } } @@ -201,6 +204,9 @@ void uClockClass::pause() continue_playing(); } else { state = PAUSED; + if (onClockPauseCallback) { + onClockPauseCallback(); + } } } } diff --git a/src/uClock.h b/src/uClock.h index e7bfd49..5323035 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -116,6 +116,14 @@ class uClockClass { onClockStopCallback = callback; } + void setOnClockContinue(void (*callback)()) { + onClockStartCallback = callback; + } + + void setOnClockPause(void (*callback)()) { + onClockPauseCallback = callback; + } + void init(); void setPPQN(PPQNResolution resolution); @@ -172,6 +180,8 @@ class uClockClass { void (*onSync24Callback)(uint32_t tick); void (*onClockStartCallback)(); void (*onClockStopCallback)(); + void (*onClockContinueCallback)(); + void (*onClockPauseCallback)(); // internal clock control // uint16_t ppqn; From f54c47df4719425d9f957f20cc1ad837a3a9947a Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Mon, 14 Jul 2025 22:28:33 +0100 Subject: [PATCH 03/21] seems to work..? --- src/uClock.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index f0fa23d..e1dfd4c 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -198,8 +198,10 @@ void uClockClass::start() } if (clock_mode == INTERNAL_CLOCK) { + Serial.printf("uClockClass::start(): uClock setting STARTED\n"); clock_state = STARTED; } else { + Serial.printf("uClockClass::start(): uClock setting STARTING\n"); clock_state = STARTING; } } @@ -220,6 +222,7 @@ void uClockClass::continue_playing() { if (clock_mode == INTERNAL_CLOCK) { clock_state = STARTED; } else { + Serial.printf("uClockClass::continue_playing(): uClock setting STARTING\n"); clock_state = STARTING; } if (onClockContinueCallback) { @@ -309,11 +312,7 @@ uClockClass::ClockMode uClockClass::getClockMode() void uClockClass::clockMe() { - if (clock_mode == EXTERNAL_CLOCK) { - ATOMIC( - handleExternalClock() - ) - } + ATOMIC(handleExternalClock()) } void uClockClass::setExtIntervalBuffer(uint8_t buffer_size) @@ -458,6 +457,7 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = STARTED; ext_clock_us = micros(); + Serial.printf("handleExternalClock: uClock is STARTING at ext_clock_tick\t%u with ext_clock_us = %u\n", ext_clock_tick, ext_clock_us); break; case STARTED: @@ -475,9 +475,11 @@ void uClockClass::handleExternalClock() ext_interval_buffer[ext_interval_idx] = last_interval; if (ext_clock_tick == 1) { + Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval to last_interval\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); ext_interval = last_interval; } else { ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; + Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval from PLL\t\t\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); } break; } @@ -514,8 +516,13 @@ void uClockClass::handleTimerInt() } // update internal clock timer frequency - float bpm = constrainBpm(freqToBpm(counter)); - if (bpm != tempo) { + //if (ext_clock_tick > 20) { + if (ext_interval > 0) { + float bpm = constrainBpm(freqToBpm(counter)); + if (Serial) { + Serial.printf("uClock: External clock tick %u, counter %u, ext_interval %u, so is detected as BPM %f\n", ext_clock_tick, counter, ext_interval, bpm); + Serial.flush(); + } tempo = bpm; setTimerTempo(bpm); } From ffe556aa790c1b3aa56f5b515eac61fd6ca02ecc Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Mon, 14 Jul 2025 22:58:04 +0100 Subject: [PATCH 04/21] tidy up debug stuff a bit --- src/platforms/rp2040.h | 4 ++++ src/uClock.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/platforms/rp2040.h b/src/platforms/rp2040.h index eb918c2..fd7a8c9 100644 --- a/src/platforms/rp2040.h +++ b/src/platforms/rp2040.h @@ -24,6 +24,10 @@ void initTimer(uint32_t init_clock) { } void setTimer(uint32_t us_interval) { + if (Serial) { + Serial.printf("setTimer(): Setting uClock timer interval to %u us\n", us_interval); + Serial.flush(); + } cancel_repeating_timer(&timer); // todo: actually should be -us_interval so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! add_repeating_timer_us(us_interval, &handlerISR, NULL, &timer); diff --git a/src/uClock.cpp b/src/uClock.cpp index e1dfd4c..1690148 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -198,7 +198,7 @@ void uClockClass::start() } if (clock_mode == INTERNAL_CLOCK) { - Serial.printf("uClockClass::start(): uClock setting STARTED\n"); + if (Serial) Serial.printf("uClockClass::start(): uClock setting STARTED\n"); clock_state = STARTED; } else { Serial.printf("uClockClass::start(): uClock setting STARTING\n"); @@ -457,7 +457,7 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = STARTED; ext_clock_us = micros(); - Serial.printf("handleExternalClock: uClock is STARTING at ext_clock_tick\t%u with ext_clock_us = %u\n", ext_clock_tick, ext_clock_us); + if (Serial) Serial.printf("handleExternalClock: uClock is STARTING at ext_clock_tick\t%u with ext_clock_us = %u\n", ext_clock_tick, ext_clock_us); break; case STARTED: @@ -475,11 +475,11 @@ void uClockClass::handleExternalClock() ext_interval_buffer[ext_interval_idx] = last_interval; if (ext_clock_tick == 1) { - Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval to last_interval\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); + if (Serial) Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval to last_interval\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); ext_interval = last_interval; } else { ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; - Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval from PLL\t\t\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); + if (Serial) Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval from PLL\t\t\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); } break; } From 684c128d0d599d7ca3ac43ec0e5b15bb858d1d76 Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Mon, 14 Jul 2025 22:59:47 +0100 Subject: [PATCH 05/21] remove debug --- src/platforms/rp2040.h | 1 - src/uClock.cpp | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/src/platforms/rp2040.h b/src/platforms/rp2040.h index fd7a8c9..16a35ae 100644 --- a/src/platforms/rp2040.h +++ b/src/platforms/rp2040.h @@ -25,7 +25,6 @@ void initTimer(uint32_t init_clock) { void setTimer(uint32_t us_interval) { if (Serial) { - Serial.printf("setTimer(): Setting uClock timer interval to %u us\n", us_interval); Serial.flush(); } cancel_repeating_timer(&timer); diff --git a/src/uClock.cpp b/src/uClock.cpp index 1690148..77bbec1 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -198,10 +198,8 @@ void uClockClass::start() } if (clock_mode == INTERNAL_CLOCK) { - if (Serial) Serial.printf("uClockClass::start(): uClock setting STARTED\n"); clock_state = STARTED; } else { - Serial.printf("uClockClass::start(): uClock setting STARTING\n"); clock_state = STARTING; } } @@ -222,7 +220,6 @@ void uClockClass::continue_playing() { if (clock_mode == INTERNAL_CLOCK) { clock_state = STARTED; } else { - Serial.printf("uClockClass::continue_playing(): uClock setting STARTING\n"); clock_state = STARTING; } if (onClockContinueCallback) { @@ -457,7 +454,6 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = STARTED; ext_clock_us = micros(); - if (Serial) Serial.printf("handleExternalClock: uClock is STARTING at ext_clock_tick\t%u with ext_clock_us = %u\n", ext_clock_tick, ext_clock_us); break; case STARTED: @@ -475,11 +471,9 @@ void uClockClass::handleExternalClock() ext_interval_buffer[ext_interval_idx] = last_interval; if (ext_clock_tick == 1) { - if (Serial) Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval to last_interval\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); ext_interval = last_interval; } else { ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; - if (Serial) Serial.printf("handleExternalClock: uClock is STARTED at ext_clock_tick\t%u with ext_clock_us = %u, setting ext_interval from PLL\t\t\t%u us\n", ext_clock_tick, ext_clock_us, last_interval); } break; } @@ -516,13 +510,8 @@ void uClockClass::handleTimerInt() } // update internal clock timer frequency - //if (ext_clock_tick > 20) { if (ext_interval > 0) { float bpm = constrainBpm(freqToBpm(counter)); - if (Serial) { - Serial.printf("uClock: External clock tick %u, counter %u, ext_interval %u, so is detected as BPM %f\n", ext_clock_tick, counter, ext_interval, bpm); - Serial.flush(); - } tempo = bpm; setTimerTempo(bpm); } From 101bdfeaaee83b11d6f1cbbe9c7393c0a32fc23e Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Tue, 15 Jul 2025 22:02:36 +0100 Subject: [PATCH 06/21] believe external pause/continue to be fixed --- src/uClock.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 77bbec1..563c9b4 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -215,6 +215,7 @@ void uClockClass::stop() } void uClockClass::continue_playing() { + // todo: if not paused, should we start anyway? if (clock_state == PAUSED) { start_timer = millis(); if (clock_mode == INTERNAL_CLOCK) { @@ -230,15 +231,9 @@ void uClockClass::continue_playing() { void uClockClass::pause() { - if (clock_mode == INTERNAL_CLOCK) { - if (clock_state == PAUSED) { - start(); - } else { - clock_state = PAUSED; - if (onClockPauseCallback) { - onClockPauseCallback(); - } - } + clock_state = PAUSED; + if (onClockPauseCallback) { + onClockPauseCallback(); } } From 283ef717449a84a65f19efdcfe945c9cb2c00f1f Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Tue, 15 Jul 2025 22:03:24 +0100 Subject: [PATCH 07/21] remove unneeded code --- src/platforms/rp2040.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/platforms/rp2040.h b/src/platforms/rp2040.h index 16a35ae..eb918c2 100644 --- a/src/platforms/rp2040.h +++ b/src/platforms/rp2040.h @@ -24,9 +24,6 @@ void initTimer(uint32_t init_clock) { } void setTimer(uint32_t us_interval) { - if (Serial) { - Serial.flush(); - } cancel_repeating_timer(&timer); // todo: actually should be -us_interval so that timer is set to start init_clock us after last tick, instead of init_clock us after finished processing last tick! add_repeating_timer_us(us_interval, &handlerISR, NULL, &timer); From aa943fb711c77f99ef5720a4e95a7bf22ea194a0 Mon Sep 17 00:00:00 2001 From: midilab Date: Thu, 24 Jul 2025 08:19:49 -0300 Subject: [PATCH 08/21] review pause+continue feature --- src/uClock.cpp | 481 ++++++++++++++++++++++++------------------------- src/uClock.h | 18 +- 2 files changed, 248 insertions(+), 251 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 563c9b4..98f557d 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -140,6 +140,11 @@ uClockClass::uClockClass() calculateReferencedata(); } +uClockClass::~uClockClass() +{ + delete[] ext_interval_buffer; +} + void uClockClass::init() { if (ext_interval_buffer == nullptr) @@ -150,42 +155,186 @@ void uClockClass::init() setTempo(tempo); } -uint32_t uClockClass::bpmToMicroSeconds(float bpm) +void uClockClass::handleInternalClock() { - return (60000000.0f / (float)output_ppqn / bpm); -} + // track main input clock counter + if (mod_clock_counter == mod_clock_ref) + mod_clock_counter = 0; -void uClockClass::calculateReferencedata() -{ - mod_clock_ref = output_ppqn / input_ppqn; - mod_sync1_ref = output_ppqn / PPQN_1; - mod_sync2_ref = output_ppqn / PPQN_2; - mod_sync4_ref = output_ppqn / PPQN_4; - mod_sync8_ref = output_ppqn / PPQN_8; - mod_sync12_ref = output_ppqn / PPQN_12; - mod_sync24_ref = output_ppqn / PPQN_24; - mod_sync48_ref = output_ppqn / PPQN_48; - mod_step_ref = output_ppqn / 4; + // process sync signals first please... + if (mod_clock_counter == 0) { + + if (clock_mode == EXTERNAL_CLOCK) { + // sync tick position with external tick clock + if ((int_clock_tick < ext_clock_tick) || (int_clock_tick > (ext_clock_tick + 1))) { + int_clock_tick = ext_clock_tick; + tick = int_clock_tick * mod_clock_ref; + mod_clock_counter = tick % mod_clock_ref; + mod_step_counter = tick % mod_step_ref; + } + + uint32_t counter = ext_interval; + uint32_t now_clock_us = micros(); + sync_interval = clock_diff(ext_clock_us, now_clock_us); + + if (int_clock_tick <= ext_clock_tick) { + counter -= phase_mult(sync_interval); + } else { + if (counter > sync_interval) { + counter += phase_mult(counter - sync_interval); + } + } + + // update internal clock timer frequency + float bpm = constrainBpm(freqToBpm(counter)); + if (bpm != tempo) { + tempo = bpm; + setTimerTempo(bpm); + } + } + + // internal clock tick me! + ++int_clock_tick; + } + ++mod_clock_counter; + + // ALL OUTPUT SYNC CALLBACKS + // Sync1 callback + if (onSync1Callback) { + if (mod_sync1_counter == mod_sync1_ref) + mod_sync1_counter = 0; + if (mod_sync1_counter == 0) { + onSync1Callback(sync1_tick); + ++sync1_tick; + } + ++mod_sync1_counter; + } + + // Sync2 callback + if (onSync2Callback) { + if (mod_sync2_counter == mod_sync2_ref) + mod_sync2_counter = 0; + if (mod_sync2_counter == 0) { + onSync2Callback(sync2_tick); + ++sync2_tick; + } + ++mod_sync2_counter; + } + + // Sync4 callback + if (onSync4Callback) { + if (mod_sync4_counter == mod_sync4_ref) + mod_sync4_counter = 0; + if (mod_sync4_counter == 0) { + onSync4Callback(sync4_tick); + ++sync4_tick; + } + ++mod_sync4_counter; + } + + // Sync8 callback + if (onSync8Callback) { + if (mod_sync8_counter == mod_sync8_ref) + mod_sync8_counter = 0; + if (mod_sync8_counter == 0) { + onSync8Callback(sync8_tick); + ++sync8_tick; + } + ++mod_sync8_counter; + } + + // Sync12 callback + if (onSync12Callback) { + if (mod_sync12_counter == mod_sync12_ref) + mod_sync12_counter = 0; + if (mod_sync12_counter == 0) { + onSync12Callback(sync12_tick); + ++sync12_tick; + } + ++mod_sync12_counter; + } + + // Sync24 callback + if (onSync24Callback) { + if (mod_sync24_counter == mod_sync24_ref) + mod_sync24_counter = 0; + if (mod_sync24_counter == 0) { + onSync24Callback(sync24_tick); + ++sync24_tick; + } + ++mod_sync24_counter; + } + + // Sync48 callback + if (onSync48Callback) { + if (mod_sync48_counter == mod_sync48_ref) + mod_sync48_counter = 0; + if (mod_sync48_counter == 0) { + onSync48Callback(sync48_tick); + ++sync48_tick; + } + ++mod_sync48_counter; + } + + // main PPQNCallback + if (onOutputPPQNCallback) { + onOutputPPQNCallback(tick); + ++tick; + } + + // step callback to support 16th old school style sequencers + // with builtin shuffle for this callback only + if (onStepCallback) { + if (mod_step_counter == mod_step_ref) + mod_step_counter = 0; + // processShufle make use of mod_step_counter == 0 logic too + if (processShuffle()) { + onStepCallback(step_counter); + // going forward to the next step call + ++step_counter; + } + ++mod_step_counter; + } } -void uClockClass::setOutputPPQN(PPQNResolution resolution) +void uClockClass::handleExternalClock() { - // dont allow PPQN lower than PPQN_4 for output clock (to avoid problems with mod_step_ref) - if (resolution < PPQN_4) - return; + switch (clock_state) { + case PAUSED: + break; - ATOMIC( - output_ppqn = resolution; - calculateReferencedata(); - ) + case STARTING: + clock_state = STARTED; + ext_clock_us = micros(); + break; + + case STARTED: + uint32_t now_clock_us = micros(); + last_interval = clock_diff(ext_clock_us, now_clock_us); + ext_clock_us = now_clock_us; + + // external clock tick me! + ext_clock_tick++; + + // accumulate interval incomming ticks data for getTempo() smooth reads on slave clock_mode + if(++ext_interval_idx >= ext_interval_buffer_size) { + ext_interval_idx = 0; + } + ext_interval_buffer[ext_interval_idx] = last_interval; + + if (ext_clock_tick == 1) { + ext_interval = last_interval; + } else { + ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; + } + break; + } } -void uClockClass::setInputPPQN(PPQNResolution resolution) +void uClockClass::clockMe() { - ATOMIC( - input_ppqn = resolution; - calculateReferencedata(); - ) + if (clock_mode == EXTERNAL_CLOCK) + ATOMIC(handleExternalClock()) } void uClockClass::start() @@ -198,43 +347,85 @@ void uClockClass::start() } if (clock_mode == INTERNAL_CLOCK) { - clock_state = STARTED; + ATOMIC(clock_state = STARTED) } else { - clock_state = STARTING; + ATOMIC(clock_state = STARTING) } } void uClockClass::stop() { - clock_state = PAUSED; - start_timer = 0; + ATOMIC(clock_state = PAUSED) resetCounters(); + start_timer = 0; if (onClockStopCallback) { onClockStopCallback(); } } -void uClockClass::continue_playing() { - // todo: if not paused, should we start anyway? +void uClockClass::pause() +{ if (clock_state == PAUSED) { - start_timer = millis(); if (clock_mode == INTERNAL_CLOCK) { - clock_state = STARTED; - } else { - clock_state = STARTING; - } - if (onClockContinueCallback) { - onClockContinueCallback(); + ATOMIC(clock_state = STARTED) + } else if (clock_mode == EXTERNAL_CLOCK) { + ATOMIC(clock_state = STARTING) } + } else { + ATOMIC(clock_state = PAUSED) } } -void uClockClass::pause() +void uClockClass::setClockMode(ClockMode tempo_mode) { - clock_state = PAUSED; - if (onClockPauseCallback) { - onClockPauseCallback(); + if (tempo_mode == EXTERNAL_CLOCK && clock_state == STARTED) { + // trying to set external clock while playing? force sync last clock tick + ATOMIC(clock_state = STARTING) } + ATOMIC(clock_mode = tempo_mode) +} + +uClockClass::ClockMode uClockClass::getClockMode() +{ + return clock_mode; +} + +uint32_t uClockClass::bpmToMicroSeconds(float bpm) +{ + return (60000000.0f / (float)output_ppqn / bpm); +} + +void uClockClass::calculateReferencedata() +{ + mod_clock_ref = output_ppqn / input_ppqn; + mod_sync1_ref = output_ppqn / PPQN_1; + mod_sync2_ref = output_ppqn / PPQN_2; + mod_sync4_ref = output_ppqn / PPQN_4; + mod_sync8_ref = output_ppqn / PPQN_8; + mod_sync12_ref = output_ppqn / PPQN_12; + mod_sync24_ref = output_ppqn / PPQN_24; + mod_sync48_ref = output_ppqn / PPQN_48; + mod_step_ref = output_ppqn / 4; +} + +void uClockClass::setOutputPPQN(PPQNResolution resolution) +{ + // dont allow PPQN lower than PPQN_4 for output clock (to avoid problems with mod_step_ref) + if (resolution < PPQN_4) + return; + + ATOMIC( + output_ppqn = resolution; + calculateReferencedata(); + ) +} + +void uClockClass::setInputPPQN(PPQNResolution resolution) +{ + ATOMIC( + input_ppqn = resolution; + calculateReferencedata(); + ) } void uClockClass::setTempo(float bpm) @@ -247,9 +438,7 @@ void uClockClass::setTempo(float bpm) return; } - ATOMIC( - tempo = bpm - ) + ATOMIC(tempo = bpm) setTimerTempo(bpm); } @@ -292,21 +481,6 @@ float inline uClockClass::constrainBpm(float bpm) return (bpm < MIN_BPM) ? MIN_BPM : ( bpm > MAX_BPM ? MAX_BPM : bpm ); } -void uClockClass::setClockMode(ClockMode tempo_mode) -{ - clock_mode = tempo_mode; -} - -uClockClass::ClockMode uClockClass::getClockMode() -{ - return clock_mode; -} - -void uClockClass::clockMe() -{ - ATOMIC(handleExternalClock()) -} - void uClockClass::setExtIntervalBuffer(uint8_t buffer_size) { if (ext_interval_buffer != nullptr) @@ -314,7 +488,7 @@ void uClockClass::setExtIntervalBuffer(uint8_t buffer_size) // alloc once and forever policy ext_interval_buffer_size = buffer_size; - ext_interval_buffer = (uint32_t*) malloc( sizeof(uint32_t) * ext_interval_buffer_size ); + ext_interval_buffer = new uint32_t[ext_interval_buffer_size]; } void uClockClass::resetCounters() @@ -440,182 +614,6 @@ bool inline uClockClass::processShuffle() return false; } -void uClockClass::handleExternalClock() -{ - switch (clock_state) { - case PAUSED: - break; - - case STARTING: - clock_state = STARTED; - ext_clock_us = micros(); - break; - - case STARTED: - uint32_t now_clock_us = micros(); - last_interval = clock_diff(ext_clock_us, now_clock_us); - ext_clock_us = now_clock_us; - - // external clock tick me! - ext_clock_tick++; - - // accumulate interval incomming ticks data for getTempo() smooth reads on slave clock_mode - if(++ext_interval_idx >= ext_interval_buffer_size) { - ext_interval_idx = 0; - } - ext_interval_buffer[ext_interval_idx] = last_interval; - - if (ext_clock_tick == 1) { - ext_interval = last_interval; - } else { - ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; - } - break; - } -} - -void uClockClass::handleTimerInt() -{ - // track main input clock counter - if (mod_clock_counter == mod_clock_ref) - mod_clock_counter = 0; - - // process sync signals first please... - if (mod_clock_counter == 0) { - - if (clock_mode == EXTERNAL_CLOCK) { - // sync tick position with external tick clock - if ((int_clock_tick < ext_clock_tick) || (int_clock_tick > (ext_clock_tick + 1))) { - int_clock_tick = ext_clock_tick; - tick = int_clock_tick * mod_clock_ref; - mod_clock_counter = tick % mod_clock_ref; - mod_step_counter = tick % mod_step_ref; - } - - uint32_t counter = ext_interval; - uint32_t now_clock_us = micros(); - sync_interval = clock_diff(ext_clock_us, now_clock_us); - - if (int_clock_tick <= ext_clock_tick) { - counter -= phase_mult(sync_interval); - } else { - if (counter > sync_interval) { - counter += phase_mult(counter - sync_interval); - } - } - - // update internal clock timer frequency - if (ext_interval > 0) { - float bpm = constrainBpm(freqToBpm(counter)); - tempo = bpm; - setTimerTempo(bpm); - } - } - - // internal clock tick me! - ++int_clock_tick; - } - ++mod_clock_counter; - - // ALL OUTPUT SYNC CALLBACKS - // Sync1 callback - if (onSync1Callback) { - if (mod_sync1_counter == mod_sync1_ref) - mod_sync1_counter = 0; - if (mod_sync1_counter == 0) { - onSync1Callback(sync1_tick); - ++sync1_tick; - } - ++mod_sync1_counter; - } - - // Sync2 callback - if (onSync2Callback) { - if (mod_sync2_counter == mod_sync2_ref) - mod_sync2_counter = 0; - if (mod_sync2_counter == 0) { - onSync2Callback(sync2_tick); - ++sync2_tick; - } - ++mod_sync2_counter; - } - - // Sync4 callback - if (onSync4Callback) { - if (mod_sync4_counter == mod_sync4_ref) - mod_sync4_counter = 0; - if (mod_sync4_counter == 0) { - onSync4Callback(sync4_tick); - ++sync4_tick; - } - ++mod_sync4_counter; - } - - // Sync8 callback - if (onSync8Callback) { - if (mod_sync8_counter == mod_sync8_ref) - mod_sync8_counter = 0; - if (mod_sync8_counter == 0) { - onSync8Callback(sync8_tick); - ++sync8_tick; - } - ++mod_sync8_counter; - } - - // Sync12 callback - if (onSync12Callback) { - if (mod_sync12_counter == mod_sync12_ref) - mod_sync12_counter = 0; - if (mod_sync12_counter == 0) { - onSync12Callback(sync12_tick); - ++sync12_tick; - } - ++mod_sync12_counter; - } - - // Sync24 callback - if (onSync24Callback) { - if (mod_sync24_counter == mod_sync24_ref) - mod_sync24_counter = 0; - if (mod_sync24_counter == 0) { - onSync24Callback(sync24_tick); - ++sync24_tick; - } - ++mod_sync24_counter; - } - - // Sync48 callback - if (onSync48Callback) { - if (mod_sync48_counter == mod_sync48_ref) - mod_sync48_counter = 0; - if (mod_sync48_counter == 0) { - onSync48Callback(sync48_tick); - ++sync48_tick; - } - ++mod_sync48_counter; - } - - // main PPQNCallback - if (onOutputPPQNCallback) { - onOutputPPQNCallback(tick); - ++tick; - } - - // step callback to support 16th old school style sequencers - // with builtin shuffle for this callback only - if (onStepCallback) { - if (mod_step_counter == mod_step_ref) - mod_step_counter = 0; - // processShufle make use of mod_step_counter == 0 logic too - if (processShuffle()) { - onStepCallback(step_counter); - // going forward to the next step call - ++step_counter; - } - ++mod_step_counter; - } -} - // elapsed time support uint8_t uClockClass::getNumberOfSeconds(uint32_t time) { @@ -673,7 +671,6 @@ void uClockHandler() // global timer counter _millis = millis(); - if (uClock.clock_state == uClock.STARTED) { - uClock.handleTimerInt(); - } + if (uClock.clock_state == uClock.STARTED) + uClock.handleInternalClock(); } diff --git a/src/uClock.h b/src/uClock.h index 69ead1a..aa933c7 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -86,6 +86,7 @@ class uClockClass { ClockState clock_state; uClockClass(); + ~uClockClass(); void setOnOutputPPQN(void (*callback)(uint32_t tick)) { onOutputPPQNCallback = callback; @@ -132,19 +133,19 @@ class uClockClass { onClockStopCallback = callback; } - void setOnClockContinue(void (*callback)()) { - onClockStartCallback = callback; - } - void setOnClockPause(void (*callback)()) { onClockPauseCallback = callback; } + void setOnClockContinue(void (*callback)()) { + onClockContinueCallback = callback; + } + void init(); void setOutputPPQN(PPQNResolution resolution); void setInputPPQN(PPQNResolution resolution); - void handleTimerInt(); + void handleInternalClock(); void handleExternalClock(); void resetCounters(); @@ -152,7 +153,6 @@ class uClockClass { void start(); void stop(); void pause(); - void continue_playing(); void setTempo(float bpm); float getTempo(); @@ -210,8 +210,8 @@ class uClockClass { void (*onSync48Callback)(uint32_t tick); void (*onClockStartCallback)(); void (*onClockStopCallback)(); - void (*onClockContinueCallback)(); void (*onClockPauseCallback)(); + void (*onClockContinueCallback)(); // clock input/output control PPQNResolution output_ppqn = PPQN_96; @@ -253,9 +253,9 @@ class uClockClass { uint32_t last_interval; uint32_t sync_interval; - float tempo; + volatile float tempo; + volatile ClockMode clock_mode; uint32_t start_timer; - ClockMode clock_mode; volatile uint32_t * ext_interval_buffer = nullptr; uint8_t ext_interval_buffer_size; From 07e291ec9da7c9bf93b9fb68a3a65bfa19697da7 Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 07:43:37 -0300 Subject: [PATCH 09/21] adding SYNCING clock_state for external sync --- src/uClock.cpp | 7 ++++++- src/uClock.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 98f557d..70eb03a 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -304,10 +304,15 @@ void uClockClass::handleExternalClock() break; case STARTING: - clock_state = STARTED; + clock_state = SYNCING; ext_clock_us = micros(); break; + case SYNCING: + // set clock_mode as start and goes on to calculate the first ext_interval + clock_state = STARTED; + // no break here just go on to calculate our first ext_interval + case STARTED: uint32_t now_clock_us = micros(); last_interval = clock_diff(ext_clock_us, now_clock_us); diff --git a/src/uClock.h b/src/uClock.h index aa933c7..e9d4f31 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -66,6 +66,7 @@ class uClockClass { enum ClockState { PAUSED = 0, STARTING, + SYNCING, STARTED }; From 7c8d8c5eb94973e27e2b8a0881a9f837a4798cba Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 07:46:57 -0300 Subject: [PATCH 10/21] place onClockPauseCallback and onClockContinueCallback callbacks correctly --- src/uClock.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 70eb03a..c1ca9da 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -309,7 +309,7 @@ void uClockClass::handleExternalClock() break; case SYNCING: - // set clock_mode as start and goes on to calculate the first ext_interval + // set clock_mode as started and goes on to calculate the first ext_interval clock_state = STARTED; // no break here just go on to calculate our first ext_interval @@ -376,8 +376,12 @@ void uClockClass::pause() } else if (clock_mode == EXTERNAL_CLOCK) { ATOMIC(clock_state = STARTING) } + if (onClockContinueCallback) + onClockContinueCallback(); } else { ATOMIC(clock_state = PAUSED) + if (onClockPauseCallback) + onClockPauseCallback(); } } From b4fff7bebf228b82c469a5958dda3b6553d7bd5f Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 07:54:05 -0300 Subject: [PATCH 11/21] cosmetic code changes --- src/uClock.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index c1ca9da..45924d3 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -347,9 +347,8 @@ void uClockClass::start() resetCounters(); start_timer = millis(); - if (onClockStartCallback) { + if (onClockStartCallback) onClockStartCallback(); - } if (clock_mode == INTERNAL_CLOCK) { ATOMIC(clock_state = STARTED) @@ -363,9 +362,8 @@ void uClockClass::stop() ATOMIC(clock_state = PAUSED) resetCounters(); start_timer = 0; - if (onClockStopCallback) { + if (onClockStopCallback) onClockStopCallback(); - } } void uClockClass::pause() @@ -387,10 +385,10 @@ void uClockClass::pause() void uClockClass::setClockMode(ClockMode tempo_mode) { - if (tempo_mode == EXTERNAL_CLOCK && clock_state == STARTED) { - // trying to set external clock while playing? force sync last clock tick + // trying to set external clock while playing? force sync ext_interval + if (tempo_mode == EXTERNAL_CLOCK && clock_state == STARTED) ATOMIC(clock_state = STARTING) - } + ATOMIC(clock_mode = tempo_mode) } From 2d7f0c5e700f58b3f19072aca54b1abe38e8c3f3 Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 07:57:08 -0300 Subject: [PATCH 12/21] prioritizing most called clock state handlers for external sync inside switch case --- src/uClock.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 45924d3..7e0ade6 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -300,14 +300,6 @@ void uClockClass::handleInternalClock() void uClockClass::handleExternalClock() { switch (clock_state) { - case PAUSED: - break; - - case STARTING: - clock_state = SYNCING; - ext_clock_us = micros(); - break; - case SYNCING: // set clock_mode as started and goes on to calculate the first ext_interval clock_state = STARTED; @@ -333,6 +325,14 @@ void uClockClass::handleExternalClock() ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; } break; + + case PAUSED: + break; + + case STARTING: + clock_state = SYNCING; + ext_clock_us = micros(); + break; } } From 1a81905346339242f8bce29df633a1bb27719a69 Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 08:06:01 -0300 Subject: [PATCH 13/21] safely initialize onClockPauseCallback and onClockContinueCallback at constructor --- src/uClock.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 7e0ade6..1589e5e 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -81,7 +81,6 @@ #include "platforms/software.h" #endif - // // Platform specific timer setup/control // @@ -136,6 +135,8 @@ uClockClass::uClockClass() onStepCallback = nullptr; onClockStartCallback = nullptr; onClockStopCallback = nullptr; + onClockPauseCallback = nullptr; + onClockContinueCallback = nullptr; // initialize reference data calculateReferencedata(); } @@ -301,9 +302,9 @@ void uClockClass::handleExternalClock() { switch (clock_state) { case SYNCING: - // set clock_mode as started and goes on to calculate the first ext_interval + // set clock_mode as started, and goes on to calculate the first ext_interval clock_state = STARTED; - // no break here just go on to calculate our first ext_interval + // no break here, just go on to calculate our first ext_interval case STARTED: uint32_t now_clock_us = micros(); From 85421c87c5107dcc4f8d64bd64fadb47ce7bdc3a Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 08:13:26 -0300 Subject: [PATCH 14/21] fix missing external clock tick for first sync signal --- src/uClock.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 1589e5e..2e56fa2 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -320,11 +320,8 @@ void uClockClass::handleExternalClock() } ext_interval_buffer[ext_interval_idx] = last_interval; - if (ext_clock_tick == 1) { - ext_interval = last_interval; - } else { - ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; - } + // calculate sync interval + ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; break; case PAUSED: @@ -333,6 +330,8 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = SYNCING; ext_clock_us = micros(); + // external clock tick me! + ext_clock_tick++; break; } } From 45d7963855804393139cf916f61ea5d27a3eaf65 Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 08:22:23 -0300 Subject: [PATCH 15/21] set clockMe() to always handle external. not clock_mode EXTERNAL based anymore --- src/uClock.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 2e56fa2..573d288 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -311,17 +311,16 @@ void uClockClass::handleExternalClock() last_interval = clock_diff(ext_clock_us, now_clock_us); ext_clock_us = now_clock_us; - // external clock tick me! - ext_clock_tick++; - // accumulate interval incomming ticks data for getTempo() smooth reads on slave clock_mode - if(++ext_interval_idx >= ext_interval_buffer_size) { + if(++ext_interval_idx >= ext_interval_buffer_size) ext_interval_idx = 0; - } ext_interval_buffer[ext_interval_idx] = last_interval; // calculate sync interval ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; + + // external clock tick me! + ext_clock_tick++; break; case PAUSED: @@ -330,6 +329,7 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = SYNCING; ext_clock_us = micros(); + // external clock tick me! ext_clock_tick++; break; @@ -338,8 +338,7 @@ void uClockClass::handleExternalClock() void uClockClass::clockMe() { - if (clock_mode == EXTERNAL_CLOCK) - ATOMIC(handleExternalClock()) + ATOMIC(handleExternalClock()) } void uClockClass::start() From 519e5fd9c5c1289052479c285acaad55d7fa7721 Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 08:27:05 -0300 Subject: [PATCH 16/21] revert fix missing external clock tick for first sync signal. it shuold be tick 0 --- src/uClock.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 573d288..e3ea81b 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -329,9 +329,7 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = SYNCING; ext_clock_us = micros(); - - // external clock tick me! - ext_clock_tick++; + // should we force internal tick process based on this first tick? break; } } From a935514a7f8a644840116ccdc5ecbfefd603eb79 Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 08:29:59 -0300 Subject: [PATCH 17/21] revert second tick calculus for external sync --- src/uClock.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index e3ea81b..1d96abd 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -316,11 +316,15 @@ void uClockClass::handleExternalClock() ext_interval_idx = 0; ext_interval_buffer[ext_interval_idx] = last_interval; - // calculate sync interval - ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; - // external clock tick me! ext_clock_tick++; + + // calculate sync interval + if (ext_clock_tick == 1) { + ext_interval = last_interval; + } else { + ext_interval = (((uint32_t)ext_interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; + } break; case PAUSED: From 6fcf2fe09b6bd8936c93aaa5693309d596f86a6d Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 08:35:22 -0300 Subject: [PATCH 18/21] force handleInternalCLock at first external tick in case EXTERNAL clock mode is setup --- src/uClock.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 1d96abd..eca3634 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -165,7 +165,7 @@ void uClockClass::handleInternalClock() // process sync signals first please... if (mod_clock_counter == 0) { - if (clock_mode == EXTERNAL_CLOCK) { + if (clock_mode == EXTERNAL_CLOCK && clock_state == STARTED) { // sync tick position with external tick clock if ((int_clock_tick < ext_clock_tick) || (int_clock_tick > (ext_clock_tick + 1))) { int_clock_tick = ext_clock_tick; @@ -333,7 +333,8 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = SYNCING; ext_clock_us = micros(); - // should we force internal tick process based on this first tick? + // force first internal tick processing + handleInternalClock(); break; } } From b85737535a3e887cae25ede5ab646799f46d1e5e Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 09:08:48 -0300 Subject: [PATCH 19/21] revert force first internal tick processing since its too dangerous, instead start internal clock at SYNCING state --- src/uClock.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index eca3634..ae50591 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -333,8 +333,6 @@ void uClockClass::handleExternalClock() case STARTING: clock_state = SYNCING; ext_clock_us = micros(); - // force first internal tick processing - handleInternalClock(); break; } } @@ -680,6 +678,6 @@ void uClockHandler() // global timer counter _millis = millis(); - if (uClock.clock_state == uClock.STARTED) + if (uClock.clock_state == uClock.STARTED || uClock.clock_state == uClock.SYNCING) uClock.handleInternalClock(); } From 23ba2c90f53b74199bf5d37b7e05d55d148e98df Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 09:19:08 -0300 Subject: [PATCH 20/21] fix examples with updated API --- .../AVRUartSlaveMidiClockMonitor.ino | 8 ++++---- .../LeonardoUsbSlaveMidiClockMonitor.ino | 8 ++++---- .../TeensyUsbSlaveMidiClockMonitor.ino | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/AVRUartSlaveMidiClockMonitor/AVRUartSlaveMidiClockMonitor.ino b/examples/AVRUartSlaveMidiClockMonitor/AVRUartSlaveMidiClockMonitor.ino index c7c3cae..12e7b7c 100644 --- a/examples/AVRUartSlaveMidiClockMonitor/AVRUartSlaveMidiClockMonitor.ino +++ b/examples/AVRUartSlaveMidiClockMonitor/AVRUartSlaveMidiClockMonitor.ino @@ -144,16 +144,16 @@ void loop() { u8x8->drawUTF8(8 + 4, 7, " "); } } - if (clock_state != uClock.state) { - clock_state = uClock.state; + if (clock_state != uClock.clock_state) { + clock_state = uClock.clock_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.getClockMode()) { + clock_mode = uClock.getClockMode(); if (clock_mode == uClock.EXTERNAL_CLOCK) { u8x8->drawUTF8(10, 0, "Slave "); } else { diff --git a/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino b/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino index a7ac66e..f681444 100644 --- a/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino +++ b/examples/LeonardoUsbSlaveMidiClockMonitor/LeonardoUsbSlaveMidiClockMonitor.ino @@ -135,16 +135,16 @@ void loop() { u8x8->drawUTF8(8+4, 7, " "); } } - if (clock_state != uClock.state) { - clock_state = uClock.state; + if (clock_state != uClock.clock_state) { + clock_state = uClock.clock_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.getClockMode()) { + clock_mode = uClock.getClockMode(); if (clock_mode == uClock.EXTERNAL_CLOCK) { u8x8->drawUTF8(10, 0, "Slave "); } else { diff --git a/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino b/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino index e6dc0c0..0c7e791 100644 --- a/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino +++ b/examples/TeensyUsbSlaveMidiClockMonitor/TeensyUsbSlaveMidiClockMonitor.ino @@ -144,16 +144,16 @@ void loop() { u8x8->drawUTF8(8+4, 7, " "); } } - if (clock_state != uClock.state) { - clock_state = uClock.state; + if (clock_state != uClock.clock_state) { + clock_state = uClock.clock_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.getClockMode()) { + clock_mode = uClock.getClockMode(); if (clock_mode == uClock.EXTERNAL_CLOCK) { u8x8->drawUTF8(10, 0, "Slave "); } else { From 1b3814ac397764ba6a43e74ec0766f5de29bf77e Mon Sep 17 00:00:00 2001 From: midilab Date: Sat, 26 Jul 2025 10:22:05 -0300 Subject: [PATCH 21/21] force clock_mode set before possible clock_state on external sync mode --- src/uClock.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index ae50591..309bcae 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -385,11 +385,10 @@ void uClockClass::pause() void uClockClass::setClockMode(ClockMode tempo_mode) { + ATOMIC(clock_mode = tempo_mode) // trying to set external clock while playing? force sync ext_interval if (tempo_mode == EXTERNAL_CLOCK && clock_state == STARTED) ATOMIC(clock_state = STARTING) - - ATOMIC(clock_mode = tempo_mode) } uClockClass::ClockMode uClockClass::getClockMode()