diff --git a/src/platforms/avr.h b/src/platforms/avr.h index 0a8dac9..9904c92 100644 --- a/src/platforms/avr.h +++ b/src/platforms/avr.h @@ -8,55 +8,55 @@ void initTimer(uint32_t init_clock) { - ATOMIC( - // 16bits Timer1 init - // begin at 120bpm (48.0007680122882 Hz) - TCCR1A = 0; // set entire TCCR1A register to 0 - TCCR1B = 0; // same for TCCR1B - TCNT1 = 0; // initialize counter value to 0 - // set compare match register for 48.0007680122882 Hz increments - OCR1A = 41665; // = 16000000 / (8 * 48.0007680122882) - 1 (must be <65536) - // turn on CTC mode - TCCR1B |= (1 << WGM12); - // Set CS12, CS11 and CS10 bits for 8 prescaler - TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10); - // enable timer compare interrupt - TIMSK1 |= (1 << OCIE1A); - ) + ATOMIC( + // 16bits Timer1 init + // begin at 120bpm (48.0007680122882 Hz) + TCCR1A = 0; // set entire TCCR1A register to 0 + TCCR1B = 0; // same for TCCR1B + TCNT1 = 0; // initialize counter value to 0 + // set compare match register for 48.0007680122882 Hz increments + OCR1A = 41665; // = 16000000 / (8 * 48.0007680122882) - 1 (must be <65536) + // turn on CTC mode + TCCR1B |= (1 << WGM12); + // Set CS12, CS11 and CS10 bits for 8 prescaler + TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10); + // enable timer compare interrupt + TIMSK1 |= (1 << OCIE1A); + ) } void setTimer(uint32_t us_interval) { - float tick_hertz_interval = 1/((float)us_interval/1000000); + float tick_hertz_interval = 1/((float)us_interval/1000000); - uint32_t ocr; - uint8_t tccr = 0; + uint32_t ocr; + uint8_t tccr = 0; - // 16bits avr timer setup - if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 1 )) < 65535) { - // Set CS12, CS11 and CS10 bits for 1 prescaler - tccr |= (0 << CS12) | (0 << CS11) | (1 << CS10); - } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 8 )) < 65535) { - // Set CS12, CS11 and CS10 bits for 8 prescaler - tccr |= (0 << CS12) | (1 << CS11) | (0 << CS10); - } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 64 )) < 65535) { - // Set CS12, CS11 and CS10 bits for 64 prescaler - tccr |= (0 << CS12) | (1 << CS11) | (1 << CS10); - } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 256 )) < 65535) { - // Set CS12, CS11 and CS10 bits for 256 prescaler - tccr |= (1 << CS12) | (0 << CS11) | (0 << CS10); - } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 1024 )) < 65535) { - // Set CS12, CS11 and CS10 bits for 1024 prescaler - tccr |= (1 << CS12) | (0 << CS11) | (1 << CS10); - } else { - // tempo not achiavable - return; - } + // 16bits avr timer setup + if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 1 )) < 65535) { + // Set CS12, CS11 and CS10 bits for 1 prescaler + tccr |= (0 << CS12) | (0 << CS11) | (1 << CS10); + } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 8 )) < 65535) { + // Set CS12, CS11 and CS10 bits for 8 prescaler + tccr |= (0 << CS12) | (1 << CS11) | (0 << CS10); + } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 64 )) < 65535) { + // Set CS12, CS11 and CS10 bits for 64 prescaler + tccr |= (0 << CS12) | (1 << CS11) | (1 << CS10); + } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 256 )) < 65535) { + // Set CS12, CS11 and CS10 bits for 256 prescaler + tccr |= (1 << CS12) | (0 << CS11) | (0 << CS10); + } else if ((ocr = AVR_CLOCK_FREQ / ( tick_hertz_interval * 1024 )) < 65535) { + // Set CS12, CS11 and CS10 bits for 1024 prescaler + tccr |= (1 << CS12) | (0 << CS11) | (1 << CS10); + } else { + // tempo not achiavable + return; + } - ATOMIC( - TCCR1B = 0; - OCR1A = ocr-1; - TCCR1B |= (1 << WGM12); - TCCR1B |= tccr; - ) + ATOMIC( + TCCR1B = 0; + OCR1A = ocr-1; + TCCR1B |= (1 << WGM12); + TCCR1B |= tccr; + ) } \ No newline at end of file diff --git a/src/platforms/esp32.h b/src/platforms/esp32.h index 5da8080..bb4aa3b 100644 --- a/src/platforms/esp32.h +++ b/src/platforms/esp32.h @@ -25,5 +25,5 @@ void initTimer(uint32_t init_clock) void setTimer(uint32_t us_interval) { - timerAlarmWrite(_uclockTimer, us_interval, true); + timerAlarmWrite(_uclockTimer, us_interval, true); } \ No newline at end of file diff --git a/src/platforms/samd.h b/src/platforms/samd.h index 87f9fca..6f5ef21 100644 --- a/src/platforms/samd.h +++ b/src/platforms/samd.h @@ -23,5 +23,5 @@ void initTimer(uint32_t init_clock) void setTimer(uint32_t us_interval) { - TimerTcc0.setPeriod(us_interval); + TimerTcc0.setPeriod(us_interval); } \ No newline at end of file diff --git a/src/platforms/teensy.h b/src/platforms/teensy.h index 764b7e8..6fceb96 100644 --- a/src/platforms/teensy.h +++ b/src/platforms/teensy.h @@ -21,5 +21,5 @@ void initTimer(uint32_t init_clock) void setTimer(uint32_t us_interval) { - _uclockTimer.update(us_interval); + _uclockTimer.update(us_interval); } \ No newline at end of file diff --git a/src/uClock.cpp b/src/uClock.cpp index 4f51d06..8839914 100755 --- a/src/uClock.cpp +++ b/src/uClock.cpp @@ -31,31 +31,31 @@ // General Arduino AVRs port // #if defined(ARDUINO_ARCH_AVR) - #include "platforms/avr.h" + #include "platforms/avr.h" #endif // // Teensyduino ARMs port // #if defined(TEENSYDUINO) - #include "platforms/teensy.h" + #include "platforms/teensy.h" #endif // // Seedstudio XIAO M0 port // #if defined(SEEED_XIAO_M0) - #include "platforms/samd.h" + #include "platforms/samd.h" #endif // // ESP32 family // #if defined(ARDUINO_ARCH_ESP32) || defined(ESP32) - #include "platforms/esp32.h" + #include "platforms/esp32.h" #endif // // STM32XX family // #if defined(ARDUINO_ARCH_STM32) - #include "platforms/stm32.h" + #include "platforms/stm32.h" #endif // @@ -66,342 +66,342 @@ // header of this file void uclockInitTimer() { - // begin at 120bpm (20833us) - initTimer(20833); + // begin at 120bpm (20833us) + initTimer(20833); } void setTimerTempo(float bpm) { - // convert bpm float into 96 ppqn resolution microseconds interval - uint32_t us_interval = (60000000 / 24 / bpm); - setTimer(us_interval); + // convert bpm float into 96 ppqn resolution microseconds interval + uint32_t us_interval = (60000000 / 24 / bpm); + setTimer(us_interval); } namespace umodular { namespace clock { static inline uint32_t phase_mult(uint32_t val) { - return (val * PHASE_FACTOR) >> 8; + return (val * PHASE_FACTOR) >> 8; } static inline uint32_t clock_diff(uint32_t old_clock, uint32_t new_clock) { - if (new_clock >= old_clock) { - return new_clock - old_clock; - } else { - return new_clock + (4294967295 - old_clock); - } + if (new_clock >= old_clock) { + return new_clock - old_clock; + } else { + return new_clock + (4294967295 - old_clock); + } } uClockClass::uClockClass() { - tempo = 120; - start_timer = 0; - last_interval = 0; - sync_interval = 0; - state = PAUSED; - mode = INTERNAL_CLOCK; - resetCounters(); - - onClock96PPQNCallback = NULL; - onClock32PPQNCallback = NULL; - onClock16PPQNCallback = NULL; - onClockStartCallback = NULL; - onClockStopCallback = NULL; + tempo = 120; + start_timer = 0; + last_interval = 0; + sync_interval = 0; + state = PAUSED; + mode = INTERNAL_CLOCK; + resetCounters(); + + onClock96PPQNCallback = NULL; + onClock32PPQNCallback = NULL; + onClock16PPQNCallback = NULL; + onClockStartCallback = NULL; + onClockStopCallback = NULL; } void uClockClass::init() { - uclockInitTimer(); - // first interval calculus - setTempo(tempo); + uclockInitTimer(); + // first interval calculus + setTempo(tempo); } void uClockClass::start() { - resetCounters(); - start_timer = millis(); - - if (onClockStartCallback) { - onClockStartCallback(); - } - - if (mode == INTERNAL_CLOCK) { - state = STARTED; - } else { - state = STARTING; - } + resetCounters(); + start_timer = millis(); + + if (onClockStartCallback) { + onClockStartCallback(); + } + + if (mode == INTERNAL_CLOCK) { + state = STARTED; + } else { + state = STARTING; + } } void uClockClass::stop() { - state = PAUSED; - start_timer = 0; - resetCounters(); - if (onClockStopCallback) { - onClockStopCallback(); - } + state = PAUSED; + start_timer = 0; + resetCounters(); + if (onClockStopCallback) { + onClockStopCallback(); + } } void uClockClass::pause() { - if (mode == INTERNAL_CLOCK) { - if (state == PAUSED) { - start(); - } else { - stop(); - } - } + if (mode == INTERNAL_CLOCK) { + if (state == PAUSED) { + start(); + } else { + stop(); + } + } } void uClockClass::setTempo(float bpm) { - if (mode == EXTERNAL_CLOCK) { - return; - } - - if (bpm < MIN_BPM || bpm > MAX_BPM) { - return; - } - - ATOMIC( - tempo = bpm - ) - - setTimerTempo(bpm); - + if (mode == EXTERNAL_CLOCK) { + return; + } + + if (bpm < MIN_BPM || bpm > MAX_BPM) { + return; + } + + ATOMIC( + tempo = bpm + ) + + setTimerTempo(bpm); + } float inline uClockClass::freqToBpm(uint32_t freq) { - float usecs = 1/((float)freq/1000000.0); - return (float)((float)(usecs/24.0) * 60.0); + float usecs = 1/((float)freq/1000000.0); + return (float)((float)(usecs/24.0) * 60.0); } float uClockClass::getTempo() { - if (mode == EXTERNAL_CLOCK) { - uint32_t acc = 0; - // wait the buffer get full - if (ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE-1] == 0) { - return tempo; - } - 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 tempo; + if (mode == EXTERNAL_CLOCK) { + uint32_t acc = 0; + // wait the buffer get full + if (ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE-1] == 0) { + return tempo; + } + 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 tempo; } void uClockClass::setMode(uint8_t tempo_mode) { - mode = tempo_mode; + mode = tempo_mode; } uint8_t uClockClass::getMode() { - return mode; + return mode; } void uClockClass::clockMe() { - if (mode == EXTERNAL_CLOCK) { - ATOMIC( - handleExternalClock() - ) - } + if (mode == EXTERNAL_CLOCK) { + ATOMIC( + handleExternalClock() + ) + } } void uClockClass::resetCounters() { - external_clock = 0; - internal_tick = 0; - external_tick = 0; - div32th_counter = 0; - div16th_counter = 0; - mod6_counter = 0; - indiv32th_counter = 0; - indiv16th_counter = 0; - inmod6_counter = 0; - ext_interval_idx = 0; - for (uint8_t i=0; i < EXT_INTERVAL_BUFFER_SIZE; i++) { - ext_interval_buffer[i] = 0; - } + external_clock = 0; + internal_tick = 0; + external_tick = 0; + div32th_counter = 0; + div16th_counter = 0; + mod6_counter = 0; + indiv32th_counter = 0; + indiv16th_counter = 0; + inmod6_counter = 0; + ext_interval_idx = 0; + for (uint8_t i=0; i < EXT_INTERVAL_BUFFER_SIZE; i++) { + ext_interval_buffer[i] = 0; + } } // TODO: Tap stuff void uClockClass::tap() { - // tap me + // tap me } // TODO: Shuffle stuff void uClockClass::shuffle() { - // shuffle me + // shuffle me } void uClockClass::handleExternalClock() { - switch (state) { - case PAUSED: - break; - - case STARTING: - state = STARTED; - external_clock = micros(); - break; - - case STARTED: - - uint32_t u_timer = micros(); - last_interval = clock_diff(external_clock, u_timer); - external_clock = u_timer; - - if (inmod6_counter == 0) { - indiv16th_counter++; - indiv32th_counter++; - } - - if (inmod6_counter == 3) { - indiv32th_counter++; - } - - // slave tick me! - external_tick++; - inmod6_counter++; - - if (inmod6_counter == 6) { - inmod6_counter = 0; - } - - // accumulate interval incomming ticks data for getTempo() smooth reads on slave mode - if(++ext_interval_idx >= EXT_INTERVAL_BUFFER_SIZE) { - ext_interval_idx = 0; - } - ext_interval_buffer[ext_interval_idx] = last_interval; - - if (external_tick == 1) { - interval = last_interval; - } else { - interval = (((uint32_t)interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; - } - break; - } + switch (state) { + case PAUSED: + break; + + case STARTING: + state = STARTED; + external_clock = micros(); + break; + + case STARTED: + + uint32_t u_timer = micros(); + last_interval = clock_diff(external_clock, u_timer); + external_clock = u_timer; + + if (inmod6_counter == 0) { + indiv16th_counter++; + indiv32th_counter++; + } + + if (inmod6_counter == 3) { + indiv32th_counter++; + } + + // slave tick me! + external_tick++; + inmod6_counter++; + + if (inmod6_counter == 6) { + inmod6_counter = 0; + } + + // accumulate interval incomming ticks data for getTempo() smooth reads on slave mode + if(++ext_interval_idx >= EXT_INTERVAL_BUFFER_SIZE) { + ext_interval_idx = 0; + } + ext_interval_buffer[ext_interval_idx] = last_interval; + + if (external_tick == 1) { + interval = last_interval; + } else { + interval = (((uint32_t)interval * (uint32_t)PLL_X) + (uint32_t)(256 - PLL_X) * (uint32_t)last_interval) >> 8; + } + break; + } } void uClockClass::handleTimerInt() { - if (mode == EXTERNAL_CLOCK) { - // sync tick position with external tick clock - if ((internal_tick < external_tick) || (internal_tick > (external_tick + 1))) { - internal_tick = external_tick; - div32th_counter = indiv32th_counter; - div16th_counter = indiv16th_counter; - mod6_counter = inmod6_counter; - } - - uint32_t counter = interval; - uint32_t u_timer = micros(); - sync_interval = clock_diff(external_clock, u_timer); - - if (internal_tick <= external_tick) { - counter -= phase_mult(sync_interval); - } else { - if (counter > sync_interval) { - counter += phase_mult(counter - sync_interval); - } - } - - // update internal clock timer frequency - float bpm = freqToBpm(counter); - if (bpm != tempo) { - if (bpm >= MIN_BPM && bpm <= MAX_BPM) { - tempo = bpm; - setTimerTempo(bpm); - } - } - } - - if (onClock96PPQNCallback) { - onClock96PPQNCallback(internal_tick); - } - - if (mod6_counter == 0) { - if (onClock32PPQNCallback) { - onClock32PPQNCallback(div32th_counter); - } - if (onClock16PPQNCallback) { - onClock16PPQNCallback(div16th_counter); - } - div16th_counter++; - div32th_counter++; - } - - if (mod6_counter == 3) { - if (onClock32PPQNCallback) { - onClock32PPQNCallback(div32th_counter); - } - div32th_counter++; - } - - // tick me! - internal_tick++; - mod6_counter++; - - if (mod6_counter == 6) { - mod6_counter = 0; - } - + if (mode == EXTERNAL_CLOCK) { + // sync tick position with external tick clock + if ((internal_tick < external_tick) || (internal_tick > (external_tick + 1))) { + internal_tick = external_tick; + div32th_counter = indiv32th_counter; + div16th_counter = indiv16th_counter; + mod6_counter = inmod6_counter; + } + + uint32_t counter = interval; + uint32_t u_timer = micros(); + sync_interval = clock_diff(external_clock, u_timer); + + if (internal_tick <= external_tick) { + counter -= phase_mult(sync_interval); + } else { + if (counter > sync_interval) { + counter += phase_mult(counter - sync_interval); + } + } + + // update internal clock timer frequency + float bpm = freqToBpm(counter); + if (bpm != tempo) { + if (bpm >= MIN_BPM && bpm <= MAX_BPM) { + tempo = bpm; + setTimerTempo(bpm); + } + } + } + + if (onClock96PPQNCallback) { + onClock96PPQNCallback(internal_tick); + } + + if (mod6_counter == 0) { + if (onClock32PPQNCallback) { + onClock32PPQNCallback(div32th_counter); + } + if (onClock16PPQNCallback) { + onClock16PPQNCallback(div16th_counter); + } + div16th_counter++; + div32th_counter++; + } + + if (mod6_counter == 3) { + if (onClock32PPQNCallback) { + onClock32PPQNCallback(div32th_counter); + } + div32th_counter++; + } + + // tick me! + internal_tick++; + mod6_counter++; + + if (mod6_counter == 6) { + mod6_counter = 0; + } + } // elapsed time support uint8_t uClockClass::getNumberOfSeconds(uint32_t time) { - if ( time == 0 ) { - return time; - } - return ((_timer - time) / 1000) % SECS_PER_MIN; + if ( time == 0 ) { + return time; + } + return ((_timer - time) / 1000) % SECS_PER_MIN; } uint8_t uClockClass::getNumberOfMinutes(uint32_t time) { - if ( time == 0 ) { - return time; - } - return (((_timer - time) / 1000) / SECS_PER_MIN) % SECS_PER_MIN; + if ( time == 0 ) { + return time; + } + return (((_timer - time) / 1000) / SECS_PER_MIN) % SECS_PER_MIN; } uint8_t uClockClass::getNumberOfHours(uint32_t time) { - if ( time == 0 ) { - return time; - } - return (((_timer - time) / 1000) % SECS_PER_DAY) / SECS_PER_HOUR; + if ( time == 0 ) { + return time; + } + return (((_timer - time) / 1000) % SECS_PER_DAY) / SECS_PER_HOUR; } uint8_t uClockClass::getNumberOfDays(uint32_t time) { - if ( time == 0 ) { - return time; - } - return ((_timer - time) / 1000) / SECS_PER_DAY; + if ( time == 0 ) { + return time; + } + return ((_timer - time) / 1000) / SECS_PER_DAY; } uint32_t uClockClass::getNowTimer() { - return _timer; + return _timer; } - + uint32_t uClockClass::getPlayTime() { - return start_timer; + return start_timer; } - + } } // end namespace umodular::clock umodular::clock::uClockClass uClock; @@ -420,10 +420,10 @@ void ARDUINO_ISR_ATTR uclockISR() void uclockISR() #endif { - // global timer counter - _timer = millis(); - - if (uClock.state == uClock.STARTED) { - uClock.handleTimerInt(); - } + // global timer counter + _timer = millis(); + + if (uClock.state == uClock.STARTED) { + uClock.handleTimerInt(); + } } diff --git a/src/uClock.h b/src/uClock.h index 41223df..403afad 100755 --- a/src/uClock.h +++ b/src/uClock.h @@ -52,104 +52,104 @@ namespace umodular { namespace clock { class uClockClass { - private: - - float inline freqToBpm(uint32_t freq); - - void (*onClock96PPQNCallback)(uint32_t tick); - void (*onClock32PPQNCallback)(uint32_t tick); - void (*onClock16PPQNCallback)(uint32_t tick); - void (*onClockStartCallback)(); - void (*onClockStopCallback)(); - - // internal clock control - uint32_t internal_tick; - uint32_t div32th_counter; - uint32_t div16th_counter; - uint8_t mod6_counter; - - // external clock control - volatile uint32_t external_clock; - volatile uint32_t external_tick; - volatile uint32_t indiv32th_counter; - volatile uint32_t indiv16th_counter; - volatile uint8_t inmod6_counter; - volatile uint32_t interval; - uint32_t last_interval; - uint32_t sync_interval; - - float tempo; - uint32_t start_timer; - uint8_t mode; - - volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE]; - uint16_t ext_interval_idx; - - public: - - enum { - INTERNAL_CLOCK = 0, - EXTERNAL_CLOCK - }; - - enum { - PAUSED = 0, - STARTING, - STARTED - }; - - uint8_t state; - - uClockClass(); - - void setClock96PPQNOutput(void (*callback)(uint32_t tick)) { - onClock96PPQNCallback = callback; - } - - void setClock32PPQNOutput(void (*callback)(uint32_t tick)) { - onClock32PPQNCallback = callback; - } - - void setClock16PPQNOutput(void (*callback)(uint32_t tick)) { - onClock16PPQNCallback = callback; - } - - void setOnClockStartOutput(void (*callback)()) { - onClockStartCallback = callback; - } - - void setOnClockStopOutput(void (*callback)()) { - onClockStopCallback = callback; - } - - void init(); - void handleTimerInt(); - void handleExternalClock(); - void resetCounters(); - - // external class control - void start(); - void stop(); - void pause(); - void setTempo(float bpm); - float getTempo(); - - // external timming control - void setMode(uint8_t tempo_mode); - uint8_t getMode(); - void clockMe(); - - // todo! - void shuffle(); - void tap(); - - // elapsed time support - uint8_t getNumberOfSeconds(uint32_t time); - uint8_t getNumberOfMinutes(uint32_t time); - uint8_t getNumberOfHours(uint32_t time); - uint8_t getNumberOfDays(uint32_t time); - uint32_t getNowTimer(); - uint32_t getPlayTime(); + private: + + float inline freqToBpm(uint32_t freq); + + void (*onClock96PPQNCallback)(uint32_t tick); + void (*onClock32PPQNCallback)(uint32_t tick); + void (*onClock16PPQNCallback)(uint32_t tick); + void (*onClockStartCallback)(); + void (*onClockStopCallback)(); + + // internal clock control + uint32_t internal_tick; + uint32_t div32th_counter; + uint32_t div16th_counter; + uint8_t mod6_counter; + + // external clock control + volatile uint32_t external_clock; + volatile uint32_t external_tick; + volatile uint32_t indiv32th_counter; + volatile uint32_t indiv16th_counter; + volatile uint8_t inmod6_counter; + volatile uint32_t interval; + uint32_t last_interval; + uint32_t sync_interval; + + float tempo; + uint32_t start_timer; + uint8_t mode; + + volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE]; + uint16_t ext_interval_idx; + + public: + + enum { + INTERNAL_CLOCK = 0, + EXTERNAL_CLOCK + }; + + enum { + PAUSED = 0, + STARTING, + STARTED + }; + + uint8_t state; + + uClockClass(); + + void setClock96PPQNOutput(void (*callback)(uint32_t tick)) { + onClock96PPQNCallback = callback; + } + + void setClock32PPQNOutput(void (*callback)(uint32_t tick)) { + onClock32PPQNCallback = callback; + } + + void setClock16PPQNOutput(void (*callback)(uint32_t tick)) { + onClock16PPQNCallback = callback; + } + + void setOnClockStartOutput(void (*callback)()) { + onClockStartCallback = callback; + } + + void setOnClockStopOutput(void (*callback)()) { + onClockStopCallback = callback; + } + + void init(); + void handleTimerInt(); + void handleExternalClock(); + void resetCounters(); + + // external class control + void start(); + void stop(); + void pause(); + void setTempo(float bpm); + float getTempo(); + + // external timming control + void setMode(uint8_t tempo_mode); + uint8_t getMode(); + void clockMe(); + + // todo! + void shuffle(); + void tap(); + + // elapsed time support + uint8_t getNumberOfSeconds(uint32_t time); + uint8_t getNumberOfMinutes(uint32_t time); + uint8_t getNumberOfHours(uint32_t time); + uint8_t getNumberOfDays(uint32_t time); + uint32_t getNowTimer(); + uint32_t getPlayTime(); }; } } // end namespace umodular::clock @@ -157,8 +157,8 @@ class uClockClass { extern umodular::clock::uClockClass uClock; extern "C" { - extern volatile uint16_t _clock; - extern volatile uint32_t _timer; + extern volatile uint16_t _clock; + extern volatile uint32_t _timer; } #endif /* __U_CLOCK_H__ */