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. 80
      src/uClock.cpp
  2. 219
      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:
float inline freqToBpm(uint32_t freq);
// shuffle
uint8_t inline processShuffle();
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;
// shuffle implementation that applies to 16PPQN callback
volatile SHUFFLE_TEMPLATE shuffle;
bool shuffle_shoot_ctrl = true;
volatile int8_t shuffle_length_ctrl = 0;
public:
enum {
INTERNAL_CLOCK = 0,
EXTERNAL_CLOCK
};
enum {
PAUSED = 0,
STARTING,
STARTED
};
uint8_t state;
uClockClass();
private: void setClock96PPQNOutput(void (*callback)(uint32_t tick)) {
onClock96PPQNCallback = callback;
float inline freqToBpm(uint32_t freq); }
void (*onClock96PPQNCallback)(uint32_t tick); void setClock32PPQNOutput(void (*callback)(uint32_t tick)) {
void (*onClock32PPQNCallback)(uint32_t tick); onClock32PPQNCallback = callback;
void (*onClock16PPQNCallback)(uint32_t tick); }
void (*onClockStartCallback)();
void (*onClockStopCallback)(); void setClock16PPQNOutput(void (*callback)(uint32_t tick)) {
onClock16PPQNCallback = callback;
// internal clock control }
uint32_t internal_tick;
uint32_t div32th_counter; void setOnClockStartOutput(void (*callback)()) {
uint32_t div16th_counter; onClockStartCallback = callback;
uint8_t mod6_counter; }
// external clock control void setOnClockStopOutput(void (*callback)()) {
volatile uint32_t external_clock; onClockStopCallback = callback;
volatile uint32_t external_tick; }
volatile uint32_t indiv32th_counter;
volatile uint32_t indiv16th_counter; void init();
volatile uint8_t inmod6_counter; void handleTimerInt();
volatile uint32_t interval; void handleExternalClock();
uint32_t last_interval; void resetCounters();
uint32_t sync_interval;
// external class control
float tempo; void start();
uint32_t start_timer; void stop();
uint8_t mode; void pause();
void setTempo(float bpm);
float getTempo();
// external timming control
void setMode(uint8_t tempo_mode);
uint8_t getMode();
void clockMe();
// shuffle
void setShuffle(bool active);
bool isShuffled();
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();
volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE]; // elapsed time support
uint16_t ext_interval_idx; uint8_t getNumberOfSeconds(uint32_t time);
uint8_t getNumberOfMinutes(uint32_t time);
public: uint8_t getNumberOfHours(uint32_t time);
uint8_t getNumberOfDays(uint32_t time);
enum { uint32_t getNowTimer();
INTERNAL_CLOCK = 0, uint32_t getPlayTime();
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 } } // end namespace umodular::clock

Loading…
Cancel
Save