frac32 Time base input
int32.positive BPM integer
int32.positive BPM tenths
int32.positive Samples
combo clocksource
combo device
combo smooth
enum {
CLOCK_SOURCE_external = 0,
CLOCK_SOURCE_midi = 1,
CLOCK_SOURCE_midi_omni = 2
} CLOCK_SOURCE;
uint32_t sync_count;
uint32_t ktimer;
uint32_t last_ktime;
int32_t bpm_int;
int32_t bpm_tenths;
int32_t samples;
int32_t old_inlet_in;
__attribute__((always_inline)) __STATIC_INLINE int
midi_device_test(midi_device_t dev, uint8_t port, int selected_dev,
uint8_t selected_port) {
if ((selected_dev == MIDI_DEVICE_OMNI) ||
(selected_dev == dev && selected_port == port))
return 1;
return 0;
}
#if attr_smooth > 0
#define FIFO_EXP attr_smooth
#define FIFO_LEN (1 << FIFO_EXP)
#define FIFO_MASK (FIFO_LEN - 1)
typedef struct _AveragerContext {
int32_t fifo[FIFO_LEN];
int32_t fifo_i;
int32_t acc;
} AveragerContext;
AveragerContext avg;
__attribute__((always_inline)) __STATIC_INLINE int32_t
moving_average(AveragerContext *avg, int32_t new_value) {
avg->fifo_i = (avg->fifo_i + 1) & FIFO_MASK;
avg->acc -= avg->fifo[avg->fifo_i];
avg->acc += new_value;
avg->fifo[avg->fifo_i] = new_value;
return avg->acc >> FIFO_EXP;
}
#endif
void on_clock(void) {
if (sync_count < 1) {
sync_count++;
} else {
#if attr_smooth > 0
int32_t kperiod = moving_average(&avg, ktimer - last_ktime);
#else
int32_t kperiod = ktimer - last_ktime;
#endif
last_ktime = ktimer;
if (kperiod < 1) {
kperiod = 1;
}
float bpm_float = 180000.0f / kperiod;
bpm_int = bpm_float;
bpm_tenths = (bpm_float - bpm_int) * 10;
samples = kperiod * 16;
}
last_ktime = ktimer;
}
#if attr_smooth > 0
for (avg.fifo_i = 0; avg.fifo_i < FIFO_LEN; avg.fifo_i++) {
avg.fifo[avg.fifo_i] = 0;
}
avg.fifo_i = 0;
avg.acc = 0;
#endif
sync_count = 0;
ktimer = 0;
last_ktime = 0;
bpm_int = 0;
bpm_tenths = 0;
samples = 0;
old_inlet_in = 0;
if (attr_clocksource == CLOCK_SOURCE_external && inlet_in > 0 &&
old_inlet_in <= 0) {
on_clock();
}
old_inlet_in = inlet_in;
outlet_bpm = bpm_int;
outlet_dec = bpm_tenths;
outlet_samples = samples;
ktimer++;
if (attr_clocksource == CLOCK_SOURCE_midi_omni ||
(attr_clocksource == CLOCK_SOURCE_midi &&
midi_device_test(dev, port, attr_device) == 1)) {
if (status == MIDI_TIMING_CLOCK) {
on_clock();
}
}