diff --git a/components/bl00mbox/CMakeLists.txt b/components/bl00mbox/CMakeLists.txt index 9688b0e0fc0f85a8fa1c7bdc867c19bcaabd9a4f..997418c9d80dc95467e0f13d6bcdd5985d0745ed 100644 --- a/components/bl00mbox/CMakeLists.txt +++ b/components/bl00mbox/CMakeLists.txt @@ -20,6 +20,8 @@ idf_component_register( plugins/distortion.c plugins/lowpass.c plugins/mixer.c + plugins/range_shifter.c + plugins/poly_squeeze.c plugins/slew_rate_limiter.c plugins/bl00mbox/bl00mbox_line_in.c radspa/radspa_helpers.c diff --git a/components/bl00mbox/bl00mbox_audio.c b/components/bl00mbox/bl00mbox_audio.c index 9571af71362be1114973c981256bff34b5902cda..a14efa73bc18f5eb30bca2a3461d1269e5e901ee 100644 --- a/components/bl00mbox/bl00mbox_audio.c +++ b/components/bl00mbox/bl00mbox_audio.c @@ -133,6 +133,7 @@ void bl00mbox_channels_init(){ chan->is_active = true; chan->is_free = true; chan->name = NULL; + chan->dc = 0; } is_initialized = true; } @@ -167,81 +168,102 @@ void bl00mbox_audio_bud_render(bl00mbox_bud_t * bud){ bud->render_pass_id = render_pass_id; } -static void bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * out, bool adding){ - if(render_pass_id == chan->render_pass_id) return; +static bool bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * out, bool adding){ + if(render_pass_id == chan->render_pass_id) return false; chan->render_pass_id = render_pass_id; bl00mbox_channel_root_t * root = chan->root_list; // early exit when no sources: if((root == NULL) || (!chan->is_active)){ - if(adding) return; // nothing to do - memset(out, 0, full_buffer_len*sizeof(int16_t)); // mute - return; + return false; } - int32_t acc[256]; - bool first = true; + int32_t acc[full_buffer_len]; + bool acc_init = false; while(root != NULL){ bl00mbox_audio_bud_render(root->con->source_bud); - if(first){ - for(uint16_t i = 0; i < full_buffer_len; i++){ - acc[i] = root->con->buffer[i]; + if(root->con->buffer[1] == -32768){ + if(!acc_init){ + for(uint16_t i = 0; i < full_buffer_len; i++){ + acc[i] = root->con->buffer[0]; + } + acc_init = true; + } else if(root->con->buffer[0]){ + for(uint16_t i = 0; i < full_buffer_len; i++){ + acc[i] += root->con->buffer[0]; + } } } else { - for(uint16_t i = 0; i < full_buffer_len; i++){ // replace this with proper ladspa-style adding function someday - acc[i] += root->con->buffer[i]; + if(!acc_init){ + for(uint16_t i = 0; i < full_buffer_len; i++){ + acc[i] = root->con->buffer[i]; + } + acc_init = true; + } else { + for(uint16_t i = 0; i < full_buffer_len; i++){ + acc[i] += root->con->buffer[i]; + } } } - first = false; root = root->next; } for(uint16_t i = 0; i < full_buffer_len; i++){ - if(adding){ + chan->dc = ((chan->dc * ((1<<10) - 1)) >> 10) + acc[i]; + acc[i] = acc[i] - (chan->dc >> 10); + } + + if(adding){ + for(uint16_t i = 0; i < full_buffer_len; i++){ out[i] = radspa_add_sat(radspa_mult_shift(acc[i], chan->volume), out[i]); - } else { + } + } else { + for(uint16_t i = 0; i < full_buffer_len; i++){ out[i] = radspa_mult_shift(acc[i], chan->volume); } } + return true; } -void bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len){ - if(!is_initialized){ - memset(tx, 0, len*sizeof(int16_t)); // mute - return; - } +bool _bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len){ + if(!is_initialized) return false; bl00mbox_audio_do_pointer_change(); bl00mbox_channel_foreground = last_chan_event; - if(!bl00mbox_audio_run){ - memset(tx, 0, len*sizeof(int16_t)); // mute - return; - } + if(!bl00mbox_audio_run) return false; render_pass_id++; // fresh pass, all relevant sources must be recomputed full_buffer_len = len/2; bl00mbox_line_in_interlaced = rx; int16_t acc[full_buffer_len]; + bool acc_init = false; // system channel always runs non-adding - bl00mbox_audio_channel_render(&(channels[0]), acc, 0); + acc_init = bl00mbox_audio_channel_render(&(channels[0]), acc, acc_init) || acc_init; // re-rendering channels is ok, if render_pass_id didn't change it will just exit - bl00mbox_audio_channel_render(&(channels[bl00mbox_channel_foreground]), acc, 1); + acc_init = bl00mbox_audio_channel_render(&(channels[bl00mbox_channel_foreground]), acc, acc_init) || acc_init; // TODO: scales poorly if there's many channels #ifdef BL00MBOX_BACKGROUND_MUTE_OVERRIDE_ENABLE for(uint8_t i = 1; i < (BL00MBOX_CHANNELS); i++){ if(bl00mbox_channel_background_mute_override[i]){ - bl00mbox_audio_channel_render(&(channels[i]), acc, 1); + acc_init = bl00mbox_audio_channel_render(&(channels[i]), acc, acc_init) || acc_init; } } #endif + if(!acc_init) return false; + for(uint16_t i = 0; i < full_buffer_len; i++){ tx[2*i] = acc[i]; tx[2*i+1] = acc[i]; } + return true; +} + +void bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len){ + if(!_bl00mbox_audio_render(rx, tx, len)) memset(tx, 0, len*sizeof(int16_t)); } diff --git a/components/bl00mbox/bl00mbox_plugin_registry.c b/components/bl00mbox/bl00mbox_plugin_registry.c index 80edc3152b850274c131d25667af1d43bf23dc20..1092b3f5afc36920e25f95eb5074062dcb70ad6a 100644 --- a/components/bl00mbox/bl00mbox_plugin_registry.c +++ b/components/bl00mbox/bl00mbox_plugin_registry.c @@ -101,6 +101,8 @@ radspa_descriptor_t * bl00mbox_plugin_registry_get_id_from_index(uint32_t index) #include "mixer.h" #include "multipitch.h" #include "slew_rate_limiter.h" +#include "range_shifter.h" +#include "poly_squeeze.h" #include "bl00mbox_line_in.h" void bl00mbox_plugin_registry_init(void){ @@ -117,6 +119,8 @@ void bl00mbox_plugin_registry_init(void){ plugin_add(&noise_burst_desc); plugin_add(&distortion_desc); plugin_add(&mixer_desc); + plugin_add(&range_shifter_desc); + plugin_add(&poly_squeeze_desc); plugin_add(&slew_rate_limiter_desc); plugin_add(&multipitch_desc); plugin_add(&bl00mbox_line_in_desc); diff --git a/components/bl00mbox/bl00mbox_user.c b/components/bl00mbox/bl00mbox_user.c index 8b73670074d6ccaa1ad863e7611925cec68b1a95..8f224860bb2b4bf6e2c106af3149cc9bd057156b 100644 --- a/components/bl00mbox/bl00mbox_user.c +++ b/components/bl00mbox/bl00mbox_user.c @@ -704,7 +704,11 @@ bool bl00mbox_channel_bud_set_signal_value(uint8_t channel, uint32_t bud_index, radspa_signal_t * sig = bl00mbox_signal_get_by_index(bud->plugin, bud_signal_index); if(sig == NULL) return false; - sig->value = value; + if(value == -32678){ + sig->value = 0; + } else { + sig->value = value; + } bl00mbox_channel_event(channel); return true; } diff --git a/components/bl00mbox/include/bl00mbox.h b/components/bl00mbox/include/bl00mbox.h index 9dd3f1c1ae442ad30f5ca9798f3c51d41b3d681e..8a57cf28469decf67d45b0f52868372d6b514f78 100644 --- a/components/bl00mbox/include/bl00mbox.h +++ b/components/bl00mbox/include/bl00mbox.h @@ -8,9 +8,5 @@ uint16_t bl00mbox_sources_count(); uint16_t bl00mbox_source_add(void* render_data, void* render_function); void bl00mbox_source_remove(uint16_t index); -void bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len); - -// TEMP -void bl00mbox_player_function(int16_t * rx, int16_t * tx, uint16_t len); - +bool bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len); void bl00mbox_init(void); diff --git a/components/bl00mbox/include/bl00mbox_audio.h b/components/bl00mbox/include/bl00mbox_audio.h index 38008c6502a4e2cab86c9caac3e136bd72f1f474..8f5112baa22636bafa876c4093f3a0e733495126 100644 --- a/components/bl00mbox/include/bl00mbox_audio.h +++ b/components/bl00mbox/include/bl00mbox_audio.h @@ -55,6 +55,7 @@ typedef struct{ bool is_free; char * name; int32_t volume; + int32_t dc; struct _bl00mbox_channel_root_t * root_list; // list of all roots associated with channels uint32_t render_pass_id; // may be used by host to determine whether recomputation is necessary struct _bl00mbox_bud_t * buds; // linked list with all channel buds diff --git a/components/bl00mbox/plugins/env_adsr.c b/components/bl00mbox/plugins/env_adsr.c index 4e1c9e18d81c1d1b86d52e8ed560d076d0eb8c48..3e31630028ec360feda6fdc472aed212247b50ec 100644 --- a/components/bl00mbox/plugins/env_adsr.c +++ b/components/bl00mbox/plugins/env_adsr.c @@ -8,16 +8,15 @@ radspa_descriptor_t env_adsr_desc = { .destroy_plugin_instance = radspa_standard_plugin_destroy }; -#define ENV_ADSR_NUM_SIGNALS 9 +#define ENV_ADSR_NUM_SIGNALS 8 #define ENV_ADSR_OUTPUT 0 -#define ENV_ADSR_PHASE 1 -#define ENV_ADSR_INPUT 2 -#define ENV_ADSR_TRIGGER 3 -#define ENV_ADSR_ATTACK 4 -#define ENV_ADSR_DECAY 5 -#define ENV_ADSR_SUSTAIN 6 -#define ENV_ADSR_RELEASE 7 -#define ENV_ADSR_GATE 8 +#define ENV_ADSR_INPUT 1 +#define ENV_ADSR_TRIGGER 2 +#define ENV_ADSR_ATTACK 3 +#define ENV_ADSR_DECAY 4 +#define ENV_ADSR_SUSTAIN 5 +#define ENV_ADSR_RELEASE 6 +#define ENV_ADSR_GAIN 7 #define ENV_ADSR_PHASE_OFF 0 #define ENV_ADSR_PHASE_ATTACK 1 @@ -29,14 +28,13 @@ radspa_t * env_adsr_create(uint32_t init_var){ radspa_t * env_adsr = radspa_standard_plugin_create(&env_adsr_desc, ENV_ADSR_NUM_SIGNALS, sizeof(env_adsr_data_t),0); env_adsr->render = env_adsr_run; radspa_signal_set(env_adsr, ENV_ADSR_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0); - radspa_signal_set(env_adsr, ENV_ADSR_PHASE, "phase", RADSPA_SIGNAL_HINT_OUTPUT, 0); radspa_signal_set(env_adsr, ENV_ADSR_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 32767); radspa_signal_set(env_adsr, ENV_ADSR_TRIGGER, "trigger", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0); radspa_signal_set(env_adsr, ENV_ADSR_ATTACK, "attack", RADSPA_SIGNAL_HINT_INPUT, 100); radspa_signal_set(env_adsr, ENV_ADSR_DECAY, "decay", RADSPA_SIGNAL_HINT_INPUT, 250); radspa_signal_set(env_adsr, ENV_ADSR_SUSTAIN, "sustain", RADSPA_SIGNAL_HINT_INPUT, 16000); radspa_signal_set(env_adsr, ENV_ADSR_RELEASE, "release", RADSPA_SIGNAL_HINT_INPUT, 50); - radspa_signal_set(env_adsr, ENV_ADSR_GATE, "gate", RADSPA_SIGNAL_HINT_INPUT,0); + radspa_signal_set(env_adsr, ENV_ADSR_GAIN, "gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN, RADSPA_SIGNAL_VAL_UNITY_GAIN); radspa_signal_get_by_index(env_adsr, ENV_ADSR_ATTACK)->unit = "ms"; radspa_signal_get_by_index(env_adsr, ENV_ADSR_DECAY)->unit = "ms"; radspa_signal_get_by_index(env_adsr, ENV_ADSR_SUSTAIN)->unit = "ms"; @@ -44,177 +42,131 @@ radspa_t * env_adsr_create(uint32_t init_var){ env_adsr_data_t * data = env_adsr->plugin_data; data->trigger_prev = 0; data->env_phase = ENV_ADSR_PHASE_OFF; + data->release_prev_ms = -1; + data->release_init_val_prev = -1; + data->attack_prev_ms = -1; + data->sustain_prev = -1; + data->decay_prev_ms = -1; return env_adsr; } -static int16_t env_adsr_run_single(env_adsr_data_t * env){ - uint32_t tmp; - switch(env->env_phase){ - case ENV_ADSR_PHASE_OFF: - env->env_counter = 0;; - break; - case ENV_ADSR_PHASE_ATTACK: - tmp = env->env_counter + env->attack; - if(tmp < env->env_counter){ // overflow - tmp = ~((uint32_t) 0); // max out - env->env_phase = ENV_ADSR_PHASE_DECAY; - } - env->env_counter = tmp; - break; - case ENV_ADSR_PHASE_DECAY: - tmp = env->env_counter - env->decay; - if(tmp > env->env_counter){ // underflow - tmp = 0; //bottom out - } - env->env_counter = tmp; - - if(env->env_counter <= env->sustain){ - env->env_counter = env->sustain; - env->env_phase = ENV_ADSR_PHASE_SUSTAIN; - } else if(env->env_counter < env->gate){ - env->env_counter = 0; - env->env_phase = ENV_ADSR_PHASE_OFF; - } - break; - case ENV_ADSR_PHASE_SUSTAIN: - if(env->sustain == 0) env->env_phase = ENV_ADSR_PHASE_OFF; - env->env_counter = env->sustain; - break; - case ENV_ADSR_PHASE_RELEASE: - tmp = env->env_counter - env->release; - if(tmp > env->env_counter){ // underflow - tmp = 0; //bottom out - env->env_phase = ENV_ADSR_PHASE_OFF; - } - env->env_counter = tmp; - /* - if(env->env_counter < env->gate){ - env->env_counter = 0; - env->env_phase = ENV_ADSR_PHASE_OFF; - } - */ - break; - } - return env->env_counter >> 17; -} - #define SAMPLE_RATE_SORRY 48000 #define ENV_ADSR_UNDERSAMPLING 5 -static inline uint32_t env_adsr_time_ms_to_val_rise(uint16_t time_ms, uint32_t val){ +static inline uint32_t env_adsr_time_ms_to_val_rise(int16_t time_ms, uint32_t val, uint16_t leftshift){ if(!time_ms) return UINT32_MAX; + if(time_ms < 0) time_ms = -time_ms; uint32_t div = time_ms * ((SAMPLE_RATE_SORRY)/1000); - return val/div; + uint32_t input = val/div; + if(!leftshift) return input; // nothing to do + if(input >> (32-leftshift)) return UINT32_MAX; // sat + return input << leftshift; } -static inline uint32_t uint32_sat_leftshift(uint32_t input, uint16_t left){ - if(!left) return input; // nothing to do - if(input >> (32-left)) return UINT32_MAX; // sat - return input << left; -} - - void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){ - env_adsr_data_t * plugin_data = env_adsr->plugin_data; + env_adsr_data_t * data = env_adsr->plugin_data; radspa_signal_t * output_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_OUTPUT); - radspa_signal_t * phase_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_PHASE); - if((output_sig->buffer == NULL) && (phase_sig->buffer == NULL)) return; - radspa_signal_t * trigger_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_TRIGGER); + if(output_sig->buffer == NULL) return; radspa_signal_t * input_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_INPUT); - radspa_signal_t * attack_sig = NULL; - radspa_signal_t * decay_sig = NULL; - radspa_signal_t * sustain_sig = NULL; - radspa_signal_t * release_sig = NULL; - radspa_signal_t * gate_sig = NULL; + radspa_signal_t * trigger_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_TRIGGER); + radspa_signal_t * attack_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_ATTACK); + radspa_signal_t * decay_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_DECAY); + radspa_signal_t * sustain_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_SUSTAIN); + radspa_signal_t * release_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_RELEASE); + radspa_signal_t * gain_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_GAIN); int16_t env = 0; for(uint16_t i = 0; i < num_samples; i++){ int16_t ret = 0; int16_t trigger = radspa_signal_get_value(trigger_sig, i, render_pass_id); - int16_t vel = radspa_trigger_get(trigger, &(plugin_data->trigger_prev)); + int16_t vel = radspa_trigger_get(trigger, &(data->trigger_prev)); if(vel < 0){ // stop - if(plugin_data->env_phase != ENV_ADSR_PHASE_OFF){ - plugin_data->env_phase = ENV_ADSR_PHASE_RELEASE; - plugin_data->release_init_val = plugin_data->env_counter; + if(data->env_phase != ENV_ADSR_PHASE_OFF){ + data->env_phase = ENV_ADSR_PHASE_RELEASE; + data->release_init_val = data->env_counter; } } else if(vel > 0 ){ // start - plugin_data->env_phase = ENV_ADSR_PHASE_ATTACK; - plugin_data->velocity = ((uint32_t) vel) << 17; + data->env_phase = ENV_ADSR_PHASE_ATTACK; + data->velocity = vel; } if(!(i%(1<<ENV_ADSR_UNDERSAMPLING))){ - uint16_t time_ms; - uint32_t sus; - switch(plugin_data->env_phase){ + uint32_t tmp; + int16_t time_ms; + switch(data->env_phase){ case ENV_ADSR_PHASE_OFF: + data->env_counter = 0;; break; case ENV_ADSR_PHASE_ATTACK: - if(attack_sig == NULL){ - attack_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_ATTACK); - } time_ms = radspa_signal_get_value(attack_sig, i, render_pass_id); - if(time_ms != plugin_data->attack_prev_ms){ - plugin_data->attack = uint32_sat_leftshift(env_adsr_time_ms_to_val_rise(time_ms, UINT32_MAX), ENV_ADSR_UNDERSAMPLING); - plugin_data->attack_prev_ms = time_ms; + if(data->attack_prev_ms != time_ms){ + data->attack_raw = env_adsr_time_ms_to_val_rise(time_ms, UINT32_MAX, ENV_ADSR_UNDERSAMPLING); + data->attack_prev_ms = time_ms; } + + tmp = data->env_counter + data->attack_raw; + if(tmp < data->env_counter){ // overflow + tmp = ~((uint32_t) 0); // max out + data->env_phase = ENV_ADSR_PHASE_DECAY; + } + data->env_counter = tmp; break; case ENV_ADSR_PHASE_DECAY: - if(sustain_sig == NULL){ - sustain_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_SUSTAIN); + data->sustain = radspa_signal_get_value(sustain_sig, i, render_pass_id) << 17UL; + time_ms = radspa_signal_get_value(decay_sig, i, render_pass_id); + if((data->decay_prev_ms != time_ms) || (data->sustain_prev != data->sustain)){ + data->decay_raw = env_adsr_time_ms_to_val_rise(time_ms, UINT32_MAX - data->sustain, ENV_ADSR_UNDERSAMPLING); + data->decay_prev_ms = time_ms; + data->sustain_prev = data->sustain; } - sus = radspa_signal_get_value(sustain_sig, i, render_pass_id); - plugin_data->sustain = sus<<17; - - if(gate_sig == NULL){ - gate_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_GATE); + tmp = data->env_counter - data->decay_raw; + if(tmp > data->env_counter){ // underflow + tmp = 0; //bottom out } - sus = radspa_signal_get_value(gate_sig, i, render_pass_id); - plugin_data->gate = sus<<17; - if(decay_sig == NULL){ - decay_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_DECAY); - } - time_ms = radspa_signal_get_value(decay_sig, i, render_pass_id); - if(time_ms != plugin_data->decay_prev_ms){ - plugin_data->decay = uint32_sat_leftshift(env_adsr_time_ms_to_val_rise(time_ms, UINT32_MAX-plugin_data->sustain), ENV_ADSR_UNDERSAMPLING); - plugin_data->decay_prev_ms = time_ms; + if(tmp <= data->sustain){ + tmp = data->sustain; + data->env_phase = ENV_ADSR_PHASE_SUSTAIN; } + + data->env_counter = tmp; + break; case ENV_ADSR_PHASE_SUSTAIN: - if(sustain_sig == NULL){ - sustain_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_SUSTAIN); - } - sus = radspa_signal_get_value(sustain_sig, i, render_pass_id); - plugin_data->sustain = sus<<17; + data->sustain = radspa_signal_get_value(sustain_sig, i, render_pass_id) << 17UL; + if(data->sustain == 0) data->env_phase = ENV_ADSR_PHASE_OFF; + data->env_counter = data->sustain; break; case ENV_ADSR_PHASE_RELEASE: - if(gate_sig == NULL){ - gate_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_GATE); - } - sus = radspa_signal_get_value(gate_sig, i, render_pass_id); - plugin_data->gate = sus<<17; - - if(release_sig == NULL){ - release_sig = radspa_signal_get_by_index(env_adsr, ENV_ADSR_RELEASE); - } time_ms = radspa_signal_get_value(release_sig, i, render_pass_id); - if(time_ms != plugin_data->release_prev_ms){ - plugin_data->release = uint32_sat_leftshift(env_adsr_time_ms_to_val_rise(time_ms, plugin_data->release_init_val), ENV_ADSR_UNDERSAMPLING); - plugin_data->release_prev_ms = time_ms; + if((data->release_prev_ms != time_ms) || (data->release_init_val_prev != data->release_init_val)){ + data->release_raw = env_adsr_time_ms_to_val_rise(time_ms, data->release_init_val, ENV_ADSR_UNDERSAMPLING); + data->release_prev_ms = time_ms; + data->release_init_val_prev = data->release_init_val;; + } + tmp = data->env_counter - data->release_raw; + if(tmp > data->env_counter){ // underflow + tmp = 0; //bottom out + data->env_phase = ENV_ADSR_PHASE_OFF; } + data->env_counter = tmp; break; } - env = env_adsr_run_single(plugin_data); + env = data->env_counter >> 17; + env = (env * (env + 1)) >> 15; + + int32_t gain = radspa_signal_get_value(gain_sig, i, render_pass_id); + env = (env * gain) >> 12; + env = (env * data->velocity) >> 15; } if(env){ int16_t input = radspa_signal_get_value(input_sig, i, render_pass_id); ret = radspa_mult_shift(env, input); } - radspa_signal_set_value(phase_sig, i, plugin_data->env_phase); radspa_signal_set_value(output_sig, i, ret); } } diff --git a/components/bl00mbox/plugins/env_adsr.h b/components/bl00mbox/plugins/env_adsr.h index c2d9534514d9934d095e4668df8e89d3517fb2c1..fae0313f10b96db7ee05a2524c0fb7f33c435b02 100644 --- a/components/bl00mbox/plugins/env_adsr.h +++ b/components/bl00mbox/plugins/env_adsr.h @@ -4,19 +4,19 @@ typedef struct { uint32_t env_counter; - uint32_t attack; - uint32_t decay; + int16_t attack_prev_ms; + uint32_t attack_raw; + int16_t decay_prev_ms; + uint32_t decay_raw; uint32_t sustain; - uint32_t release; + uint32_t sustain_prev; + int16_t release_prev_ms; + uint32_t release_raw; uint32_t release_init_val; - uint16_t attack_prev_ms; - uint16_t decay_prev_ms; - uint16_t release_prev_ms; - uint32_t gate; - uint32_t velocity; - uint8_t env_phase; - uint8_t skip_hold; + uint32_t release_init_val_prev; + int16_t velocity; int16_t trigger_prev; + uint8_t env_phase; } env_adsr_data_t; extern radspa_descriptor_t env_adsr_desc; diff --git a/components/bl00mbox/plugins/mixer.c b/components/bl00mbox/plugins/mixer.c index d77064e01c95f49b8ed2f91adeb51d36800fdba8..a7e74b4c7b385acb0cbed74b651683ace5804466 100644 --- a/components/bl00mbox/plugins/mixer.c +++ b/components/bl00mbox/plugins/mixer.c @@ -19,8 +19,6 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ input_sigs[i] = radspa_signal_get_by_index(mixer, 2 + i); } - int32_t * dc_acc = mixer->plugin_data; - static int32_t ret = 0; for(uint16_t i = 0; i < num_samples; i++){ int16_t gain = radspa_signal_get_value(gain_sig, i, render_pass_id); @@ -28,9 +26,6 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ for(uint8_t j = 0; j < num_inputs; j++){ ret += radspa_signal_get_value(input_sigs[j], i, render_pass_id); } - // remove dc - (* dc_acc) = (ret + (* dc_acc)*1023) >> 10; - ret -= (* dc_acc); ret = radspa_clip(radspa_gain(ret, gain)); radspa_signal_set_value(output_sig, i, ret); } @@ -39,14 +34,12 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ radspa_t * mixer_create(uint32_t init_var){ if(init_var == 0) init_var = 4; if(init_var > 127) init_var = 127; - radspa_t * mixer = radspa_standard_plugin_create(&mixer_desc, 2 + init_var, sizeof(int32_t), 0); + radspa_t * mixer = radspa_standard_plugin_create(&mixer_desc, 2 + init_var, 0, 0); if(mixer == NULL) return NULL; mixer->render = mixer_run; radspa_signal_set(mixer, 0, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0); int16_t gain = RADSPA_SIGNAL_VAL_UNITY_GAIN/init_var; radspa_signal_set(mixer, 1, "gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN, gain); radspa_signal_set_group(mixer, init_var, 1, 2, "input", RADSPA_SIGNAL_HINT_INPUT, 0); - int32_t * dc_acc = mixer->plugin_data; - (* dc_acc) = 0; return mixer; } diff --git a/components/bl00mbox/plugins/osc_fm.c b/components/bl00mbox/plugins/osc_fm.c index a05bec085424055bf1a66ddc25b0eda10e6c8a00..b78610497a21cb22e960e16ac76880a5d7fbdae1 100644 --- a/components/bl00mbox/plugins/osc_fm.c +++ b/components/bl00mbox/plugins/osc_fm.c @@ -1,7 +1,5 @@ #include "osc_fm.h" -static inline int16_t waveshaper(int16_t saw, int16_t shape); - radspa_descriptor_t osc_fm_desc = { .name = "osc_fm", .id = 420, @@ -10,11 +8,13 @@ radspa_descriptor_t osc_fm_desc = { .destroy_plugin_instance = radspa_standard_plugin_destroy }; -#define OSC_FM_NUM_SIGNALS 4 +#define OSC_FM_NUM_SIGNALS 6 #define OSC_FM_OUTPUT 0 #define OSC_FM_PITCH 1 #define OSC_FM_WAVEFORM 2 #define OSC_FM_LIN_FM 3 +#define OSC_FM_PITCH_THRU 4 +#define OSC_FM_PITCH_OFFSET 5 radspa_t * osc_fm_create(uint32_t init_var){ radspa_t * osc_fm = radspa_standard_plugin_create(&osc_fm_desc, OSC_FM_NUM_SIGNALS, sizeof(osc_fm_data_t), 0); @@ -23,46 +23,16 @@ radspa_t * osc_fm_create(uint32_t init_var){ radspa_signal_set(osc_fm, OSC_FM_PITCH, "pitch", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, 18367); radspa_signal_set(osc_fm, OSC_FM_WAVEFORM, "waveform", RADSPA_SIGNAL_HINT_INPUT, -16000); radspa_signal_set(osc_fm, OSC_FM_LIN_FM, "lin_fm", RADSPA_SIGNAL_HINT_INPUT, 0); + radspa_signal_set(osc_fm, OSC_FM_PITCH_THRU, "fm_pitch_thru", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT, 18367); + radspa_signal_set(osc_fm, OSC_FM_PITCH_OFFSET, "fm_pitch_offset", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, 18367); return osc_fm; } -void osc_fm_run(radspa_t * osc_fm, uint16_t num_samples, uint32_t render_pass_id){ - osc_fm_data_t * plugin_data = osc_fm->plugin_data; - radspa_signal_t * output_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_OUTPUT); - radspa_signal_t * pitch_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH); - radspa_signal_t * waveform_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_WAVEFORM); - radspa_signal_t * lin_fm_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_LIN_FM); - if(output_sig->buffer == NULL) return; - - int16_t ret = 0; - for(uint16_t i = 0; i < num_samples; i++){ - int16_t pitch = radspa_signal_get_value(pitch_sig, i, render_pass_id); - int16_t wave = radspa_signal_get_value(waveform_sig, i, render_pass_id); - int32_t lin_fm = radspa_signal_get_value(lin_fm_sig, i, render_pass_id); - - if(pitch != plugin_data->prev_pitch){ - plugin_data->incr = radspa_sct_to_rel_freq(pitch, 0); - plugin_data->prev_pitch = pitch; - } - plugin_data->counter += plugin_data->incr; - if(lin_fm){ - plugin_data->counter += lin_fm * (plugin_data->incr >> 15); - } - - int32_t tmp = (plugin_data->counter) >> 17; - tmp = (tmp*2) - 32767; - ret = waveshaper(tmp, wave); - radspa_signal_set_value(output_sig, i, ret); - } -} - -static inline int16_t triangle(int16_t saw){ - int32_t tmp = saw; - tmp += 16384; - if(tmp > 32767) tmp -= 65535; - if(tmp > 0) tmp = -tmp; - tmp = (2 * tmp) + 32767; - return tmp; +static inline int16_t triangle(int32_t saw){ + saw -= 16384; + if(saw < -32767) saw += 65535; + if(saw > 0) saw = -saw; + return saw * 2 + 32767; } static inline int16_t waveshaper(int16_t saw, int16_t shape){ @@ -75,11 +45,11 @@ static inline int16_t waveshaper(int16_t saw, int16_t shape){ if(tmp > 0){ tmp = 32767 - tmp; tmp = (tmp*tmp)>>15; - tmp = 32767. - tmp; + tmp = 32767 - tmp; } else { tmp = 32767 + tmp; tmp = (tmp*tmp)>>15; - tmp = tmp - 32767.; + tmp = tmp - 32767; } break; case 1: //tri @@ -97,3 +67,46 @@ static inline int16_t waveshaper(int16_t saw, int16_t shape){ } return tmp; } + +void osc_fm_run(radspa_t * osc_fm, uint16_t num_samples, uint32_t render_pass_id){ + osc_fm_data_t * plugin_data = osc_fm->plugin_data; + radspa_signal_t * output_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_OUTPUT); + radspa_signal_t * pitch_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH); + radspa_signal_t * waveform_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_WAVEFORM); + radspa_signal_t * lin_fm_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_LIN_FM); + + radspa_signal_t * fm_pitch_thru_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH_THRU); + if(fm_pitch_thru_sig->buffer != NULL){ + radspa_signal_t * fm_pitch_offset_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH_OFFSET); + int32_t thru_acc = 0; + for(uint16_t i = 0; i < num_samples; i++){ + thru_acc = radspa_signal_get_value(pitch_sig, i, render_pass_id); + thru_acc += radspa_signal_get_value(fm_pitch_offset_sig, i, render_pass_id); + thru_acc = radspa_clip(thru_acc); + radspa_signal_set_value(fm_pitch_thru_sig, i, thru_acc); + } + }; + + if(output_sig->buffer == NULL) return; + + int16_t ret = 0; + for(uint16_t i = 0; i < num_samples; i++){ + int16_t pitch = radspa_signal_get_value(pitch_sig, i, render_pass_id); + int16_t wave = radspa_signal_get_value(waveform_sig, i, render_pass_id); + int32_t lin_fm = radspa_signal_get_value(lin_fm_sig, i, render_pass_id); + + if(pitch != plugin_data->prev_pitch){ + plugin_data->incr = radspa_sct_to_rel_freq(pitch, 0); + plugin_data->prev_pitch = pitch; + } + plugin_data->counter += plugin_data->incr; + if(lin_fm){ + plugin_data->counter += lin_fm * (plugin_data->incr >> 15); + } + + int32_t tmp = (plugin_data->counter) >> 16; + tmp = tmp - 32767; + ret = waveshaper(tmp, wave); + radspa_signal_set_value(output_sig, i, ret); + } +} diff --git a/components/bl00mbox/plugins/poly_squeeze.c b/components/bl00mbox/plugins/poly_squeeze.c new file mode 100644 index 0000000000000000000000000000000000000000..2d23836a5c5cc429da2f53f7dce57bb633d3f779 --- /dev/null +++ b/components/bl00mbox/plugins/poly_squeeze.c @@ -0,0 +1,245 @@ +#include "poly_squeeze.h" + +radspa_descriptor_t poly_squeeze_desc = { + .name = "poly_squeeze", + .id = 172, + .description = "Multiplexes a number of triggerand pitch inputs into a lesser number of trigger pitch output pairs. " + "The latest triggered inputs are forwarded to the output. If such an input receives a stop trigger it is disconnected " + "from its output. If another inputs is in triggered state but not forwarded at the same time it will be connected to that " + "output and the output is triggered. Pitch is constantly streamed to the outputs if they are connected, else the last " + "connected value is being held." + "\ninit_var: lsb: number of outputs, 1..16, default 3; lsb+1: number of inputs, <lsb>..32, default 10; ", + .create_plugin_instance = poly_squeeze_create, + .destroy_plugin_instance = radspa_standard_plugin_destroy +}; + + +// mpx block 1 +#define POLY_SQUEEZE_TRIGGER_INPUT 0 +#define POLY_SQUEEZE_PITCH_INPUT 1 +// mpx block 2 +#define POLY_SQUEEZE_TRIGGER_OUTPUT 0 +#define POLY_SQUEEZE_PITCH_OUTPUT 1 + +static void assign_note_voices(poly_squeeze_data_t * data){ + poly_squeeze_note_t * note = data->active_notes_top; + if(note == NULL) return; + uint32_t active_voices = 0xFFFFFFFFUL << data->num_voices; + + for(uint8_t i = 0; i < data->num_voices; i++){ + if(note == NULL) break; + if(note->voice >= 0) active_voices = active_voices | (1UL<<note->voice); + note = note->lower; + } + while(note != NULL){ + note->voice = -1; + note = note->lower; + } + + if(active_voices == UINT32_MAX) return; + + note = data->active_notes_top; + for(uint8_t i = 0; i < data->num_voices; i++){ + if(note == NULL) break; + if(note->voice < 0){ + int8_t voice = -1; + for(int8_t v = 0; v < data->num_voices; v++){ + if((~active_voices) & (1<<v)){ + active_voices = active_voices | (1<<v); + voice = v; + break; + } + + } + note->voice = voice; + } + note = note->lower; + } +} + +static poly_squeeze_note_t * get_note_with_voice(poly_squeeze_data_t * data, int8_t voice){ + poly_squeeze_note_t * note = data->active_notes_top; + for(uint8_t i = 0; i < data->num_voices; i++){ + if(note == NULL) break; + if(note->voice == voice) return note; + note = note->lower; + } + return NULL; +} + +void take_note(poly_squeeze_data_t * data, poly_squeeze_note_t * note){ + if(note == NULL) return; + if(data->free_notes == note) data->free_notes = note->lower; + if(data->active_notes_bottom == note) data->active_notes_bottom = note->higher; + if(data->active_notes_top == note) data->active_notes_top = note->lower; + if(note->higher != NULL) note->higher->lower = note->lower; + if(note->lower != NULL) note->lower->higher = note->higher; + note->higher = NULL; + note->lower = NULL; +} + +static int8_t put_note_on_top(poly_squeeze_data_t * data, poly_squeeze_note_t * note){ + if(note == NULL) return -1; + if(note == data->active_notes_top) return note->voice; + take_note(data, note); + note->lower = data->active_notes_top; + if(note->lower != NULL) note->lower->higher = note; + data->active_notes_top = note; + + if(note->lower == NULL) data->active_notes_bottom = note; + assign_note_voices(data); + return note->voice; +} + +static int8_t free_note(poly_squeeze_data_t * data, poly_squeeze_note_t * note){ + if(note == NULL) return -1; + take_note(data, note); + int8_t ret = note->voice; + note->voice = -1; + note->lower = data->free_notes; + if(note->lower != NULL) note->lower->higher = note; + data->free_notes = note; + assign_note_voices(data); + return ret; +} + +static void voice_start(poly_squeeze_voice_t * voice, int16_t pitch, int16_t vol){ + voice->pitch_out = pitch; + int16_t tmp = voice->_start_trigger; + radspa_trigger_start(vol, &tmp); + voice->trigger_out = tmp; +} + +static void voice_stop(poly_squeeze_voice_t * voice){ + int16_t tmp = voice->_start_trigger; + radspa_trigger_stop(&tmp); + voice->trigger_out = tmp; +} + +void poly_squeeze_run(radspa_t * poly_squeeze, uint16_t num_samples, uint32_t render_pass_id){ + poly_squeeze_data_t * data = poly_squeeze->plugin_data; + poly_squeeze_note_t * notes = (void *) (&(data[1])); + poly_squeeze_input_t * inputs = (void *) (&(notes[data->num_notes])); + poly_squeeze_voice_t * voices = (void *) (&(inputs[data->num_inputs])); + + radspa_signal_t * trigger_input_sigs[data->num_inputs]; + radspa_signal_t * pitch_input_sigs[data->num_inputs]; + radspa_signal_t * trigger_output_sigs[data->num_voices]; + radspa_signal_t * pitch_output_sigs[data->num_voices]; + + for(uint8_t j = 0; j < data->num_inputs; j++){ + trigger_input_sigs[j] = radspa_signal_get_by_index(poly_squeeze, POLY_SQUEEZE_TRIGGER_INPUT + 2*j); + pitch_input_sigs[j] = radspa_signal_get_by_index(poly_squeeze, POLY_SQUEEZE_PITCH_INPUT + 2*j); + } + for(uint8_t j = 0; j < data->num_voices; j++){ + trigger_output_sigs[j] = radspa_signal_get_by_index(poly_squeeze, POLY_SQUEEZE_TRIGGER_OUTPUT + 2*(data->num_inputs+j)); + pitch_output_sigs[j] = radspa_signal_get_by_index(poly_squeeze, POLY_SQUEEZE_PITCH_OUTPUT + 2*(data->num_inputs+j)); + } + + for(uint16_t i = 0; i < num_samples; i++){ + for(uint8_t j = 0; j < data->num_inputs; j++){ + notes[j].pitch = radspa_signal_get_value(pitch_input_sigs[j], i, render_pass_id); + int16_t trigger_in = radspa_trigger_get(radspa_signal_get_value(trigger_input_sigs[j], i, render_pass_id), + &(inputs[j].trigger_in_hist)); + + if(trigger_in > 0){ + notes[j].vol = trigger_in; + int8_t voice = put_note_on_top(data, &(notes[j])); + if(voice >= 0) voice_start(&(voices[voice]), notes[j].pitch, notes[j].vol); + } else if(trigger_in < 0){ + int8_t voice = free_note(data, &(notes[j])); + if(voice >= 0){ + poly_squeeze_note_t * note = get_note_with_voice(data, voice); + if(note == NULL){ + voice_stop(&(voices[voice])); + } else { + voice_start(&(voices[voice]), note->pitch, note->vol); + } + } + } + } + for(uint8_t j = 0; j < data->num_inputs; j++){ + if((notes[j].voice != -1) && (notes[j].voice < data->num_voices)){ + voices[notes[j].voice].pitch_out = notes[j].pitch; + } + } + for(uint8_t j = 0; j < data->num_voices; j++){ + radspa_signal_set_value_check_const(trigger_output_sigs[j], i, voices[j].trigger_out); + radspa_signal_set_value_check_const(pitch_output_sigs[j], i, voices[j].pitch_out); + voices[j]._start_trigger = voices[j].trigger_out; + } + } +} + +radspa_t * poly_squeeze_create(uint32_t init_var){ + if(!init_var) init_var = 3 + (1UL<<8) + 9 * (1UL<<16); + uint8_t num_voices = init_var & 0xFF; + if(num_voices > 32) num_voices = 32; + if(num_voices < 1) num_voices = 1; + + init_var = init_var >> 8; + uint8_t num_inputs = init_var & 0xFF; + if(num_inputs > 32) num_inputs = 32; + if(num_inputs < num_voices) num_inputs = num_voices; + + uint8_t num_notes = num_inputs; + + uint32_t num_signals = num_voices * 2 + num_inputs * 2; + size_t data_size = sizeof(poly_squeeze_data_t); + data_size += sizeof(poly_squeeze_voice_t) * num_voices; + data_size += sizeof(poly_squeeze_note_t) * num_notes; + data_size += sizeof(poly_squeeze_input_t) * num_inputs; + radspa_t * poly_squeeze = radspa_standard_plugin_create(&poly_squeeze_desc, num_signals, data_size, 0); + if(poly_squeeze == NULL) return NULL; + + poly_squeeze->render = poly_squeeze_run; + + radspa_signal_set_group(poly_squeeze, num_inputs, 2, POLY_SQUEEZE_TRIGGER_INPUT, "trigger_in", + RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0); + radspa_signal_set_group(poly_squeeze, num_inputs, 2, POLY_SQUEEZE_PITCH_INPUT, "pitch_in", + RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440); + radspa_signal_set_group(poly_squeeze, num_voices, 2, POLY_SQUEEZE_TRIGGER_OUTPUT + 2*num_inputs, "trigger_out", + RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0); + radspa_signal_set_group(poly_squeeze, num_voices, 2, POLY_SQUEEZE_PITCH_OUTPUT + 2*num_inputs, "pitch_out", + RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440); + + poly_squeeze_data_t * data = poly_squeeze->plugin_data; + data->num_voices = num_voices; + data->num_notes = num_notes; + data->num_inputs = num_inputs; + + poly_squeeze_note_t * notes = (void *) (&(data[1])); + poly_squeeze_input_t * inputs = (void *) (&(notes[data->num_notes])); + poly_squeeze_voice_t * voices = (void *) (&(inputs[data->num_inputs])); + + data->active_notes_top = NULL; + data->active_notes_bottom = NULL; + data->free_notes = &(notes[0]); + + for(uint8_t i = 0; i < num_voices; i++){ + voices[i].trigger_out = 0; + voices[i].pitch_out = RADSPA_SIGNAL_VAL_SCT_A440; + voices[i]._start_trigger = voices[i].trigger_out; + } + + for(uint8_t i = 0; i < num_notes; i++){ + notes[i].pitch = -32768; + notes[i].voice = -1; + if(i){ + notes[i].higher = &(notes[i-1]); + } else{ + notes[i].higher = NULL; + } + if(i != (num_notes - 1)){ + notes[i].lower = &(notes[i+1]); + } else { + notes[i].lower = NULL; + } + } + + for(uint8_t i = 0; i < num_inputs; i++){ + inputs[i].trigger_in_hist = 0; + } + + return poly_squeeze; +} diff --git a/components/bl00mbox/plugins/poly_squeeze.h b/components/bl00mbox/plugins/poly_squeeze.h new file mode 100644 index 0000000000000000000000000000000000000000..40f954d3cfc25f6b34a17a19fc716eac477eccf9 --- /dev/null +++ b/components/bl00mbox/plugins/poly_squeeze.h @@ -0,0 +1,34 @@ +#pragma once +#include "radspa.h" +#include "radspa_helpers.h" + +typedef struct _poly_squeeze_note_t { + int16_t pitch; + int16_t vol; + int8_t voice; + struct _poly_squeeze_note_t * lower; + struct _poly_squeeze_note_t * higher; +} poly_squeeze_note_t; + +typedef struct { + int16_t trigger_out; + int16_t pitch_out; + int16_t _start_trigger; +} poly_squeeze_voice_t; + +typedef struct { + int16_t trigger_in_hist; +} poly_squeeze_input_t; + +typedef struct { + uint8_t num_voices; + uint8_t num_notes; + uint8_t num_inputs; + poly_squeeze_note_t * active_notes_top; + poly_squeeze_note_t * active_notes_bottom; + poly_squeeze_note_t * free_notes; +} poly_squeeze_data_t; + +extern radspa_descriptor_t poly_squeeze_desc; +radspa_t * poly_squeeze_create(uint32_t init_var); +void poly_squeeze_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); diff --git a/components/bl00mbox/plugins/range_shifter.c b/components/bl00mbox/plugins/range_shifter.c new file mode 100644 index 0000000000000000000000000000000000000000..baf57c6842bedf37c078e5727aabf62b48d2f339 --- /dev/null +++ b/components/bl00mbox/plugins/range_shifter.c @@ -0,0 +1,76 @@ +#include "range_shifter.h" + +radspa_t * range_shifter_create(uint32_t init_var); +radspa_descriptor_t range_shifter_desc = { + .name = "range_shifter", + .id = 68, + .description = "saturating multiplication and addition", + .create_plugin_instance = range_shifter_create, + .destroy_plugin_instance = radspa_standard_plugin_destroy +}; + +#define RANGE_SHIFTER_NUM_SIGNALS 6 +#define RANGE_SHIFTER_OUTPUT 0 +#define RANGE_SHIFTER_INPUT 1 +#define RANGE_SHIFTER_OUTPUT_A 2 +#define RANGE_SHIFTER_OUTPUT_B 3 +#define RANGE_SHIFTER_INPUT_A 2 +#define RANGE_SHIFTER_INPUT_B 3 + +void range_shifter_run(radspa_t * range_shifter, uint16_t num_samples, uint32_t render_pass_id){ + radspa_signal_t * output_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT); + if(output_sig->buffer == NULL) return; + radspa_signal_t * input_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_INPUT); + int32_t output_a = radspa_signal_get_value(radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT_A), 0, render_pass_id); + int32_t output_b = radspa_signal_get_value(radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT_B), 0, render_pass_id); + int32_t input_a = radspa_signal_get_value(radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_INPUT_A), 0, render_pass_id); + int32_t input_b = radspa_signal_get_value(radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_INPUT_B), 0, render_pass_id); + int32_t output_span = output_b - output_a; + if(!output_span){ + for(uint16_t i = 0; i < num_samples; i++){ + radspa_signal_set_value(output_sig, i, output_a); + } + return; + } + int32_t input_span = input_b - input_a; + if(!input_span){ + int32_t avg = (output_b - output_a)/2; + for(uint16_t i = 0; i < num_samples; i++){ + radspa_signal_set_value(output_sig, i, avg); + } + return; + } + int32_t gain = (output_span << 14) / input_span; + + for(uint16_t i = 0; i < num_samples; i++){ + int32_t ret = radspa_signal_get_value(input_sig, i, render_pass_id); + if(ret == input_a){ + ret = output_a; + } else if(ret == input_b){ + ret = output_b; + } else { + ret -= input_a; + ret = (ret * gain) >> 14; + ret += output_a; + if(ret > 32767){ + ret = 32767; + } else if(ret < -32767){ + ret = -32767; + } + } + radspa_signal_set_value(output_sig, i, ret); + } +} + +radspa_t * range_shifter_create(uint32_t init_var){ + radspa_t * range_shifter = radspa_standard_plugin_create(&range_shifter_desc, RANGE_SHIFTER_NUM_SIGNALS, sizeof(char), 0); + if(range_shifter == NULL) return NULL; + range_shifter->render = range_shifter_run; + radspa_signal_set(range_shifter, RANGE_SHIFTER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0); + radspa_signal_set(range_shifter, RANGE_SHIFTER_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 0); + radspa_signal_set(range_shifter, RANGE_SHIFTER_OUTPUT_A, "output_a", RADSPA_SIGNAL_HINT_INPUT, -32767); + radspa_signal_set(range_shifter, RANGE_SHIFTER_OUTPUT_B, "output_b", RADSPA_SIGNAL_HINT_INPUT, 32767); + radspa_signal_set(range_shifter, RANGE_SHIFTER_INPUT_A, "input_a", RADSPA_SIGNAL_HINT_INPUT, -32767); + radspa_signal_set(range_shifter, RANGE_SHIFTER_INPUT_B, "input_b", RADSPA_SIGNAL_HINT_INPUT, 32767); + return range_shifter; +} diff --git a/components/bl00mbox/plugins/range_shifter.h b/components/bl00mbox/plugins/range_shifter.h new file mode 100644 index 0000000000000000000000000000000000000000..254099f8a2a0be8e175429c1be9fc07e20e55299 --- /dev/null +++ b/components/bl00mbox/plugins/range_shifter.h @@ -0,0 +1,7 @@ +#pragma once +#include <radspa.h> +#include <radspa_helpers.h> + +extern radspa_descriptor_t range_shifter_desc; +radspa_t * range_shifter_create(uint32_t init_var); +void range_shifter_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); diff --git a/components/bl00mbox/plugins/sampler.c b/components/bl00mbox/plugins/sampler.c index e2627c54d6e9b68093db834adc34080875a0dbc2..3de9e4349e8877bf2e3a500be25259ddd9c47a81 100644 --- a/components/bl00mbox/plugins/sampler.c +++ b/components/bl00mbox/plugins/sampler.c @@ -14,8 +14,8 @@ radspa_descriptor_t sampler_desc = { #define SAMPLER_NUM_SIGNALS 5 #define SAMPLER_OUTPUT 0 #define SAMPLER_TRIGGER 1 -#define SAMPLER_REC_IN 2 -#define SAMPLER_REC_TRIGGER 3 +#define SAMPLER_REC_TRIGGER 2 +#define SAMPLER_REC_IN 3 #define SAMPLER_PITCH_SHIFT 4 #define READ_HEAD_POS 0 @@ -27,52 +27,60 @@ radspa_descriptor_t sampler_desc = { void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(sampler, SAMPLER_OUTPUT); if(output_sig->buffer == NULL) return; + sampler_data_t * data = sampler->plugin_data; int16_t * buf = sampler->plugin_table; uint32_t * buf32 = (uint32_t *) buf; + data->read_head_pos = buf32[READ_HEAD_POS/2]; + uint32_t sample_len = buf32[SAMPLE_LEN/2]; + uint32_t buffer_size = sampler->plugin_table_len - BUFFER_OFFSET; + if(sample_len >= buffer_size) sample_len = buffer_size - 1; + if(data->read_head_pos >= buffer_size) data->read_head_pos = buffer_size - 1; + radspa_signal_t * trigger_sig = radspa_signal_get_by_index(sampler, SAMPLER_TRIGGER); - radspa_signal_t * rec_in_sig = radspa_signal_get_by_index(sampler, SAMPLER_REC_IN); radspa_signal_t * rec_trigger_sig = radspa_signal_get_by_index(sampler, SAMPLER_REC_TRIGGER); - radspa_signal_t * pitch_shift_sig = radspa_signal_get_by_index(sampler, SAMPLER_PITCH_SHIFT); - static int32_t ret = 0; - - uint32_t buffer_size = sampler->plugin_table_len - BUFFER_OFFSET; + int16_t trigger_const = radspa_signal_get_const_value(trigger_sig, render_pass_id); + int16_t rec_trigger_const = radspa_signal_get_const_value(rec_trigger_sig, render_pass_id); + + bool output_mute = (data->read_head_pos >= sample_len); + if( output_mute && (!data->rec_active) && (trigger_const == data->trigger_prev) && (rec_trigger_const == data->rec_trigger_prev)){ + radspa_signal_set_const_value(output_sig, 0); + return; + } - data->read_head_pos = buf32[READ_HEAD_POS/2]; uint32_t sample_start = buf32[SAMPLE_START/2]; - uint32_t sample_len = buf32[SAMPLE_LEN/2]; uint32_t sample_rate = buf32[SAMPLE_RATE/2]; + radspa_signal_t * rec_in_sig = radspa_signal_get_by_index(sampler, SAMPLER_REC_IN); + radspa_signal_t * pitch_shift_sig = radspa_signal_get_by_index(sampler, SAMPLER_PITCH_SHIFT); + if(sample_start >= buffer_size) sample_start = buffer_size - 1; - if(sample_len >= buffer_size) sample_len = buffer_size - 1; - if(data->read_head_pos >= buffer_size) data->read_head_pos = buffer_size - 1; - bool buffer_all_zeroes = true; for(uint16_t i = 0; i < num_samples; i++){ - int16_t trigger = radspa_trigger_get(radspa_signal_get_value(trigger_sig, i, render_pass_id), &(data->trigger_prev)); - int16_t rec_trigger = radspa_trigger_get(radspa_signal_get_value(rec_trigger_sig, i, render_pass_id), &(data->rec_trigger_prev)); - - if(rec_trigger > 0){ - if(!(data->rec_active)){ - data->read_head_pos = sample_len; - data->write_head_pos = 0; - data->write_head_pos_long = 0; - sample_len = 0; - data->rec_active = true; - } - } else if(rec_trigger < 0){ - if(data->rec_active){ - if(sample_len == buffer_size){ - sample_start = data->write_head_pos; - } else { - sample_start = 0; + int32_t ret; + if((rec_trigger_const == -32768) || (!i)){ + int16_t rec_trigger = radspa_trigger_get(radspa_signal_get_value(rec_trigger_sig, i, render_pass_id), &(data->rec_trigger_prev)); + if(rec_trigger > 0){ + if(!(data->rec_active)){ + data->read_head_pos = sample_len; + data->write_head_pos = 0; + data->write_head_pos_long = 0; + sample_len = 0; + data->rec_active = true; + } + } else if(rec_trigger < 0){ + if(data->rec_active){ + if(sample_len == buffer_size){ + sample_start = data->write_head_pos; + } else { + sample_start = 0; + } + buf[8] = 1; + data->rec_active = false; } - buf[8] = 1; - data->rec_active = false; } } - if(data->rec_active){ int16_t rec_in = radspa_signal_get_value(rec_in_sig, i, render_pass_id); @@ -93,12 +101,21 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ buf32[SAMPLE_LEN] = sample_len; } } else { - if(trigger > 0){ - data->read_head_pos_long = 0; - data->read_head_pos = 0; - data->volume = trigger; - } else if(trigger < 0){ - data->read_head_pos = sample_len; + if((trigger_const == -32768) || (!i)){ + int16_t trigger = radspa_trigger_get(radspa_signal_get_value(trigger_sig, i, render_pass_id), &(data->trigger_prev)); + if(trigger > 0){ + data->read_head_pos_long = 0; + data->read_head_pos = 0; + data->volume = trigger; + if(output_mute){ + for(uint8_t j = 0; j < i; j++){ + radspa_signal_set_value(output_sig, j, 0); + } + output_mute = false; + } + } else if(trigger < 0){ + data->read_head_pos = sample_len; + } } @@ -106,6 +123,7 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ uint32_t sample_offset_pos = data->read_head_pos + sample_start; if(sample_offset_pos >= sample_len) sample_offset_pos -= sample_len; ret = radspa_mult_shift(buf[sample_offset_pos + BUFFER_OFFSET], data->volume); + radspa_signal_set_value(output_sig, i, ret); int32_t pitch_shift = radspa_signal_get_value(pitch_shift_sig, i, render_pass_id); if(pitch_shift != data->pitch_shift_prev){ @@ -122,17 +140,13 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ data->read_head_pos_long += (sample_rate * data->pitch_shift_mult) >> 11; data->read_head_pos = (data->read_head_pos_long * 699) >> 25; // equiv to _/48000 (acc 0.008%) } - } else { - if(data->buffer_all_zeroes) continue; - //ret = (ret * 255)>>8; // avoid dc clicks with bad samples - ret = 0; + } else if(!output_mute){ + radspa_signal_set_value(output_sig, i, 0); } - if(ret) buffer_all_zeroes = false; - radspa_signal_set_value(output_sig, i, ret); } } - data->buffer_all_zeroes = buffer_all_zeroes; + if(output_mute) radspa_signal_set_const_value(output_sig, 0); buf32[READ_HEAD_POS/2] = data->read_head_pos; buf32[SAMPLE_START/2] = sample_start; buf32[SAMPLE_LEN/2] = sample_len; diff --git a/components/bl00mbox/plugins/sequencer.c b/components/bl00mbox/plugins/sequencer.c index 3bf2bab82892b119f7e6555e58481f2205666d94..083e43d66cff3b63090af2bccc24509d76a45e56 100644 --- a/components/bl00mbox/plugins/sequencer.c +++ b/components/bl00mbox/plugins/sequencer.c @@ -31,18 +31,13 @@ static uint64_t target(uint64_t step_len, uint64_t bpm, uint64_t 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; + sequencer_track_data_t * tracks = (void *) (&data[1]); 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); @@ -50,6 +45,12 @@ void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_p 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); + 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; + } + if(!output_request) return; + int16_t * table = sequencer->plugin_table; int16_t s1 = radspa_signal_get_value(end_step_sig, 0, render_pass_id); @@ -59,6 +60,7 @@ void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_p int16_t bpm = radspa_signal_get_value(bpm_sig, 0, render_pass_id); int16_t beat_div = radspa_signal_get_value(beat_div_sig, 0, 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->is_stopped = data->counter_target ? false : true; @@ -99,22 +101,29 @@ void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_p 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((!tracks[j].changed) && (tracks[j].stage_val_prev != stage_val)){ + tracks[j].changed = true; + tracks[j].stage_val_prev = stage_val; + for(uint16_t k = 0; k < i; k++){ + radspa_signal_set_value(track_sigs[j], k, tracks[j].track_fill); + } + } if(type == 32767){ - data->tracks[j].track_fill = stage_val; + 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)); + if(stage_val > 0){ + radspa_trigger_start(stage_val, &(tracks[j].track_fill)); + } else if(stage_val < 0){ + radspa_trigger_stop(&(tracks[j].track_fill)); + } } + tracks[j].stage_val_prev = stage_val; } } - - } else { - for(uint8_t j = 0; j < data->num_tracks; j++){ - data->tracks[j].track_fill = radspa_trigger_stop(&(data->tracks[j].trigger_hist)); - } } + for(uint8_t j = 0; j < data->num_tracks; j++){ - radspa_signal_set_value(track_sigs[j], i, data->tracks[j].track_fill); + if(tracks[j].changed) radspa_signal_set_value(track_sigs[j], i, tracks[j].track_fill); } int16_t sync_out = 0; @@ -124,30 +133,37 @@ void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_p sync_out = radspa_trigger_stop(&(data->sync_out_hist)); } radspa_signal_set_value(sync_out_sig, i, sync_out); - radspa_signal_set_value(step_sig, i, data->step); } + for(uint8_t j = 0; j < data->num_tracks; j++){ + if(!tracks[j].changed){ + radspa_signal_set_const_value(track_sigs[j], tracks[j].track_fill); + } else { + tracks[j].changed = false; + } + } + radspa_signal_set_const_value(step_sig, data->step); } radspa_t * sequencer_create(uint32_t init_var){ uint32_t num_tracks = 4; - uint32_t num_pixels = 16; + uint32_t num_steps = 16; if(init_var){ num_tracks = init_var & 0xFF; - num_pixels = (init_var>>8) & 0xFF; + num_steps = (init_var>>8) & 0xFF; } if(!num_tracks) return NULL; - if(!num_pixels) return NULL; + if(!num_steps) return NULL; - uint32_t table_size = num_tracks * (num_pixels + 1); + uint32_t table_size = num_tracks * (num_steps + 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); + size_t data_size = sizeof(sequencer_data_t) + sizeof(sequencer_track_data_t) * num_tracks; 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->track_step_len = num_steps; data->num_tracks = num_tracks; data->bpm_prev = 120; data->beat_div_prev = 16; @@ -156,7 +172,7 @@ radspa_t * sequencer_create(uint32_t init_var){ 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_END_STEP, "step_end", RADSPA_SIGNAL_HINT_INPUT, num_steps-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", @@ -168,6 +184,12 @@ radspa_t * sequencer_create(uint32_t init_var){ data->sync_out_start = false; data->sync_out_stop = false; data->is_stopped = false; + sequencer_track_data_t * tracks = (void *) (&data[1]); + for(uint8_t j = 0; j < data->num_tracks; j++){ + tracks[j].changed = false; + tracks[j].track_fill = 0; + tracks[j].stage_val_prev = 0; + } return sequencer; } diff --git a/components/bl00mbox/plugins/sequencer.h b/components/bl00mbox/plugins/sequencer.h index 970a86f8499b19d5d7dee5015bc98bd6554b6df7..4d53c4f9d5a047680802d094b24c668aa66ddcc0 100644 --- a/components/bl00mbox/plugins/sequencer.h +++ b/components/bl00mbox/plugins/sequencer.h @@ -5,7 +5,8 @@ typedef struct { int16_t track_fill; - int16_t trigger_hist; + int16_t stage_val_prev; + bool changed; } sequencer_track_data_t; typedef struct { @@ -23,7 +24,6 @@ typedef struct { bool is_stopped; int16_t bpm_prev; int16_t beat_div_prev; - sequencer_track_data_t tracks[]; } sequencer_data_t; diff --git a/components/bl00mbox/radspa/radspa.h b/components/bl00mbox/radspa/radspa.h index 80c66ddca7034dae04f50d7938068e3f623e0fb0..c3af2f5114de8897811ec5483fb1350c799df2e9 100644 --- a/components/bl00mbox/radspa/radspa.h +++ b/components/bl00mbox/radspa/radspa.h @@ -81,6 +81,7 @@ typedef struct _radspa_signal_t{ int16_t * buffer; // static value to be used when buffer is NULL for input signals only int16_t value; + // when the signal has last requested to render its source uint32_t render_pass_id; // linked list pointer struct _radspa_signal_t * next; @@ -124,27 +125,28 @@ inline int32_t radspa_mult_shift(int32_t a, int32_t b){ return radspa_clip((a*b) inline int32_t radspa_gain(int32_t a, int32_t b){ return radspa_clip((a*b)>>12); } inline int16_t radspa_trigger_start(int16_t velocity, int16_t * hist){ - int16_t ret = ((* hist) > 0) ? -velocity : velocity; - (* hist) = ret; - return ret; + if(!velocity) velocity = 1; + if(velocity == -32768) velocity = 1; + if(velocity < 0) velocity = -velocity; + (* hist) = ((* hist) > 0) ? -velocity : velocity; + return * hist; } inline int16_t radspa_trigger_stop(int16_t * hist){ (* hist) = 0; - return 0; + return * hist; } inline int16_t radspa_trigger_get(int16_t trigger_signal, int16_t * hist){ - int16_t ret = 0; - if((!trigger_signal) && (* hist)){ //stop - ret = -1; - } else if(trigger_signal > 0 ){ - if((* hist) <= 0) ret = trigger_signal; + if((* hist) == trigger_signal) return 0; + (* hist) = trigger_signal; + if(!trigger_signal){ + return -1; } else if(trigger_signal < 0 ){ - if((* hist) >= 0) ret = -trigger_signal; + return -trigger_signal; + } else { + return trigger_signal; } - (* hist) = trigger_signal; - return ret; } /* REQUIREMENTS diff --git a/components/bl00mbox/radspa/radspa_helpers.c b/components/bl00mbox/radspa/radspa_helpers.c index c95e1bde462932a8b134461cce2ae70781c34147..e584935bfbb3e88ea0d3a8542809cfe9fae0fc6c 100644 --- a/components/bl00mbox/radspa/radspa_helpers.c +++ b/components/bl00mbox/radspa/radspa_helpers.c @@ -2,7 +2,10 @@ #include "radspa_helpers.h" extern inline int16_t radspa_signal_get_value(radspa_signal_t * sig, int16_t index, uint32_t render_pass_id); -extern inline void radspa_signal_set_value(radspa_signal_t * sig, int16_t index, int16_t value); +extern inline int16_t radspa_signal_get_const_value(radspa_signal_t * sig, uint32_t render_pass_id); +extern inline void radspa_signal_set_value(radspa_signal_t * sig, int16_t index, int32_t value); +extern inline void radspa_signal_set_value_check_const(radspa_signal_t * sig, int16_t index, int32_t value); +extern inline void radspa_signal_set_const_value(radspa_signal_t * sig, int32_t value); extern inline int16_t radspa_clip(int32_t a); extern inline int16_t radspa_add_sat(int32_t a, int32_t b); extern inline int32_t radspa_mult_shift(int32_t a, int32_t b); diff --git a/components/bl00mbox/radspa/radspa_helpers.h b/components/bl00mbox/radspa/radspa_helpers.h index 86a08ee4841b9396b167cccb6fe14c00a58b9720..ff3a912d128e659095191a4118dcd30183a7365d 100644 --- a/components/bl00mbox/radspa/radspa_helpers.h +++ b/components/bl00mbox/radspa/radspa_helpers.h @@ -29,15 +29,55 @@ inline int16_t radspa_signal_get_value(radspa_signal_t * sig, int16_t index, uin radspa_host_request_buffer_render(sig->buffer); sig->render_pass_id = render_pass_id; } + if(sig->buffer[1] == -32768) return sig->buffer[0]; return sig->buffer[index]; + } + return sig->value; +} + +inline void radspa_signal_set_value(radspa_signal_t * sig, int16_t index, int32_t val){ + if(sig->buffer != NULL){ + sig->buffer[index] = radspa_clip(val); + } else if(!index){ + sig->value = radspa_clip(val); + } +} + +inline void radspa_signal_set_value_check_const(radspa_signal_t * sig, int16_t index, int32_t val){ + if(sig->buffer == NULL){ + if(!index) sig->value = radspa_clip(val); + return; + } + val = radspa_clip(val); + if(index == 0){ + sig->buffer[0] = val; + } else if(index == 1){ + if(val == sig->buffer[0]) sig->buffer[1] = -32768; + } else { + if((sig->buffer[1] == -32768) && (val != sig->buffer[0])) sig->buffer[1] = sig->buffer[0]; + sig->buffer[index] = val; + } +} + +inline void radspa_signal_set_const_value(radspa_signal_t * sig, int32_t val){ + if(sig->buffer == NULL){ + sig->value = radspa_clip(val); } else { - return sig->value; + sig->buffer[0] = radspa_clip(val); + sig->buffer[1] = -32768; } } -inline void radspa_signal_set_value(radspa_signal_t * sig, int16_t index, int16_t val){ - if(sig->buffer != NULL) sig->buffer[index] = val; - if(!index) sig->value = val; +inline int16_t radspa_signal_get_const_value(radspa_signal_t * sig, uint32_t render_pass_id){ + if(sig->buffer != NULL){ + if(sig->render_pass_id != render_pass_id){ + radspa_host_request_buffer_render(sig->buffer); + sig->render_pass_id = render_pass_id; + } + if(sig->buffer[1] == -32768) return sig->buffer[0]; + return -32768; + } + return sig->value; } // get signal struct from a signal index diff --git a/components/micropython/usermodule/mp_sys_bl00mbox.c b/components/micropython/usermodule/mp_sys_bl00mbox.c index 79a1f19a308433375d33719660b2aa873d9edf25..05dc7837bf2feb21a039892343bfd55cbcdae737 100644 --- a/components/micropython/usermodule/mp_sys_bl00mbox.c +++ b/components/micropython/usermodule/mp_sys_bl00mbox.c @@ -68,7 +68,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_get_free_obj, mp_channel_get_free); static mp_obj_t mp_channel_set_free(mp_obj_t index, mp_obj_t free) { return mp_obj_new_int( bl00mbox_channel_set_free(mp_obj_get_int(index), mp_obj_is_true(free))); - return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_channel_set_free_obj, mp_channel_set_free); diff --git a/python_payload/bl00mbox/_user.py b/python_payload/bl00mbox/_user.py index b48c5017f6dd7108b3bca91dd9b9b029bec51a90..06b76a8f7b843722d54bf06237bfc35a107ebede 100644 --- a/python_payload/bl00mbox/_user.py +++ b/python_payload/bl00mbox/_user.py @@ -73,11 +73,9 @@ class Signal: self._name = sys_bl00mbox.channel_bud_get_signal_name( plugin.channel_num, plugin.bud_num, signal_num ) - mpx = sys_bl00mbox.channel_bud_get_signal_name_multiplex( + self._mpx = sys_bl00mbox.channel_bud_get_signal_name_multiplex( plugin.channel_num, plugin.bud_num, signal_num ) - if mpx != (-1): - self._name += str(mpx) self._description = sys_bl00mbox.channel_bud_get_signal_description( plugin.channel_num, plugin.bud_num, signal_num ) @@ -96,6 +94,8 @@ class Signal: self._plugin._check_existence() ret = self.name + if self._mpx != -1: + ret += "[" + str(self._mpx) + "]" if len(self.unit): ret += " [" + self.unit + "]" ret += " [" + self.hints + "]: " @@ -132,8 +132,11 @@ class Signal: if isinstance(self, SignalPitchMixin): ret += " / " + str(self.tone) + " semitones / " + str(self.freq) + "Hz" - if isinstance(self, SignalVolumeMixin): - ret += " / " + str(self.dB) + "dB / x" + str(self.mult) + if isinstance(self, SignalGainMixin): + if self.mult == 0: + ret += " / (mute)" + else: + ret += " / " + str(self.dB) + "dB / x" + str(self.mult) return ret @@ -164,6 +167,57 @@ class Signal: self._plugin.channel_num, self._plugin.bud_num, self._signal_num ) + @property + def _tone(self): + return (self.value - (32767 - 2400 * 6)) / 200 + + @_tone.setter + def _tone(self, val): + if isinstance(self, SignalInput): + if (type(val) == int) or (type(val) == float): + self.value = (32767 - 2400 * 6) + 200 * val + if type(val) == str: + self.value = helpers.note_name_to_sct(val) + else: + raise AttributeError("can't set output signal") + + @property + def _freq(self): + tone = (self.value - (32767 - 2400 * 6)) / 200 + return 440 * (2 ** (tone / 12)) + + @_freq.setter + def _freq(self, val): + if isinstance(self, SignalInput): + tone = 12 * math.log(val / 440, 2) + self.value = (32767 - 2400 * 6) + 200 * tone + else: + raise AttributeError("can't set output signal") + + @property + def _dB(self): + if self.value == 0: + return -9999 + return 20 * math.log((abs(self.value) / 4096), 10) + + @_dB.setter + def _dB(self, val): + if isinstance(self, SignalInput): + self.value = int(4096 * (10 ** (val / 20))) + else: + raise AttributeError("can't set output signal") + + @property + def _mult(self): + return self.value / 4096 + + @_mult.setter + def _mult(self, val): + if isinstance(self, SignalInput): + self.value = int(4096 * val) + else: + raise AttributeError("can't set output signal") + class SignalOutput(Signal): @Signal.value.setter @@ -245,70 +299,128 @@ class SignalInput(Signal): cons += [_makeSignal(Plugin(Channel(chan), 0, bud_num=b), s)] return cons - -class SignalTriggerMixin: - def start(self, velocity=32767): + def _start(self, velocity=32767): if self.value > 0: - self.value = -velocity + self.value = -abs(velocity) else: - self.value = velocity + self.value = abs(velocity) - def stop(self): + def _stop(self): self.value = 0 +class SignalInputTriggerMixin: + def start(self, velocity=32767): + self._start(velocity) + + def stop(self): + self._stop() + class SignalPitchMixin: @property def tone(self): - return (self.value - (32767 - 2400 * 6)) / 200 + return self._tone @tone.setter def tone(self, val): - if (type(val) == int) or (type(val) == float): - self.value = (32767 - 2400 * 6) + 200 * val - if type(val) == str: - self.value = helpers.note_name_to_sct(val) + self._tone = val @property def freq(self): - tone = (self.value - (32767 - 2400 * 6)) / 200 - return 440 * (2 ** (tone / 12)) + return self._freq @freq.setter def freq(self, val): - tone = 12 * math.log(val / 440, 2) - self.value = (32767 - 2400 * 6) + 200 * tone + self._freq = val -class SignalVolumeMixin: +class SignalGainMixin: @property def dB(self): - return 20 * math.log((self.value / 4096), 10) + return self._dB @dB.setter def dB(self, val): - self.value = int(4096 * (10 ** (val / 20))) + self._dB = val @property def mult(self): - return self.value / 4096 + return self._mult @mult.setter def mult(self, val): - self.value = int(4096 * val) + self._mult = val -class SignalInputTrigger(SignalInput, SignalTriggerMixin): +class SignalOutputTrigger(SignalOutput): pass +class SignalOutputPitch(SignalOutput, SignalPitchMixin): + pass -class SignalInputPitch(SignalInput, SignalPitchMixin): +class SignalOutputGain(SignalOutput, SignalGainMixin): + pass + +class SignalInputTrigger(SignalInput, SignalInputTriggerMixin): pass +class SignalInputPitch(SignalInput, SignalPitchMixin): + pass -class SignalInputVolume(SignalInput, SignalVolumeMixin): +class SignalInputGain(SignalInput, SignalGainMixin): pass +class SignalMpxList: + def __init__(self): + self._list = [] + self._setattr_allowed = False + + def __len__(self): + return len(self._list) + + def __getitem__(self, index): + return self._list[index] + + def __setitem__(self, index, value): + try: + current_value = self._list[index] + except: + raise AttributeError("index does not exist") + if isinstance(current_value, Signal): + current_value.value = value + else: + raise AttributeError("signal does not exist") + + def __iter__(self): + self._iter_index = 0 + return self + + def __next__(self): + self._iter_index += 1; + if self._iter_index >= len(self._list): + raise StopIteration + else: + return self._list[self._iter_index] + + def add_new_signal(self, signal, index): + self._setattr_allowed = True + index = int(index) + if len(self._list) <= index: + self._list += [None] * (1 + index - len(self._list)) + self._list[index] = signal + self._setattr_allowed = False + + def __setattr__(self, key, value): + """ + current_value = getattr(self, key, None) + if isinstance(current_value, Signal): + current_value.value = value + return + """ + if key == "_setattr_allowed" or getattr(self, "_setattr_allowed", True): + super().__setattr__(key, value) + else: + raise AttributeError("signal does not exist") class SignalList: def __init__(self, plugin): @@ -319,31 +431,58 @@ class SignalList: hints = sys_bl00mbox.channel_bud_get_signal_hints( plugin.channel_num, plugin.bud_num, signal_num ) - if hints & 2: - signal = SignalOutput(plugin, signal_num) - signal._hints = "output" - elif hints & 1: - if hints & 4: + if hints & 4: + if hints & 1: signal = SignalInputTrigger(plugin, signal_num) signal._hints = "input/trigger" - elif hints & 32: + elif hints & 2: + signal = SignalOutputTrigger(plugin, signal_num) + signal._hints = "output/trigger" + elif hints & 32: + if hints & 1: signal = SignalInputPitch(plugin, signal_num) signal._hints = "input/pitch" - elif hints & 8: - signal = SignalInputVolume(plugin, signal_num) - signal._hints = "input/volume" - else: + elif hints & 2: + signal = SignalOutputPitch(plugin, signal_num) + signal._hints = "output/pitch" + elif hints & 8: + if hints & 1: + signal = SignalInputGain(plugin, signal_num) + signal._hints = "input/gain" + elif hints & 2: + signal = SignalOutputGain(plugin, signal_num) + signal._hints = "input/gain" + else: + if hints & 1: signal = SignalInput(plugin, signal_num) signal._hints = "input" + elif hints & 2: + signal = SignalOutput(plugin, signal_num) + signal._hints = "output" self._list += [signal] - setattr(self, signal.name.split(" ")[0], signal) + name = signal.name.split(" ")[0] + if signal._mpx == -1: + setattr(self, name, signal) + else: + # <LEGACY SUPPORT> + setattr(self, name + str(signal._mpx), signal) + # </LEGACY SUPPORT> + current_list = getattr(self, name, None) + if not isinstance(current_list, SignalMpxList): + setattr(self, name, SignalMpxList()) + getattr(self, name, None).add_new_signal(signal, signal._mpx) + self._setattr_allowed = False + def __setattr__(self, key, value): current_value = getattr(self, key, None) if isinstance(current_value, Signal): current_value.value = value return - super().__setattr__(key, value) + elif getattr(self, "_setattr_allowed", True): + super().__setattr__(key, value) + else: + raise AttributeError("signal does not exist") class Plugin: