initial support for shuffle with early and late tick setup on 16PPQN calls

pull/32/head
midilab 1 year ago
parent a89d0e70b9
commit 6f0863f247
  1. 78
      src/uClock.cpp
  2. 223
      src/uClock.h

@ -238,10 +238,43 @@ void uClockClass::tap()
// tap me // tap me
} }
// TODO: Shuffle stuff void uClockClass::setShuffle(bool active)
void uClockClass::shuffle()
{ {
// shuffle me ATOMIC(shuffle.active = active)
}
bool uClockClass::isShuffled()
{
return shuffle.active;
}
void uClockClass::setShuffleSize(uint8_t size)
{
if (size > MAX_SHUFFLE_TEMPLATE_SIZE)
size = MAX_SHUFFLE_TEMPLATE_SIZE;
ATOMIC(shuffle.size = size)
}
void uClockClass::setShuffleData(uint8_t step, int8_t tick)
{
if (step >= MAX_SHUFFLE_TEMPLATE_SIZE)
return;
ATOMIC(shuffle.step[step] = tick)
}
void uClockClass::setShuffleTemplate(int8_t * shuff, uint8_t size)
{
if (size > MAX_SHUFFLE_TEMPLATE_SIZE)
size = MAX_SHUFFLE_TEMPLATE_SIZE;
setShuffleSize(size);
for (uint8_t i=0; i < size; i++) {
setShuffleData(i, shuff[i]);
}
}
int8_t uClockClass::getShuffleLength()
{
return shuffle_length_ctrl;
} }
void uClockClass::handleExternalClock() void uClockClass::handleExternalClock()
@ -331,18 +364,17 @@ void uClockClass::handleTimerInt()
onClock96PPQNCallback(internal_tick); onClock96PPQNCallback(internal_tick);
} }
if (mod6_counter == 0) { // 16PPQN call and shuffle processing if enabled
if (onClock32PPQNCallback) { if (processShuffle() == 0) {
onClock32PPQNCallback(div32th_counter);
}
if (onClock16PPQNCallback) { if (onClock16PPQNCallback) {
onClock16PPQNCallback(div16th_counter); onClock16PPQNCallback(div16th_counter);
} }
div16th_counter++; div16th_counter++;
div32th_counter++; shuffle_shoot_ctrl = false;
} }
if (mod6_counter == 3) { // 32PPQN call. does anyone uses it?
if (mod6_counter == 3 || mod6_counter == 6) {
if (onClock32PPQNCallback) { if (onClock32PPQNCallback) {
onClock32PPQNCallback(div32th_counter); onClock32PPQNCallback(div32th_counter);
} }
@ -356,7 +388,35 @@ void uClockClass::handleTimerInt()
if (mod6_counter == 6) { if (mod6_counter == 6) {
mod6_counter = 0; mod6_counter = 0;
} }
}
uint8_t inline uClockClass::processShuffle()
{
uint8_t mod6_shuffle_counter;
if (!shuffle.active) {
mod6_shuffle_counter = mod6_counter;
} else {
// apply shuffle template to step
int8_t shff = shuffle.step[div16th_counter%shuffle.size];
// keep track of next note shuffle for current note lenght control
shuffle_length_ctrl = shuffle.step[(div16th_counter+1)%shuffle.size];
// prepare the next mod6 quantize to be called
if (shff == 0) {
mod6_shuffle_counter = mod6_counter;
shuffle_length_ctrl += shff;
} else if (shff > 0) {
if (shuffle_shoot_ctrl == false && mod6_counter > shff)
shuffle_shoot_ctrl = true;
mod6_shuffle_counter = shuffle_shoot_ctrl ? mod6_counter - shff : 1;
shuffle_length_ctrl -= shff;
} else if (shff < 0) {
if (shuffle_shoot_ctrl == false && mod6_counter == 0)
shuffle_shoot_ctrl = true;
mod6_shuffle_counter = shff - mod6_counter == -6 ? shuffle_shoot_ctrl ? 0 : 1 : 1;
shuffle_length_ctrl += shff;
}
}
return mod6_shuffle_counter;
} }
// elapsed time support // elapsed time support

@ -34,6 +34,16 @@
namespace umodular { namespace clock { namespace umodular { namespace clock {
// min: 2 step, max: 16 steps
// adjust the size of you template if more than 16 needed
// step adjust goes min: -5, max: 5
#define MAX_SHUFFLE_TEMPLATE_SIZE 16
typedef struct {
bool active;
uint8_t size = MAX_SHUFFLE_TEMPLATE_SIZE;
int8_t step[MAX_SHUFFLE_TEMPLATE_SIZE] = {0};
} SHUFFLE_TEMPLATE;
// for smooth slave tempo calculate display you should raise this value // for smooth slave tempo calculate display you should raise this value
// in between 64 to 128. // in between 64 to 128.
// note: this doesn't impact on sync time, only display time getTempo() // note: this doesn't impact on sync time, only display time getTempo()
@ -51,105 +61,120 @@ namespace umodular { namespace clock {
#define SECS_PER_DAY (SECS_PER_HOUR * 24L) #define SECS_PER_DAY (SECS_PER_HOUR * 24L)
class uClockClass { class uClockClass {
private:
private:
float inline freqToBpm(uint32_t freq);
float inline freqToBpm(uint32_t freq);
// shuffle
void (*onClock96PPQNCallback)(uint32_t tick); uint8_t inline processShuffle();
void (*onClock32PPQNCallback)(uint32_t tick);
void (*onClock16PPQNCallback)(uint32_t tick); void (*onClock96PPQNCallback)(uint32_t tick);
void (*onClockStartCallback)(); void (*onClock32PPQNCallback)(uint32_t tick);
void (*onClockStopCallback)(); void (*onClock16PPQNCallback)(uint32_t tick);
void (*onClockStartCallback)();
// internal clock control void (*onClockStopCallback)();
uint32_t internal_tick;
uint32_t div32th_counter; // internal clock control
uint32_t div16th_counter; uint32_t internal_tick;
uint8_t mod6_counter; uint32_t div32th_counter;
uint32_t div16th_counter;
// external clock control uint8_t mod6_counter;
volatile uint32_t external_clock;
volatile uint32_t external_tick; // external clock control
volatile uint32_t indiv32th_counter; volatile uint32_t external_clock;
volatile uint32_t indiv16th_counter; volatile uint32_t external_tick;
volatile uint8_t inmod6_counter; volatile uint32_t indiv32th_counter;
volatile uint32_t interval; volatile uint32_t indiv16th_counter;
uint32_t last_interval; volatile uint8_t inmod6_counter;
uint32_t sync_interval; volatile uint32_t interval;
uint32_t last_interval;
float tempo; uint32_t sync_interval;
uint32_t start_timer;
uint8_t mode; float tempo;
uint32_t start_timer;
volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE]; uint8_t mode;
uint16_t ext_interval_idx;
volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE];
public: uint16_t ext_interval_idx;
enum { // shuffle implementation that applies to 16PPQN callback
INTERNAL_CLOCK = 0, volatile SHUFFLE_TEMPLATE shuffle;
EXTERNAL_CLOCK bool shuffle_shoot_ctrl = true;
}; volatile int8_t shuffle_length_ctrl = 0;
enum { public:
PAUSED = 0,
STARTING, enum {
STARTED INTERNAL_CLOCK = 0,
}; EXTERNAL_CLOCK
};
uint8_t state;
enum {
uClockClass(); PAUSED = 0,
STARTING,
void setClock96PPQNOutput(void (*callback)(uint32_t tick)) { STARTED
onClock96PPQNCallback = callback; };
}
uint8_t state;
void setClock32PPQNOutput(void (*callback)(uint32_t tick)) {
onClock32PPQNCallback = callback; uClockClass();
}
void setClock96PPQNOutput(void (*callback)(uint32_t tick)) {
void setClock16PPQNOutput(void (*callback)(uint32_t tick)) { onClock96PPQNCallback = callback;
onClock16PPQNCallback = callback; }
}
void setClock32PPQNOutput(void (*callback)(uint32_t tick)) {
void setOnClockStartOutput(void (*callback)()) { onClock32PPQNCallback = callback;
onClockStartCallback = callback; }
}
void setClock16PPQNOutput(void (*callback)(uint32_t tick)) {
void setOnClockStopOutput(void (*callback)()) { onClock16PPQNCallback = callback;
onClockStopCallback = callback; }
}
void setOnClockStartOutput(void (*callback)()) {
void init(); onClockStartCallback = callback;
void handleTimerInt(); }
void handleExternalClock();
void resetCounters(); void setOnClockStopOutput(void (*callback)()) {
onClockStopCallback = callback;
// external class control }
void start();
void stop(); void init();
void pause(); void handleTimerInt();
void setTempo(float bpm); void handleExternalClock();
float getTempo(); void resetCounters();
// external timming control // external class control
void setMode(uint8_t tempo_mode); void start();
uint8_t getMode(); void stop();
void clockMe(); void pause();
void setTempo(float bpm);
// todo! float getTempo();
void shuffle();
void tap(); // external timming control
void setMode(uint8_t tempo_mode);
// elapsed time support uint8_t getMode();
uint8_t getNumberOfSeconds(uint32_t time); void clockMe();
uint8_t getNumberOfMinutes(uint32_t time);
uint8_t getNumberOfHours(uint32_t time); // shuffle
uint8_t getNumberOfDays(uint32_t time); void setShuffle(bool active);
uint32_t getNowTimer(); bool isShuffled();
uint32_t getPlayTime(); void setShuffleSize(uint8_t size);
void setShuffleData(uint8_t step, int8_t tick);
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);
uint8_t getNumberOfHours(uint32_t time);
uint8_t getNumberOfDays(uint32_t time);
uint32_t getNowTimer();
uint32_t getPlayTime();
}; };
} } // end namespace umodular::clock } } // end namespace umodular::clock

Loading…
Cancel
Save