frac32.bipolar Clock frequency mod
frac32.bipolar Gate length mod
bool32 Enable playing
bool32 Play backwards
bool32 Play steps counting up and down
bool32 Repeat end steps for upndown mode
bool32.rising Reset to step 0 on next clock
bool32.rising Reset to step 0 immediately
int32 Step number out
bool32 Gate/clock out
bool32.pulse Step clock output
bool32.pulse Pulse when step 1 starts
frac32.u.map.ratio Gate length
int32 seqlength
frac32.s.map.lfopitch Clock frequency modulation
uint32_t start_sequence;
uint32_t first_run;
uint32_t phase;
uint32_t old_phase;
uint32_t old_reset_sync;
uint32_t old_reset_imm;
uint32_t reset_sync;
uint32_t reset_imm;
uint32_t supress_trig; // Avoid new gate on current step for stop -> run
uint32_t enforce_trig; // Ensure that we get a retrigger on reset immediate if
// pressed when gate was on
int32_t step_count;
int32_t old_step_count;
int32_t step_direction;
start_sequence = 0;
first_run = 1;
phase = 0;
old_phase = 0;
old_reset_sync = 0;
old_reset_imm = 0;
reset_sync = 0;
reset_imm = 0;
supress_trig = 0;
enforce_trig = 0;
step_count = 0;
old_step_count = 0;
step_direction = 1;
int32_t freq;
int32_t gatelength;
// Reset output pulses
outlet_clock = 0;
outlet_start = 0;
if (start_sequence < 2) {
if (inlet_reverse) {
step_count = param_seqlength - 1;
step_direction = -1;
}
start_sequence++;
}
// Catch counter reset requests, with immediate reset taking priority
if (inlet_rstimm && !old_reset_imm) {
reset_imm = 1;
} else if (inlet_rstsync && !old_reset_sync) {
reset_sync = 1;
}
old_reset_sync = inlet_rstsync;
old_reset_imm = inlet_rstimm;
if (inlet_run) {
MTOFEXTENDED(param_tempo + inlet_tempo, freq);
phase += freq >> 2;
if (first_run) {
// Need to force a start pulse the very first run, since no count will
// trigger before the seconf step
outlet_start = 1;
first_run = 0;
} else if (phase < old_phase) {
// Clock!
if (inlet_upndown) {
step_count += step_direction;
if (step_count < 0) {
step_direction = 1;
if (inlet_endrep) {
step_count = 0;
} else {
step_count = 1;
}
} else if (step_count >= param_seqlength) {
step_direction = -1;
if (inlet_endrep) {
step_count = param_seqlength - 1;
} else {
step_count = param_seqlength - 2;
}
}
} else {
step_direction = 1;
if (inlet_reverse) {
step_count--;
} else {
step_count++;
}
if (step_count < 0) {
step_count = param_seqlength - 1;
} else if (step_count >= param_seqlength) {
step_count = 0;
}
}
if (step_count == 0) {
outlet_start = 1;
}
outlet_clock = 1;
}
// Handle sequencer reset, either immediate or synchronized to next step
if (reset_imm) {
phase = 0;
reset_imm = 0;
reset_sync = 0;
enforce_trig = 1;
if (inlet_reverse) {
step_count = param_seqlength - 1;
step_direction = -1;
} else {
step_count = 0;
step_direction = 1;
}
} else if (reset_sync) {
if (phase < old_phase) {
phase = 0;
reset_imm = 0;
reset_sync = 0;
if (inlet_reverse) {
step_count = param_seqlength - 1;
step_direction = -1;
} else {
step_count = 0;
step_direction = 1;
}
}
}
// The gate length is variable from 0% to 100%
gatelength = param_gatelength + inlet_gatelength;
if (gatelength > (1 << 27)) {
gatelength = (1 << 27);
} else if (gatelength < 0) {
gatelength = 0;
}
// Handle the gate correctly for all cases
// Supressed trigger : avoids new gate on current step for stop -> run
// Enforced trigger : force a new gate on reset immediate if pressed when
// the gate was on Normal trigger : running gate pulse with variable gate
// length
if (supress_trig) {
outlet_gate = 0;
if (step_count != old_step_count) {
supress_trig = 0;
}
} else if (enforce_trig) {
outlet_gate = 0;
enforce_trig = 0;
} else {
if ((phase >> 5) > gatelength) {
outlet_gate = 0;
} else {
outlet_gate = 1;
}
}
outlet_step = step_count;
old_step_count = step_count;
old_phase = phase;
} else {
outlet_gate = 0;
outlet_step = step_count;
supress_trig = 1; // Avoid retriggering current step on stop -> run
}