fix: external sync. freqToBpm function called by sync mechanism with wrong divider

pull/34/head
midilab 4 months ago
parent 5be9c088c7
commit 9cbb0ce8c3
  1. 1
      README.md
  2. 138
      src/uClock.cpp
  3. 10
      src/uClock.h

@ -31,7 +31,6 @@ void setup() {
uClock.setOnPPQN(onPPQNCallback); uClock.setOnPPQN(onPPQNCallback);
uClock.setOnStep(onStepCallback); uClock.setOnStep(onStepCallback);
uClock.setOnSync24(onSync24Callback); uClock.setOnSync24(onSync24Callback);
uClock.setOnSync48(onSync48Callback);
uClock.setOnClockStart(onClockStartCallback); uClock.setOnClockStart(onClockStartCallback);
uClock.setOnClockStop(onClockStopCallback); uClock.setOnClockStop(onClockStopCallback);

@ -103,7 +103,6 @@ uClockClass::uClockClass()
onPPQNCallback = nullptr; onPPQNCallback = nullptr;
onSync24Callback = nullptr; onSync24Callback = nullptr;
onSync48Callback = nullptr;
onStepCallback = nullptr; onStepCallback = nullptr;
onClockStartCallback = nullptr; onClockStartCallback = nullptr;
onClockStopCallback = nullptr; onClockStopCallback = nullptr;
@ -129,9 +128,8 @@ void uClockClass::setPPQN(PPQNResolution resolution)
// so we avoid volatile then and ATOMIC everyone // so we avoid volatile then and ATOMIC everyone
stop(); stop();
ppqn = resolution; ppqn = resolution;
// calculate the mod24, mod48 and mod_step tick reference trigger // calculate the mod24 and mod_step tick reference trigger
mod24_ref = ppqn / 24; mod24_ref = ppqn / 24;
mod48_ref = ppqn / 48;
mod_step_ref = ppqn / 4; mod_step_ref = ppqn / 4;
} }
@ -189,10 +187,11 @@ void uClockClass::setTempo(float bpm)
setTimerTempo(bpm); setTimerTempo(bpm);
} }
// this function is based on sync24PPQN
float inline uClockClass::freqToBpm(uint32_t freq) float inline uClockClass::freqToBpm(uint32_t freq)
{ {
float usecs = 1/((float)freq/1000000.0); float usecs = 1/((float)freq/1000000.0);
return (float)((float)(usecs/(float)ppqn) * 60.0); return (float)((float)(usecs/(float)24) * 60.0);
} }
float uClockClass::getTempo() float uClockClass::getTempo()
@ -236,14 +235,16 @@ void uClockClass::resetCounters()
{ {
tick = 0; tick = 0;
int_clock_tick = 0; int_clock_tick = 0;
sync48_tick = 0;
ext_clock_tick = 0;
ext_clock_us = 0;
ext_interval_idx = 0;
mod24_counter = 0; mod24_counter = 0;
mod48_counter = 0;
mod_step_counter = 0; mod_step_counter = 0;
step_counter = 0; step_counter = 0;
ext_clock_tick = 0;
ext_clock_us = 0;
ext_interval_idx = 0;
//ext_mod24_counter = 0;
//ext_mod_step_counter = 0;
//ext_step_counter = 0;
for (uint8_t i=0; i < EXT_INTERVAL_BUFFER_SIZE; i++) { for (uint8_t i=0; i < EXT_INTERVAL_BUFFER_SIZE; i++) {
ext_interval_buffer[i] = 0; ext_interval_buffer[i] = 0;
} }
@ -301,41 +302,27 @@ bool inline uClockClass::processShuffle()
return mod_step_counter == 0; return mod_step_counter == 0;
} }
// internal reference for mod_counter
uint8_t mod_counter = mod_step_ref - (mod_step_counter == 0 ? mod_step_ref : mod_step_counter);
int8_t mod_shuffle = 0; int8_t mod_shuffle = 0;
// check shuffle template to step // check shuffle template of current
int8_t shff = shuffle.step[step_counter%shuffle.size]; int8_t shff = shuffle.step[step_counter%shuffle.size];
if (shuffle_shoot_ctrl == false && mod_counter == 0) if (shuffle_shoot_ctrl == false && mod_step_counter == 0)
shuffle_shoot_ctrl = true; shuffle_shoot_ctrl = true;
//if (mod_counter == mod_step_ref-1) //if (mod_step_counter == mod_step_ref-1)
if (shff >= 0) { if (shff >= 0) {
mod_shuffle = mod_counter - shff; mod_shuffle = mod_step_counter - shff;
// any late shuffle? we should skip next mod_counter == 0 // any late shuffle? we should skip next mod_step_counter == 0
if (last_shff < 0 && mod_counter != 1) if (last_shff < 0 && mod_step_counter != 1)
return false; return false;
} else if (shff < 0) { } else if (shff < 0) {
mod_shuffle = mod_counter - (mod_step_ref + shff); mod_shuffle = mod_step_counter - (mod_step_ref + shff);
//if (last_shff < 0 && mod_counter != 1) //if (last_shff < 0 && mod_step_counter != 1)
// return false; // return false;
shuffle_shoot_ctrl = true; shuffle_shoot_ctrl = true;
} }
//Serial.println("-----------------");
//Serial.print("shff: ");
//Serial.println(shff);
//Serial.print("mod_counter: ");
//Serial.println(mod_counter);
//Serial.print("mod_shuffle: ");
//Serial.println(mod_shuffle);
//Serial.print("shuffle_shoot_ctrl: ");
//Serial.println(shuffle_shoot_ctrl);
//Serial.print("last_shff: ");
//Serial.println(last_shff);
last_shff = shff; last_shff = shff;
@ -391,84 +378,77 @@ void uClockClass::handleExternalClock()
void uClockClass::handleTimerInt() void uClockClass::handleTimerInt()
{ {
// External sync is handled here... test if clock check on each tick instead when // do we put a limit here to check external sync phase?
// mod24_counter kicks in will help or worst slave timing sync quality // try on at max PPQN
if (mod24_counter == 0) { if (mode == EXTERNAL_CLOCK) {
if (mode == EXTERNAL_CLOCK) { // sync tick position with external tick clock
// sync tick position with external tick clock if ((int_clock_tick < ext_clock_tick) || (int_clock_tick > (ext_clock_tick + 1))) {
if ((int_clock_tick < ext_clock_tick) || (int_clock_tick > (ext_clock_tick + 1))) { int_clock_tick = ext_clock_tick;
int_clock_tick = ext_clock_tick; tick = int_clock_tick * mod24_ref;
} mod24_counter = int_clock_tick % mod24_ref;
mod_step_counter = int_clock_tick % mod_step_ref;
}
uint32_t counter = ext_interval; uint32_t counter = ext_interval;
uint32_t now_clock_us = micros(); uint32_t now_clock_us = micros();
sync_interval = clock_diff(ext_clock_us, now_clock_us); sync_interval = clock_diff(ext_clock_us, now_clock_us);
if (int_clock_tick <= ext_clock_tick) { if (int_clock_tick <= ext_clock_tick) {
counter -= phase_mult(sync_interval); counter -= phase_mult(sync_interval);
} else { } else {
if (counter > sync_interval) { if (counter > sync_interval) {
counter += phase_mult(counter - sync_interval); counter += phase_mult(counter - sync_interval);
}
} }
}
// update internal clock timer frequency // update internal clock timer frequency
float bpm = freqToBpm(counter); float bpm = freqToBpm(counter);
if (bpm != tempo) { if (bpm != tempo) {
if (bpm >= MIN_BPM && bpm <= MAX_BPM) { if (bpm >= MIN_BPM && bpm <= MAX_BPM) {
tempo = bpm; tempo = bpm;
setTimerTempo(bpm); setTimerTempo(bpm);
}
} }
} }
// callback to inform about sync24 event }
// reset mod24 counter reference ?
if (mod24_counter == mod24_ref)
mod24_counter = 0;
// sync signals first please...
if (mod24_counter == 0) {
if (onSync24Callback) { if (onSync24Callback) {
onSync24Callback(int_clock_tick); onSync24Callback(int_clock_tick);
} }
// reset counter reference
mod24_counter = mod24_ref;
// internal clock tick me! sync24 tick too // internal clock tick me! sync24 tick too
++int_clock_tick; ++int_clock_tick;
} }
// sync signals first please...
if (onSync48Callback) {
if (mod48_counter == 0) {
onSync48Callback(sync48_tick);
// reset counter reference
mod48_counter = mod48_ref;
// sync48 tick me!
++sync48_tick;
}
}
// PPQNCallback time! // PPQNCallback time!
if (onPPQNCallback) { if (onPPQNCallback) {
onPPQNCallback(tick); onPPQNCallback(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 // step callback to support 16th old school style sequencers
// with builtin shuffle for this callback only // with builtin shuffle for this callback only
if (onStepCallback) { if (onStepCallback) {
// processShufle make use of mod_step_counter // processShufle make use of mod_step_counter == 0 logic too
if (processShuffle()) { if (processShuffle()) {
onStepCallback(step_counter); onStepCallback(step_counter);
// going forward to the next step call // going forward to the next step call
++step_counter; ++step_counter;
} }
// keep track of mod_step_counter
if (mod_step_counter == 0) {
// reset counter reference
mod_step_counter = mod_step_ref;
}
} }
// tick me! // tick me!
++tick; ++tick;
// decrement mod counters // increment mod counters
--mod24_counter; ++mod24_counter;
--mod48_counter; ++mod_step_counter;
--mod_step_counter;
} }
// elapsed time support // elapsed time support

@ -92,7 +92,7 @@ class uClockClass {
PPQN_960 = 960 PPQN_960 = 960
}; };
uint8_t state; ClockState state;
uClockClass(); uClockClass();
@ -108,10 +108,6 @@ class uClockClass {
onSync24Callback = callback; onSync24Callback = callback;
} }
void setOnSync48(void (*callback)(uint32_t tick)) {
onSync48Callback = callback;
}
void setOnClockStart(void (*callback)()) { void setOnClockStart(void (*callback)()) {
onClockStartCallback = callback; onClockStartCallback = callback;
} }
@ -170,7 +166,6 @@ class uClockClass {
void (*onPPQNCallback)(uint32_t tick); void (*onPPQNCallback)(uint32_t tick);
void (*onStepCallback)(uint32_t step); void (*onStepCallback)(uint32_t step);
void (*onSync24Callback)(uint32_t tick); void (*onSync24Callback)(uint32_t tick);
void (*onSync48Callback)(uint32_t tick);
void (*onClockStartCallback)(); void (*onClockStartCallback)();
void (*onClockStopCallback)(); void (*onClockStopCallback)();
@ -179,11 +174,8 @@ class uClockClass {
PPQNResolution ppqn = PPQN_96; PPQNResolution ppqn = PPQN_96;
uint32_t tick; uint32_t tick;
uint32_t int_clock_tick; uint32_t int_clock_tick;
uint32_t sync48_tick;
uint8_t mod24_counter; uint8_t mod24_counter;
uint8_t mod24_ref; uint8_t mod24_ref;
uint8_t mod48_counter;
uint8_t mod48_ref;
uint8_t mod_step_counter; uint8_t mod_step_counter;
uint8_t mod_step_ref; uint8_t mod_step_ref;
uint32_t step_counter; // should we go uint16_t? uint32_t step_counter; // should we go uint16_t?

Loading…
Cancel
Save