From e1d6674635b2c2f121958cdfea89923aab89a200 Mon Sep 17 00:00:00 2001 From: midilab Date: Tue, 25 Mar 2025 10:33:56 -0300 Subject: [PATCH] added clock output callback for the following resolutions 1PPQN, 2PPQN, 4PPQN, 8PPQN, 12PPQN and 48PPQN --- src/uClock.cpp | 137 +++++++++++++++++++++++++++++++++++++------------ src/uClock.h | 57 ++++++++++++++------ 2 files changed, 145 insertions(+), 49 deletions(-) diff --git a/src/uClock.cpp b/src/uClock.cpp index 405cb87..182314b 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -126,7 +126,13 @@ uClockClass::uClockClass() resetCounters(); onPPQNCallback = nullptr; + onSync1Callback = nullptr; + onSync2Callback = nullptr; + onSync4Callback = nullptr; + onSync8Callback = nullptr; + onSync12Callback = nullptr; onSync24Callback = nullptr; + onSync48Callback = nullptr; onStepCallback = nullptr; onClockStartCallback = nullptr; onClockStopCallback = nullptr; @@ -149,6 +155,11 @@ uint32_t uClockClass::bpmToMicroSeconds(float bpm) void uClockClass::calculateReferencedata() { mod_clock_ref = ppqn / clock_ppqn; + mod_sync1_ref = ppqn / PPQN_1; + mod_sync2_ref = ppqn / PPQN_2; + mod_sync4_ref = ppqn / PPQN_4; + mod_sync8_ref = ppqn / PPQN_8; + mod_sync12_ref = ppqn / PPQN_12; mod_sync24_ref = ppqn / PPQN_24; mod_sync48_ref = ppqn / PPQN_48; mod_step_ref = ppqn / 4; @@ -156,20 +167,18 @@ void uClockClass::calculateReferencedata() void uClockClass::setPPQN(PPQNResolution resolution) { - // stop clock to make it safe changing those references - // so we avoid volatile then and ATOMIC everywhere - //stop(); - ppqn = resolution; - calculateReferencedata(); + ATOMIC( + ppqn = resolution; + calculateReferencedata(); + ) } void uClockClass::setClockPPQN(PPQNResolution resolution) { - // stop clock to make it safe changing those references - // so we avoid volatile then and ATOMIC everywhere - //stop(); - clock_ppqn = resolution; - calculateReferencedata(); + ATOMIC( + clock_ppqn = resolution; + calculateReferencedata(); + ) } void uClockClass::start() @@ -284,14 +293,25 @@ void uClockClass::resetCounters() int_clock_tick = 0; mod_clock_counter = 0; mod_step_counter = 0; - mod_sync24_counter = 0; - sync24_tick = 0; - mod_sync48_counter = 0; - sync48_tick = 0; step_counter = 0; ext_clock_tick = 0; ext_clock_us = 0; ext_interval_idx = 0; + // sync output counters + mod_sync1_counter = 0; + sync1_tick = 0; + mod_sync2_counter = 0; + sync2_tick = 0; + mod_sync4_counter = 0; + sync4_tick = 0; + mod_sync8_counter = 0; + sync8_tick = 0; + mod_sync12_counter = 0; + sync12_tick = 0; + mod_sync24_counter = 0; + sync24_tick = 0; + mod_sync48_counter = 0; + sync48_tick = 0; for (uint8_t i=0; i < EXT_INTERVAL_BUFFER_SIZE; i++) { ext_interval_buffer[i] = 0; @@ -426,7 +446,7 @@ void uClockClass::handleExternalClock() void uClockClass::handleTimerInt() { - // reset mod_clock_counter + // track main input clock counter if (mod_clock_counter == mod_clock_ref) mod_clock_counter = 0; @@ -467,56 +487,105 @@ void uClockClass::handleTimerInt() // internal clock tick me! ++int_clock_tick; } + ++mod_clock_counter; - // Sync24 callback - if (mod_sync24_counter == mod_sync24_ref) - mod_sync24_counter = 0; + // 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 (mod_sync48_counter == mod_sync48_ref) - mod_sync48_counter = 0; - 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; } - // PPQNCallback time! + // main PPQNCallback if (onPPQNCallback) { onPPQNCallback(tick); + ++tick; } - // reset step mod counter reference ? - if (mod_step_counter == mod_step_ref) - mod_step_counter = 0; - // 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; } - - // tick me! - ++tick; - // increment mod counters - ++mod_clock_counter; - ++mod_sync24_counter; - ++mod_sync48_counter; - ++mod_step_counter; } // elapsed time support diff --git a/src/uClock.h b/src/uClock.h index 96cd47b..ab4f4ed 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -34,16 +34,6 @@ namespace umodular { namespace clock { -// for extended steps in memory style and make use of 96ppqn for record propurse we can -// keep array[step] memory layout and add new information about note possition to be check for the entire ppqn pulse -// example: for a whole 24 pulses we only check array[step].offset that can vary from 0 to 24(ppqn/4) -// time/tick notation and representation notes: -// one quarter note == 4 steps in 16th notes step sequencer style -// PPQN / 4 = pulses in between steps(from step sequencer perspective, a quarter note have 4 steps) -// 24 PPQN (6 pulses per step) -// 48 PPQN (12 pulses per step) -// 96 PPQN (24 pulses per step) - // min: -(ppqn/4)-1 step, max: (ppqn/4)-1 steps // adjust the size of you template if more than 16 shuffle step info needed #define MAX_SHUFFLE_TEMPLATE_SIZE 16 @@ -108,12 +98,27 @@ class uClockClass { void setOnStep(void (*callback)(uint32_t step)) { onStepCallback = callback; } + + // multiple output clock signatures + void setOnSync1(void (*callback)(uint32_t tick)) { + onSync1Callback = callback; + } - // setOnSync1 - // setOnSync2 - // setOnSync4 - // setOnSync8 - // setOnSync12 + void setOnSync2(void (*callback)(uint32_t tick)) { + onSync2Callback = callback; + } + + void setOnSync4(void (*callback)(uint32_t tick)) { + onSync4Callback = callback; + } + + void setOnSync8(void (*callback)(uint32_t tick)) { + onSync8Callback = callback; + } + + void setOnSync12(void (*callback)(uint32_t tick)) { + onSync12Callback = callback; + } void setOnSync24(void (*callback)(uint32_t tick)) { onSync24Callback = callback; @@ -185,6 +190,11 @@ class uClockClass { void (*onPPQNCallback)(uint32_t tick); void (*onStepCallback)(uint32_t step); + void (*onSync1Callback)(uint32_t tick); + void (*onSync2Callback)(uint32_t tick); + void (*onSync4Callback)(uint32_t tick); + void (*onSync8Callback)(uint32_t tick); + void (*onSync12Callback)(uint32_t tick); void (*onSync24Callback)(uint32_t tick); void (*onSync48Callback)(uint32_t tick); void (*onClockStartCallback)(); @@ -201,6 +211,23 @@ class uClockClass { uint8_t mod_step_counter; uint8_t mod_step_ref; uint32_t step_counter; // should we go uint16_t? + + // clock output counters, ticks and references + uint8_t mod_sync1_counter; + uint8_t mod_sync1_ref; + uint32_t sync1_tick; + uint8_t mod_sync2_counter; + uint8_t mod_sync2_ref; + uint32_t sync2_tick; + uint8_t mod_sync4_counter; + uint8_t mod_sync4_ref; + uint32_t sync4_tick; + uint8_t mod_sync8_counter; + uint8_t mod_sync8_ref; + uint32_t sync8_tick; + uint8_t mod_sync12_counter; + uint8_t mod_sync12_ref; + uint32_t sync12_tick; uint8_t mod_sync24_counter; uint8_t mod_sync24_ref; uint32_t sync24_tick;