Select Git revision
objgenerator.h
sequencer.c 7.02 KiB
#include "sequencer.h"
radspa_descriptor_t sequencer_desc = {
.name = "_sequencer",
.id = 56709,
.description = "sequencer that can output triggers or general control signals, best enjoyed through the "
"'sequencer' patch.\ninit_var: 1st byte (lsb): number of tracks, 2nd byte: number of steps"
"\ntable encoding (all int16_t): index 0: track type (-32767: trigger track, 32767: direct "
"track). next 'number of steps' indices: track data (repeat for number of tracks)",
.create_plugin_instance = sequencer_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define SEQUENCER_NUM_SIGNALS 7
#define SEQUENCER_STEP 0
#define SEQUENCER_SYNC_OUT 1
#define SEQUENCER_SYNC_IN 2
#define SEQUENCER_START_STEP 3
#define SEQUENCER_END_STEP 4
#define SEQUENCER_BPM 5
#define SEQUENCER_BEAT_DIV 6
// mpx'd
#define SEQUENCER_OUTPUT 7
static uint64_t target(uint64_t step_len, uint64_t bpm, uint64_t beat_div){
if(bpm == 0) return 0;
return (48000ULL * 60 * 4) / (bpm * beat_div);
}
void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_pass_id){
bool output_request = false;
sequencer_data_t * data = sequencer->plugin_data;
radspa_signal_t * track_sigs[data->num_tracks];
for(uint8_t j = 0; j < data->num_tracks; j++){
track_sigs[j] = radspa_signal_get_by_index(sequencer, SEQUENCER_OUTPUT+j);
if(track_sigs[j]->buffer != NULL) output_request = true;
}
radspa_signal_t * step_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_STEP);
if(step_sig->buffer != NULL) output_request = true;
radspa_signal_t * sync_out_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_SYNC_OUT);
if(sync_out_sig->buffer != NULL) output_request = true;
if(!output_request) return;
radspa_signal_t * sync_in_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_SYNC_IN);
radspa_signal_t * start_step_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_START_STEP);
radspa_signal_t * end_step_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_END_STEP);
radspa_signal_t * bpm_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_BPM);
radspa_signal_t * beat_div_sig = radspa_signal_get_by_index(sequencer, SEQUENCER_BEAT_DIV);
int16_t * table = sequencer->plugin_table;
int16_t s1 = radspa_signal_get_value(end_step_sig, 0, num_samples, render_pass_id);
int16_t s2 = data->track_step_len - 1;
data->step_end = s1 > 0 ? (s1 > s2 ? s2 : s1) : 1;
data->step_start = radspa_signal_get_value(start_step_sig, 0, num_samples, render_pass_id);
int16_t bpm = bpm_sig->get_value(bpm_sig, 0, num_samples, render_pass_id);
int16_t beat_div = beat_div_sig->get_value(beat_div_sig, 0, num_samples, render_pass_id);
if((bpm != data->bpm_prev) || (beat_div != data->beat_div_prev)){
data->counter_target = target(data->track_step_len, bpm, beat_div);
data->bpm_prev = bpm;
data->beat_div_prev = beat_div;
}
if(data->counter_target){
for(uint16_t i = 0; i < num_samples; i++){
data->counter++;
if(data->counter >= data->counter_target){
data->counter = 0;
data->step++;
if(data->step > data->step_end){
data->step = data->step_start;
data->sync_out = -data->sync_out;
}
}
int16_t sync_in = sync_in_sig->get_value(sync_in_sig, i, num_samples, render_pass_id);
if(((sync_in > 0) && (data->sync_in_prev <= 0)) || ((sync_in > 0) && (data->sync_in_prev <= 0))){
data->counter = 0;
data->step = data->step_start;
data->sync_out = -data->sync_out;
}
data->sync_in_prev = sync_in;
if(!data->counter){ //event just happened
for(uint8_t j = 0; j < data->num_tracks; j++){
int16_t type = table[j * (data->track_step_len + 1)];
int16_t stage_val = table[data->step + 1 + (1 + data->track_step_len) * j];
if(type == 32767){
data->tracks[j].track_fill = stage_val;
} else if(type == -32767){
if(stage_val > 0) data->tracks[j].track_fill = radspa_trigger_start(stage_val, &(data->tracks[j].trigger_hist));
if(stage_val < 0) data->tracks[j].track_fill = radspa_trigger_stop(&(data->tracks[j].trigger_hist));
}
}
}
for(uint8_t j = 0; j < data->num_tracks; j++){
if(track_sigs[j]->buffer != NULL) (track_sigs[j]->buffer)[i] = data->tracks[j].track_fill;
}
if(sync_out_sig->buffer != NULL) (sync_out_sig->buffer)[i] = data->sync_out;
if(step_sig->buffer != NULL) (step_sig->buffer)[i] = data->step;
}
}
for(uint8_t j = 0; j < data->num_tracks; j++){
track_sigs[j]->value = data->tracks[j].track_fill;
}
sync_out_sig->value = data->sync_out;
step_sig->value = data->step;
}
radspa_t * sequencer_create(uint32_t init_var){
uint32_t num_tracks = 4;
uint32_t num_pixels = 16;
if(init_var){
num_tracks = init_var & 0xFF;
num_pixels = (init_var>>8) & 0xFF;
}
if(!num_tracks) return NULL;
if(!num_pixels) return NULL;
uint32_t table_size = num_tracks * (num_pixels + 1);
uint32_t num_signals = num_tracks + SEQUENCER_NUM_SIGNALS; //one for each channel output
size_t data_size = sizeof(sequencer_data_t) + sizeof(sequencer_track_data_t) * (num_tracks - 1);
radspa_t * sequencer = radspa_standard_plugin_create(&sequencer_desc, num_signals, data_size, table_size);
if(sequencer == NULL) return NULL;
sequencer->render = sequencer_run;
sequencer_data_t * data = sequencer->plugin_data;
data->track_step_len = num_pixels;
data->num_tracks = num_tracks;
data->bpm_prev = 120;
data->beat_div_prev = 16;
data->counter_target = target(data->track_step_len, data->bpm_prev, data->beat_div_prev);
radspa_signal_set(sequencer, SEQUENCER_STEP, "step", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(sequencer, SEQUENCER_SYNC_OUT, "sync_out", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(sequencer, SEQUENCER_SYNC_IN, "sync_in", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(sequencer, SEQUENCER_START_STEP, "step_start", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(sequencer, SEQUENCER_END_STEP, "step_end", RADSPA_SIGNAL_HINT_INPUT, num_pixels-1);
radspa_signal_set(sequencer, SEQUENCER_BPM, "bpm", RADSPA_SIGNAL_HINT_INPUT, data->bpm_prev);
radspa_signal_set(sequencer, SEQUENCER_BEAT_DIV, "beat_div", RADSPA_SIGNAL_HINT_INPUT, data->beat_div_prev);
radspa_signal_set_group(sequencer, data->num_tracks, 1, SEQUENCER_OUTPUT, "track",
RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
data->counter = 0;
data->sync_in_prev = 0;
data->sync_out = 32767;
return sequencer;
}