diff --git a/src/uClock.cpp b/src/uClock.cpp index 72e324f..ad152e2 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -23,7 +23,7 @@ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * DEALINGS IN THE SOFTWARE. */ #include "uClock.h" @@ -90,23 +90,23 @@ // header of this file void uclockInitTimer() { - // begin at 120bpm + // begin at 120bpm initTimer(uClock.bpmToMicroSeconds(120.00)); } -void setTimerTempo(float bpm) +void setTimerTempo(float bpm) { setTimer(uClock.bpmToMicroSeconds(bpm)); } namespace umodular { namespace clock { -static inline uint32_t phase_mult(uint32_t val) +static inline uint32_t phase_mult(uint32_t val) { return (val * PHASE_FACTOR) >> 8; } -static inline uint32_t clock_diff(uint32_t old_clock, uint32_t new_clock) +static inline uint32_t clock_diff(uint32_t old_clock, uint32_t new_clock) { if (new_clock >= old_clock) { return new_clock - old_clock; @@ -140,21 +140,24 @@ uClockClass::uClockClass() calculateReferencedata(); } -void uClockClass::init() +void uClockClass::init() { + if (ext_interval_buffer == nullptr) + setExtIntervalBuffer(1); + uclockInitTimer(); // first interval calculus setTempo(tempo); } -uint32_t uClockClass::bpmToMicroSeconds(float bpm) +uint32_t uClockClass::bpmToMicroSeconds(float bpm) { return (60000000.0f / (float)output_ppqn / bpm); } void uClockClass::calculateReferencedata() { - mod_clock_ref = output_ppqn / input_ppqn; + 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; @@ -185,20 +188,20 @@ void uClockClass::setInputPPQN(PPQNResolution resolution) ) } -void uClockClass::start() +void uClockClass::start() { resetCounters(); start_timer = millis(); - + if (onClockStartCallback) { onClockStartCallback(); - } - + } + if (clock_mode == INTERNAL_CLOCK) { clock_state = STARTED; } else { clock_state = STARTING; - } + } } void uClockClass::stop() @@ -211,7 +214,7 @@ void uClockClass::stop() } } -void uClockClass::pause() +void uClockClass::pause() { if (clock_mode == INTERNAL_CLOCK) { if (clock_state == PAUSED) { @@ -222,12 +225,12 @@ void uClockClass::pause() } } -void uClockClass::setTempo(float bpm) +void uClockClass::setTempo(float bpm) { if (clock_mode == EXTERNAL_CLOCK) { return; } - + if (bpm < MIN_BPM || bpm > MAX_BPM) { return; } @@ -239,19 +242,19 @@ void uClockClass::setTempo(float bpm) setTimerTempo(bpm); } -float uClockClass::getTempo() +float uClockClass::getTempo() { if (clock_mode == EXTERNAL_CLOCK) { uint32_t acc = 0; // wait the buffer to get full - if (ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE-1] == 0) { + if (ext_interval_buffer[ext_interval_buffer_size-1] == 0) { return tempo; } - for (uint8_t i=0; i < EXT_INTERVAL_BUFFER_SIZE; i++) { + for (uint8_t i=0; i < ext_interval_buffer_size; i++) { acc += ext_interval_buffer[i]; } if (acc != 0) { - return freqToBpm(acc / EXT_INTERVAL_BUFFER_SIZE); + return freqToBpm(acc / ext_interval_buffer_size); } } return tempo; @@ -272,17 +275,17 @@ float inline uClockClass::freqToBpm(uint32_t freq) return (float)((float)(usecs/(float)input_ppqn) * 60.0); } -void uClockClass::setClockMode(ClockMode tempo_mode) +void uClockClass::setClockMode(ClockMode tempo_mode) { clock_mode = tempo_mode; } -uClockClass::ClockMode uClockClass::getClockMode() +uClockClass::ClockMode uClockClass::getClockMode() { return clock_mode; } -void uClockClass::clockMe() +void uClockClass::clockMe() { if (clock_mode == EXTERNAL_CLOCK) { ATOMIC( @@ -291,7 +294,17 @@ void uClockClass::clockMe() } } -void uClockClass::resetCounters() +void uClockClass::setExtIntervalBuffer(uint8_t buffer_size) +{ + if (ext_interval_buffer != nullptr) + return; + + // alloc once and forever policy + ext_interval_buffer_size = buffer_size; + ext_interval_buffer = (uint32_t*) malloc( sizeof(uint32_t) * ext_interval_buffer_size ); +} + +void uClockClass::resetCounters() { tick = 0; int_clock_tick = 0; @@ -316,16 +329,16 @@ void uClockClass::resetCounters() sync24_tick = 0; mod_sync48_counter = 0; sync48_tick = 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; } } -void uClockClass::tap() +void uClockClass::tap() { // we can make use of mod_sync1_ref for tap - //uint8_t mod_tap_ref = output_ppqn / PPQN_1; + //uint8_t mod_tap_ref = output_ppqn / PPQN_1; // we only set tap if ClockMode is INTERNAL_CLOCK } @@ -381,7 +394,7 @@ bool inline uClockClass::processShuffle() int8_t shff = shuffle.step[step_counter%shuffle.size]; if (shuffle_shoot_ctrl == false && mod_step_counter == 0) - shuffle_shoot_ctrl = true; + shuffle_shoot_ctrl = true; //if (mod_step_counter == mod_step_ref-1) @@ -389,11 +402,11 @@ bool inline uClockClass::processShuffle() mod_shuffle = mod_step_counter - shff; // any late shuffle? we should skip next mod_step_counter == 0 if (last_shff < 0 && mod_step_counter != 1) - return false; + return false; } else if (shff < 0) { mod_shuffle = mod_step_counter - (mod_step_ref + shff); //if (last_shff < 0 && mod_step_counter != 1) - // return false; + // return false; shuffle_shoot_ctrl = true; } @@ -414,7 +427,7 @@ bool inline uClockClass::processShuffle() return false; } -void uClockClass::handleExternalClock() +void uClockClass::handleExternalClock() { switch (clock_state) { case PAUSED: @@ -434,7 +447,7 @@ void uClockClass::handleExternalClock() 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; @@ -448,7 +461,7 @@ void uClockClass::handleExternalClock() } } -void uClockClass::handleTimerInt() +void uClockClass::handleTimerInt() { // track main input clock counter if (mod_clock_counter == mod_clock_ref) @@ -515,7 +528,7 @@ void uClockClass::handleTimerInt() } ++mod_sync2_counter; } - + // Sync4 callback if (onSync4Callback) { if (mod_sync4_counter == mod_sync4_ref) @@ -583,7 +596,7 @@ void uClockClass::handleTimerInt() if (mod_step_counter == mod_step_ref) mod_step_counter = 0; // processShufle make use of mod_step_counter == 0 logic too - if (processShuffle()) { + if (processShuffle()) { onStepCallback(step_counter); // going forward to the next step call ++step_counter; @@ -605,7 +618,7 @@ uint8_t uClockClass::getNumberOfMinutes(uint32_t time) { if ( time == 0 ) { return time; - } + } return (((_millis - time) / 1000) / SECS_PER_MIN) % SECS_PER_MIN; } @@ -613,7 +626,7 @@ uint8_t uClockClass::getNumberOfHours(uint32_t time) { if ( time == 0 ) { return time; - } + } return (((_millis - time) / 1000) % SECS_PER_DAY) / SECS_PER_HOUR; } @@ -621,7 +634,7 @@ uint8_t uClockClass::getNumberOfDays(uint32_t time) { if ( time == 0 ) { return time; - } + } return ((_millis - time) / 1000) / SECS_PER_DAY; } @@ -629,12 +642,12 @@ uint32_t uClockClass::getNowTimer() { return _millis; } - + uint32_t uClockClass::getPlayTime() { return start_timer; } - + } } // end namespace umodular::clock umodular::clock::uClockClass uClock; @@ -642,13 +655,13 @@ umodular::clock::uClockClass uClock; volatile uint32_t _millis = 0; // -// TIMER HANDLER -// -void uClockHandler() +// TIMER HANDLER +// +void uClockHandler() { // global timer counter _millis = millis(); - + if (uClock.clock_state == uClock.STARTED) { uClock.handleTimerInt(); } diff --git a/src/uClock.h b/src/uClock.h index 97ca6ac..468cf1d 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -23,7 +23,7 @@ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * DEALINGS IN THE SOFTWARE. */ #ifndef __U_CLOCK_H__ @@ -36,7 +36,7 @@ namespace umodular { namespace clock { // Shuffle templates are specific for each PPQN output resolution // min: -(output_ppqn/4)-1 ticks -// max: (output_ppqn/4)-1 ticks +// max: (output_ppqn/4)-1 ticks // adjust the size of you template if more than 16 shuffle step info needed #define MAX_SHUFFLE_TEMPLATE_SIZE 16 typedef struct { @@ -45,12 +45,6 @@ typedef struct { int8_t step[MAX_SHUFFLE_TEMPLATE_SIZE] = {0}; } SHUFFLE_TEMPLATE; -// for smooth slave tempo calculate display you should raise this value -// in between 64 to 128. -// note: this doesn't impact on sync time, only display time getTempo() -// if you dont want to use it, set it to 1 for memory save -#define EXT_INTERVAL_BUFFER_SIZE 128 - #define MIN_BPM 1 #define MAX_BPM 400 @@ -90,7 +84,7 @@ class uClockClass { }; ClockState clock_state; - + uClockClass(); void setOnOutputPPQN(void (*callback)(uint32_t tick)) { @@ -105,19 +99,19 @@ class uClockClass { void setOnSync1(void (*callback)(uint32_t tick)) { onSync1Callback = callback; } - + 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; } @@ -125,7 +119,7 @@ class uClockClass { void setOnSync24(void (*callback)(uint32_t tick)) { onSync24Callback = callback; } - + void setOnSync48(void (*callback)(uint32_t tick)) { onSync48Callback = callback; } @@ -145,7 +139,7 @@ class uClockClass { void handleTimerInt(); void handleExternalClock(); void resetCounters(); - + // external class control void start(); void stop(); @@ -160,6 +154,11 @@ class uClockClass { void setClockMode(ClockMode tempo_mode); ClockMode getClockMode(); void clockMe(); + // for smooth slave tempo calculate display you should raise the + // buffer_size of ext_interval_buffer in between 64 to 128. 254 max size. + // note: this doesn't impact on sync time, only display time getTempo() + // if you dont want to use it, it is default set it to 1 for memory save + void setExtIntervalBuffer(uint8_t buffer_size); // shuffle void setShuffle(bool active); @@ -169,10 +168,10 @@ class uClockClass { void setShuffleTemplate(int8_t * shuff, uint8_t size); // use this to know how many positive or negative ticks to add to current note length int8_t getShuffleLength(); - + // todo! void tap(); - + // elapsed time support uint8_t getNumberOfSeconds(uint32_t time); uint8_t getNumberOfMinutes(uint32_t time); @@ -246,7 +245,8 @@ class uClockClass { uint32_t start_timer; ClockMode clock_mode; - volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE]; + volatile uint32_t * ext_interval_buffer = nullptr; + uint8_t ext_interval_buffer_size; uint16_t ext_interval_idx; // shuffle implementation @@ -265,4 +265,3 @@ extern "C" { } #endif /* __U_CLOCK_H__ */ -