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. 29
      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,11 +61,13 @@ 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
uint8_t inline processShuffle();
void (*onClock96PPQNCallback)(uint32_t tick); void (*onClock96PPQNCallback)(uint32_t tick);
void (*onClock32PPQNCallback)(uint32_t tick); void (*onClock32PPQNCallback)(uint32_t tick);
void (*onClock16PPQNCallback)(uint32_t tick); void (*onClock16PPQNCallback)(uint32_t tick);
@ -85,6 +97,11 @@ class uClockClass {
volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE]; volatile uint32_t ext_interval_buffer[EXT_INTERVAL_BUFFER_SIZE];
uint16_t ext_interval_idx; 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: public:
enum { enum {
@ -139,8 +156,16 @@ class uClockClass {
uint8_t getMode(); uint8_t getMode();
void clockMe(); 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! // todo!
void shuffle();
void tap(); void tap();
// elapsed time support // elapsed time support

Loading…
Cancel
Save