diff --git a/components/bl00mbox/CMakeLists.txt b/components/bl00mbox/CMakeLists.txt index f64b7c81f5808f391981e6679fb1d002dfb5ff1f..2fb97bf4af8929c851f77accf3fbd7cbcdf25553 100644 --- a/components/bl00mbox/CMakeLists.txt +++ b/components/bl00mbox/CMakeLists.txt @@ -3,9 +3,10 @@ idf_component_register( SRCS bl00mbox.c - bl00mbox_audio.c - bl00mbox_user.c + bl00mbox_channels.c + bl00mbox_plugins_signals.c bl00mbox_os.c + bl00mbox_patches.c bl00mbox_plugin_registry.c bl00mbox_radspa_requirements.c bl00mbox_containers.c diff --git a/components/bl00mbox/bl00mbox_audio.c b/components/bl00mbox/bl00mbox_channels.c similarity index 76% rename from components/bl00mbox/bl00mbox_audio.c rename to components/bl00mbox/bl00mbox_channels.c index 564a4fe6241dc863091cd3e2703acdb4d9b40da3..6a84d0e77b41598a9f34ec58a8d323f7db62520d 100644 --- a/components/bl00mbox/bl00mbox_audio.c +++ b/components/bl00mbox/bl00mbox_channels.c @@ -5,9 +5,7 @@ #include "bl00mbox_channel_plugin.h" #include <assert.h> -static uint16_t full_buffer_len; - -static uint32_t render_pass_id; +static uint32_t bl00mbox_render_pass_id = 0; int16_t * bl00mbox_line_in_interlaced = NULL; @@ -135,9 +133,7 @@ bl00mbox_channel_t * bl00mbox_channel_create(){ failed: if(chan){ if(chan->channel_plugin){ - // supress errors - chan->channel_plugin->parent_self_ref = &chan->channel_plugin; - bl00mbox_plugin_destroy(chan->channel_plugin); + bl00mbox_plugin_destroy_unlisted(chan->channel_plugin); } if(chan->render_lock) bl00mbox_delete_lock(&chan->render_lock); free(chan); @@ -148,13 +144,11 @@ failed: void bl00mbox_channel_clear(bl00mbox_channel_t * chan){ // note: this does NOT destroy the channel_plugin as it is unlisted - bl00mbox_set_iter_t iter; - bl00mbox_set_iter_start(&iter, &chan->plugins); - bl00mbox_plugin_t * plugin; - while((plugin = bl00mbox_set_iter_next(&iter))){ - bl00mbox_plugin_destroy(plugin); - } + bl00mbox_clear_patch_container(&chan->patches); chan->plugin_id = 0; + if(chan->patches.plugin_t.len) bl00mbox_log_error("plugin_t nonempty"); + if(chan->patches.patch_t.len) bl00mbox_log_error("patch_t nonempty"); + if(chan->num_plugins) bl00mbox_log_error("num_plugins nonzero"); } void bl00mbox_channel_destroy(bl00mbox_channel_t * chan){ @@ -174,27 +168,13 @@ void bl00mbox_channel_destroy(bl00mbox_channel_t * chan){ bl00mbox_set_remove(all_chans, chan); bl00mbox_give_lock(&user_lock); - // remove from parent - if(* (chan->parent_self_ref) != chan){ - bl00mbox_log_error("channel: parent_self_ref improper: channel %p, ref %p", - chan, * (chan->parent_self_ref)); - } - * (chan->parent_self_ref) = NULL; - - // remove from weak parent - if(chan->weak_parent_self_ref){ - if(* (chan->weak_parent_self_ref) != chan){ - bl00mbox_log_error("channel: weak_parent_self_ref improper: channel %p, ref %p", - chan, * (chan->weak_parent_self_ref)); - } - * (chan->weak_parent_self_ref) = NULL; - } + bl00mbox_deref(&chan->ref, chan, "channel"); + bl00mbox_deref(&chan->weak_ref, chan, "channel"); #ifdef BL00MBOX_DEBUG if(chan->connections.len) bl00mbox_log_error("connections nonempty"); if(chan->roots.len) bl00mbox_log_error("roots nonempty"); if(chan->always_render.len) bl00mbox_log_error("always render nonempty"); - if(chan->plugins.len) bl00mbox_log_error("plugins nonempty"); bl00mbox_wait(); #endif @@ -209,23 +189,11 @@ void bl00mbox_channel_destroy(bl00mbox_channel_t * chan){ if(chan->channel_plugin) bl00mbox_plugin_destroy(chan->channel_plugin); free(chan->render_plugins); free(chan->render_buffers); - free(chan->name); free(chan); } -void bl00mbox_audio_plugin_render(bl00mbox_plugin_t * plugin){ - if(plugin->render_pass_id == render_pass_id) return; -#ifdef BL00MBOX_LOOPS_ENABLE - if(plugin->is_being_rendered) return; -#endif - plugin->is_being_rendered = true; - plugin->rugin->render(plugin->rugin, full_buffer_len, render_pass_id); - plugin->render_pass_id = render_pass_id; - plugin->is_being_rendered = false; -} - -static bool _bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * out, bool adding){ - chan->render_pass_id = render_pass_id; +static bool _bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int32_t * out, bool adding){ + chan->render_pass_id = bl00mbox_render_pass_id; int32_t vol = radspa_mult_shift(chan->volume, chan->sys_gain); if(!vol) return false; // don't render if muted @@ -233,25 +201,26 @@ static bool _bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * // render these even if nothing is plugged into mixer if(chan->render_plugins){ for(size_t i = 0; i < chan->render_plugins->len; i++){ - bl00mbox_audio_plugin_render(chan->render_plugins->elems[i]); + bl00mbox_plugin_t * plugin = chan->render_plugins->elems[i]; + radspa_render_plugin(plugin->rugin, bl00mbox_render_pass_id); } } - bl00mbox_channel_plugin_update_values(chan->channel_plugin->rugin, render_pass_id); + bl00mbox_channel_plugin_update_values(chan->channel_plugin->rugin, bl00mbox_render_pass_id); if(!(chan->render_buffers && chan->render_buffers->len)) return false; - int32_t acc[full_buffer_len]; + int32_t acc[BL00MBOX_BUFFER_LEN]; // first one non-adding int16_t * buffer = chan->render_buffers->elems[0]; if(buffer[1] == -32768){ - for(size_t i = 0; i < full_buffer_len; i++){ + for(size_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ acc[i] = buffer[0]; } } else { - for(size_t i = 0; i < full_buffer_len; i++){ + for(size_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ acc[i] = buffer[i]; } } @@ -261,18 +230,18 @@ static bool _bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * buffer = chan->render_buffers->elems[i]; if(buffer[1] == -32768){ if(buffer[0]){ - for(size_t i = 0; i < full_buffer_len; i++){ + for(size_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ acc[i] += buffer[0]; } } } else { - for(size_t i = 0; i < full_buffer_len; i++){ + for(size_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ acc[i] += buffer[i]; } } } - for(uint16_t i = 0; i < full_buffer_len; i++){ + for(uint16_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ // flip around for rounding towards zero/mulsh boost int invert = chan->dc < 0 ? -1 : 1; chan->dc = chan->dc * invert; @@ -284,16 +253,16 @@ static bool _bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * acc[i] -= (chan->dc >> 12); } if(adding){ - for(uint16_t i = 0; i < full_buffer_len; i++){ - out[i] = radspa_add_sat(radspa_gain(acc[i], vol), out[i]); + for(uint16_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ + out[i] += radspa_gain(acc[i], vol); } } else { - for(uint16_t i = 0; i < full_buffer_len; i++){ + for(uint16_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ out[i] = radspa_gain(acc[i], vol); } } if(chan->compute_rms){ - for(uint16_t i = 0; i < full_buffer_len; i++){ + for(uint16_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ int32_t sq = acc[i]; sq = (sq * sq) - chan->mean_square; // always round down with negative sq so that decay always works. @@ -305,24 +274,31 @@ static bool _bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * return true; } -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; - bl00mbox_take_lock(&chan->render_lock); - bool ret = _bl00mbox_audio_channel_render(chan, out, adding); - bl00mbox_give_lock(&chan->render_lock); - // null it out if nothing was rendered - chan->mean_square *= ret; +static bool bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int32_t * out, bool adding){ + if(bl00mbox_render_pass_id == chan->render_pass_id) return false; + bool ret; + if(chan->compute_time){ + uint32_t time = bl00mbox_get_time(); + bl00mbox_take_lock(&chan->render_lock); + ret = _bl00mbox_audio_channel_render(chan, out, adding); + bl00mbox_give_lock(&chan->render_lock); + // esp-timer: max 1 sec + time = (bl00mbox_get_time() - time) & 0xFFFFF; + chan->time = ((chan->time * 63)>>6) + time; + } else { + bl00mbox_take_lock(&chan->render_lock); + ret = _bl00mbox_audio_channel_render(chan, out, adding); + bl00mbox_give_lock(&chan->render_lock); + } return ret; } -void bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len){ - full_buffer_len = len/2; +bool _bl00mbox_audio_render(int16_t * rx, int32_t *acc){ bl00mbox_line_in_interlaced = rx; - int16_t acc[full_buffer_len]; bool acc_init = false; bl00mbox_take_lock(&active_chans_lock); - render_pass_id++; + bl00mbox_render_pass_id++; if(active_chans){ for(size_t i = 0; i < active_chans->len; i++){ acc_init = bl00mbox_audio_channel_render(active_chans->elems[i], acc, acc_init) || acc_init; @@ -330,14 +306,36 @@ void bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len){ } bl00mbox_give_lock(&active_chans_lock); + return acc_init; +} + +bool bl00mbox_audio_render(int16_t * rx, int16_t * tx){ + int32_t acc[BL00MBOX_BUFFER_LEN]; + bool acc_init = _bl00mbox_audio_render(rx, acc); + if(acc_init){ - for(uint16_t i = 0; i < full_buffer_len; i++){ - tx[2*i] = acc[i]; - tx[2*i+1] = acc[i]; + for(uint16_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ + int16_t val = radspa_clip(acc[i]); + tx[2*i] = val; + tx[2*i+1] = val; } - } else { - memset(tx, 0, len * sizeof(int16_t)); } + + return acc_init; +} + +bool bl00mbox_audio_render_adding(int16_t * rx, int16_t * tx){ + int32_t acc[BL00MBOX_BUFFER_LEN]; + bool acc_init = _bl00mbox_audio_render(rx, acc); + + if(acc_init){ + for(uint16_t i = 0; i < BL00MBOX_BUFFER_LEN; i++){ + tx[2*i] += radspa_add_sat(tx[2*i], acc[i]); + tx[2*i+1] += radspa_add_sat(tx[2*i+1], acc[i]); + } + } + + return acc_init; } void bl00mbox_audio_init(){ diff --git a/components/bl00mbox/bl00mbox_containers.c b/components/bl00mbox/bl00mbox_containers.c index 097d57d32ba4dd6dc9dd8b6b00d780e472a244de..df6f818527776e3eb380dc032c21b74c6ff2b0bf 100644 --- a/components/bl00mbox/bl00mbox_containers.c +++ b/components/bl00mbox/bl00mbox_containers.c @@ -84,3 +84,10 @@ bl00mbox_array_t * bl00mbox_set_to_array(bl00mbox_set_t * set){ } return ret; } + +void bl00mbox_deref(bl00mbox_ref_t * ref, void * self, char * name){ + if(* (ref->self_ref) != self){ + bl00mbox_log_error("%s: parent_self_ref improper", name); + } + * (ref->self_ref) = NULL; +} diff --git a/components/bl00mbox/bl00mbox_patches.c b/components/bl00mbox/bl00mbox_patches.c new file mode 100644 index 0000000000000000000000000000000000000000..ac3d1228fd41e7977d04dc260588fae2d184a7c5 --- /dev/null +++ b/components/bl00mbox/bl00mbox_patches.c @@ -0,0 +1,69 @@ +#include "bl00mbox_audio.h" +#include "bl00mbox_user.h" + +void bl00mbox_clear_patch_container(bl00mbox_patch_container_t * container){ + bl00mbox_set_iter_t iter; + bl00mbox_set_iter_start(&iter, &container->plugin_t); + bl00mbox_plugin_t * plugin; + while((plugin = bl00mbox_set_iter_next(&iter))){ + bl00mbox_plugin_destroy(plugin); + } + bl00mbox_set_iter_start(&iter, &container->patch_t); + bl00mbox_patch_t * patch; + while((patch = bl00mbox_set_iter_next(&iter))){ + bl00mbox_patch_destroy(patch); + } +} + +bl00mbox_array_t * bl00mbox_parents_from_patch_container(bl00mbox_patch_container_t * container){ + size_t len = container->plugin_t.len + container->patch_t.len; + + bl00mbox_array_t * parents = malloc(sizeof(bl00mbox_array_t) + len * sizeof(void *)); + if(!parents){ + bl00mbox_log_error("out of memory"); + return NULL; + } + + size_t index = 0; + bl00mbox_set_iter_t iter; + bl00mbox_set_iter_start(&iter, &container->plugin_t); + bl00mbox_plugin_t * plugin; + while((plugin = bl00mbox_set_iter_next(&iter))){ + parents->elems[index] = plugin->parent; + index++; + } + bl00mbox_set_iter_start(&iter, &container->patch_t); + bl00mbox_patch_t * patch; + while((patch = bl00mbox_set_iter_next(&iter))){ + parents->elems[index] = patch->parent; + index++; + } + parents->len = index; + return parents; +} + +static inline bl00mbox_set_t * patch_get_set(bl00mbox_patch_t * patch){ + bl00mbox_patch_container_t * c = patch->container ? &patch->container->patches : &patch->channel->patches; + return &c->patch_t; +} + +bl00mbox_patch_t * bl00mbox_patch_create(bl00mbox_channel_t * chan, bl00mbox_patch_t * container){ + bl00mbox_patch_t * patch = calloc(1, sizeof(bl00mbox_patch_t)); + if(!patch) return NULL; + patch->channel = chan; + patch->container = container; + + if(!bl00mbox_set_add_skip_unique_check(patch_get_set(patch), patch)){ + free(patch); + return NULL; + } + return patch; +} +void bl00mbox_patch_destroy(bl00mbox_patch_t * patch){ + bl00mbox_clear_patch_container(&patch->patches); + + bl00mbox_set_remove(patch_get_set(patch), patch); + + bl00mbox_deref(&patch->ref, patch, "patch"); + free(patch); +} diff --git a/components/bl00mbox/bl00mbox_user.c b/components/bl00mbox/bl00mbox_plugins_signals.c similarity index 91% rename from components/bl00mbox/bl00mbox_user.c rename to components/bl00mbox/bl00mbox_plugins_signals.c index b836d1830fb84699dfcc5ceb4101b1694ea18ce8..6de8502c3491e1b61199f0ae35c6b4d7647b38d7 100644 --- a/components/bl00mbox/bl00mbox_user.c +++ b/components/bl00mbox/bl00mbox_plugins_signals.c @@ -11,8 +11,11 @@ radspa_signal_t * bl00mbox_signal_get_by_index(radspa_t * plugin, uint16_t signa return &(plugin->signals[signal_index]); } +static inline bl00mbox_connection_t * conn_from_rignal(radspa_signal_t * rignal){ + return (bl00mbox_connection_t *) rignal->buffer; +} static inline bl00mbox_connection_t * conn_from_signal(bl00mbox_signal_t * signal){ - return (bl00mbox_connection_t *) signal->rignal->buffer; + return conn_from_rignal(signal->rignal); } static bool signal_is_input(bl00mbox_signal_t * signal){ @@ -45,18 +48,18 @@ bl00mbox_connection_t * bl00mbox_connection_from_signal(bl00mbox_signal_t * sign } uint16_t bl00mbox_channel_plugins_num(bl00mbox_channel_t * chan){ - return chan->plugins.len; + return chan->num_plugins; } bl00mbox_array_t * bl00mbox_channel_collect_plugins(bl00mbox_channel_t * chan){ - unsigned int len = chan->plugins.len; + unsigned int len = chan->patches.plugin_t.len; bl00mbox_array_t * ret; ret = malloc(sizeof(bl00mbox_array_t) + len * sizeof(void *)); if(!ret) return NULL; ret->len = len; bl00mbox_set_iter_t iter; - bl00mbox_set_iter_start(&iter, &chan->plugins); + bl00mbox_set_iter_start(&iter, &chan->patches.plugin_t); bl00mbox_plugin_t * plugin; size_t i = 0; while((plugin = bl00mbox_set_iter_next(&iter))) ret->elems[i++] = plugin; @@ -140,7 +143,7 @@ static void update_roots(bl00mbox_channel_t * chan){ bl00mbox_set_iter_start(&iter, roots); bl00mbox_connection_t * conn; while((conn = bl00mbox_set_iter_next(&iter))){ - render_buffers->elems[index] = conn->buffer; + render_buffers->elems[index] = &conn->buffer.data; render_plugins->elems[index] = conn->source.plugin; index++; } @@ -152,7 +155,7 @@ static void update_roots(bl00mbox_channel_t * chan){ render_buffers->elems[index] = output_rignal->buffer; render_buffers->len++; - conn = output_rignal->buffer; + conn = conn_from_rignal(output_rignal); bl00mbox_plugin_t * plugin = conn->source.plugin; bool is_duplicate = false; for(size_t rindex = 0; rindex < index; rindex++){ @@ -213,6 +216,14 @@ defer: free(render_plugins_prev); free(render_buffers_prev); } +static inline bl00mbox_set_t * plugin_get_set(bl00mbox_plugin_t * plugin){ +#ifdef BL00MBOX_DEBUG + char * txt = plugin->container ? " " : " not "; + bl00mbox_log_info("plugin is%sin container", txt); +#endif + bl00mbox_patch_container_t * c = plugin->container ? &plugin->container->patches : &plugin->channel->patches; + return &c->plugin_t; +} bl00mbox_plugin_t * bl00mbox_plugin_create_unlisted(bl00mbox_channel_t * chan, radspa_descriptor_t * desc, uint32_t init_var){ // doesn't instantiate, don't free @@ -223,38 +234,34 @@ bl00mbox_plugin_t * bl00mbox_plugin_create_unlisted(bl00mbox_channel_t * chan, r plugin->init_var = init_var; plugin->rugin = rugin; + plugin->render = rugin->render; plugin->channel = chan; plugin->id = chan->plugin_id++; return plugin; } -bl00mbox_plugin_t * bl00mbox_plugin_create(bl00mbox_channel_t * chan, uint32_t id, uint32_t init_var){ +bl00mbox_plugin_t * bl00mbox_plugin_create(bl00mbox_channel_t * chan, bl00mbox_patch_t * container, uint32_t id, uint32_t init_var){ // doesn't instantiate, don't free radspa_descriptor_t * desc = bl00mbox_plugin_registry_get_descriptor_from_id(id); if(desc == NULL) return NULL; bl00mbox_plugin_t * plugin = bl00mbox_plugin_create_unlisted(chan, desc, init_var); - if(!bl00mbox_set_add_skip_unique_check(&chan->plugins, plugin)){ + plugin->container = container; + + if(!bl00mbox_set_add_skip_unique_check(plugin_get_set(plugin), plugin)){ plugin->rugin->descriptor->destroy_plugin_instance(plugin->rugin); free(plugin); return NULL; } - + chan->num_plugins += 1; bl00mbox_channel_event(chan); return plugin; } -void bl00mbox_plugin_destroy(bl00mbox_plugin_t * plugin){ +void bl00mbox_plugin_destroy_unlisted(bl00mbox_plugin_t * plugin){ bl00mbox_channel_t * chan = plugin->channel; - // remove from parent - if(* (plugin->parent_self_ref) != plugin){ - bl00mbox_log_error("plugin: parent_self_ref improper: plugin %s, %p, ref %p", - plugin->rugin->descriptor->name, plugin, * (plugin->parent_self_ref)); - } - * (plugin->parent_self_ref) = NULL; - // disconnect all signals int num_signals = plugin->rugin->len_signals; for(int i = 0; i < num_signals; i++){ @@ -268,7 +275,7 @@ void bl00mbox_plugin_destroy(bl00mbox_plugin_t * plugin){ // pop from sets bl00mbox_plugin_set_always_render(plugin, false); - bl00mbox_set_remove(&chan->plugins, plugin); + bl00mbox_set_remove(plugin_get_set(plugin), plugin); if(plugin == chan->channel_plugin) chan->channel_plugin = NULL; @@ -276,11 +283,19 @@ void bl00mbox_plugin_destroy(bl00mbox_plugin_t * plugin){ free(plugin); } +void bl00mbox_plugin_destroy(bl00mbox_plugin_t * plugin){ + bl00mbox_channel_t * chan = plugin->channel; + chan->num_plugins -= 1; + bl00mbox_deref(&plugin->ref, plugin, "plugin"); + bl00mbox_plugin_destroy_unlisted(plugin); +} + static bl00mbox_connection_t * create_connection(bl00mbox_signal_t * source){ if(!signal_is_output(source)) return NULL; bl00mbox_connection_t * ret = calloc(1, sizeof(bl00mbox_connection_t)); if(ret == NULL) return NULL; + ret->buffer.plugin = source->plugin->rugin; ret->subscribers.key = signal_equals; memcpy(&ret->source, source, sizeof(bl00mbox_signal_t)); @@ -484,7 +499,6 @@ void bl00mbox_plugin_set_always_render(bl00mbox_plugin_t * plugin, bool value){ } bl00mbox_error_t bl00mbox_signal_set_value(bl00mbox_signal_t * signal, int value){ - //while(signal->plugin->is_being_rendered) {}; if(!signal_is_input(signal)) return BL00MBOX_ERROR_INVALID_CONNECTION; if(conn_from_signal(signal)) bl00mbox_signal_disconnect(signal); signal->rignal->value = value < -32767 ? -32767 : (value > 32767 ? 32767 : value); @@ -492,6 +506,5 @@ bl00mbox_error_t bl00mbox_signal_set_value(bl00mbox_signal_t * signal, int value } int16_t bl00mbox_signal_get_value(bl00mbox_signal_t * signal){ - //while(signal->plugin->is_being_rendered) {}; - return signal->rignal->buffer ? signal->rignal->buffer[0] : signal->rignal->value; + return signal->rignal->buffer ? signal->rignal->buffer->data[0] : signal->rignal->value; } diff --git a/components/bl00mbox/bl00mbox_radspa_requirements.c b/components/bl00mbox/bl00mbox_radspa_requirements.c index 509d58854c53ff680c891e4046af4daa78261e58..2f7d293419b91b6ee4afe44497f8b3fc627929d2 100644 --- a/components/bl00mbox/bl00mbox_radspa_requirements.c +++ b/components/bl00mbox/bl00mbox_radspa_requirements.c @@ -1,11 +1,19 @@ //SPDX-License-Identifier: CC0-1.0 +#include "bl00mbox_audio.h" #include "bl00mbox_radspa_requirements.h" -bool radspa_host_request_buffer_render(int16_t * buf){ - bl00mbox_plugin_t * plugin = ((bl00mbox_connection_t *) buf)->source.plugin; - bl00mbox_audio_plugin_render(plugin); - return 1; -} +// value: 2400*math.log(48000/RADSPA_SAMPLE_RATE) +#if RADSPA_SAMPLE_RATE == 48000 +#define RADSPA_SCT_TO_REL_FREQ_OFFSET 0 +#endif +// we haven't tested anything besides 48k yet, there's plenty hardcoded stuff, +// might result in memory corruption +// note: this is right in the middle so we're like a quarter cent off :/ +#if RADSPA_SAMPLE_RATE == 44100 +#define RADSPA_SCT_TO_REL_FREQ_OFFSET 293 +#endif + +// ideally we should recalc these per sample rate but we forgor how it works // py: bigtable = [int(22/200*(2**(14-5+8+x*4096/2400/64))) for x in range(64)] // for 48kHz main sample rate @@ -39,8 +47,7 @@ uint32_t radspa_sct_to_rel_freq(int16_t sct, int16_t undersample_pow){ /// when sampled at (48>>undersample_pow)kHz // compiler explorer says this is 33 instructions with O2. might be alright? - uint32_t a = sct; - a = sct + 28*2400 - 32767 - 330; + uint32_t a = sct + 28*2400 - 32767 - 330 + RADSPA_SCT_TO_REL_FREQ_OFFSET; // at O2 u get free division for each modulo. still slow, 10 instructions or so. int16_t octa = a / 2400; a = a % 2400; diff --git a/components/bl00mbox/config/bl00mbox_config.h b/components/bl00mbox/config/bl00mbox_config.h index 37a2ddeefbcb10e7f4d8d4ec3a8b14f50fa433af..5743fbf056205370ad1c2a7dc0fa8d8e939a43a4 100644 --- a/components/bl00mbox/config/bl00mbox_config.h +++ b/components/bl00mbox/config/bl00mbox_config.h @@ -4,9 +4,8 @@ //#define BL00MBOX_DEBUG #ifdef BL00MBOX_FLOW3R -//#include "flow3r_bsp.h" -//#define BL00MBOX_MAX_BUFFER_LEN FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE -#define BL00MBOX_MAX_BUFFER_LEN 64 +#define BL00MBOX_SAMPLE_RATE 48000 +#define BL00MBOX_BUFFER_LEN 64 #define BL00MBOX_DEFAULT_CHANNEL_VOLUME 8192 #define BL00MBOX_AUTO_FOREGROUNDING #define BL00MBOX_LOOPS_ENABLE diff --git a/components/bl00mbox/config/radspa_config.h b/components/bl00mbox/config/radspa_config.h new file mode 100644 index 0000000000000000000000000000000000000000..8d230803b53c286a6a107291356f88880b1a22d9 --- /dev/null +++ b/components/bl00mbox/config/radspa_config.h @@ -0,0 +1,4 @@ +#pragma once +#include "bl00mbox_config.h" +#define RADSPA_BUFFER_LEN BL00MBOX_BUFFER_LEN +#define RADSPA_SAMPLE_RATE BL00MBOX_SAMPLE_RATE diff --git a/components/bl00mbox/include/bl00mbox.h b/components/bl00mbox/include/bl00mbox.h index 8a57cf28469decf67d45b0f52868372d6b514f78..34dc6a0437cc6a7777f80aa97f1c21b941c6b9f5 100644 --- a/components/bl00mbox/include/bl00mbox.h +++ b/components/bl00mbox/include/bl00mbox.h @@ -5,8 +5,6 @@ #define SAMPLE_RATE 48000 -uint16_t bl00mbox_sources_count(); -uint16_t bl00mbox_source_add(void* render_data, void* render_function); -void bl00mbox_source_remove(uint16_t index); -bool bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len); +bool bl00mbox_audio_render(int16_t * rx, int16_t * tx); +bool bl00mbox_audio_render_adding(int16_t * rx, int16_t * tx); void bl00mbox_init(void); diff --git a/components/bl00mbox/include/bl00mbox_audio.h b/components/bl00mbox/include/bl00mbox_audio.h index 41552c44a118af95e792f300e793bc09322d915a..17850e83837fcdaaad967a869869c4d7db8ea240 100644 --- a/components/bl00mbox/include/bl00mbox_audio.h +++ b/components/bl00mbox/include/bl00mbox_audio.h @@ -10,27 +10,34 @@ #include "radspa.h" #include "radspa_helpers.h" +extern int16_t * bl00mbox_line_in_interlaced; + struct _bl00mbox_plugin_t; struct _bl00mbox_connection_source_t; struct _bl00mbox_channel_root_t; struct _bl00mbox_channel_t; +struct _bl00mbox_patch_t; -extern int16_t * bl00mbox_line_in_interlaced; +typedef struct _bl00mbox_patch_container_t { + bl00mbox_set_t plugin_t; + bl00mbox_set_t patch_t; +} bl00mbox_patch_container_t; // pointer is unique identifier, no memcpy of this! typedef struct _bl00mbox_plugin_t{ radspa_t * rugin; // radspa plugin + radspa_render_t render; char * name; uint32_t id; // unique number in channel to for UI purposes - uint32_t render_pass_id; // may be used by host to determine whether recomputation is necessary uint32_t init_var; // init var that was used for plugin creation - volatile bool is_being_rendered; // true if rendering the plugin is in progress, else false. bool always_render; struct _bl00mbox_channel_t * channel; // channel that owns the plugin + struct _bl00mbox_patch_t * container; + void * parent; - struct _bl00mbox_plugin_t ** parent_self_ref; + bl00mbox_ref_t ref; } bl00mbox_plugin_t; // pointer is NOT unique identifier, memcpy allowed @@ -41,7 +48,7 @@ typedef struct { } bl00mbox_signal_t; typedef struct _bl00mbox_connection_t{ //child of bl00mbox_ll_t - int16_t buffer[BL00MBOX_MAX_BUFFER_LEN]; // MUST stay on top of struct bc type casting! TODO: offsetof() + radspa_buffer_t buffer; // MUST stay on top of struct bc type casting! TODO: offsetof() bl00mbox_signal_t source; bl00mbox_set_t subscribers; // content: bl00mbox_signal_t; bool connected_to_mixer; // legacy thing, don't wanna sentinel subsribers @@ -49,9 +56,10 @@ typedef struct _bl00mbox_connection_t{ //child of bl00mbox_ll_t // pointer is unique identifier, no memcpy of this! typedef struct _bl00mbox_channel_t{ - char * name; + int32_t dev; int32_t volume; + bool background_mute_override; // secondary gain that the channel user is supposed to leave untouched so that the OS @@ -66,19 +74,27 @@ typedef struct _bl00mbox_channel_t{ // you have to only do the log operation and can skip the root as you can express roots // as divisions in the log domain which is much cheaper. uint32_t mean_square; + // average output used for DC blocking. int32_t dc; + // used for profiling + bool compute_time; + uint32_t time; + uint32_t render_pass_id; // may be used by host to determine whether recomputation is necessary uint32_t plugin_id; // used to give each plugin in channel a unique identifier + uint32_t num_plugins; + // we render all of these and add them up. it's a legacy thing from when we had a output mixer // but that kinda mixes poorly (heh) with our general API. bl00mbox_set_t roots; // content: bl00mbox_connection_t bl00mbox_set_t connections; // content: bl00mbox_connection_t bl00mbox_set_t always_render; // content: bl00mbox_plugin_t - bl00mbox_set_t plugins; // content: bl00mbox_plugin_t + + struct _bl00mbox_patch_container_t patches; bl00mbox_plugin_t * channel_plugin; @@ -88,14 +104,13 @@ typedef struct _bl00mbox_channel_t{ bl00mbox_array_t * render_buffers; void * parent; - struct _bl00mbox_channel_t ** parent_self_ref; - struct _bl00mbox_channel_t ** weak_parent_self_ref; + bl00mbox_ref_t ref; + bl00mbox_ref_t weak_ref; } bl00mbox_channel_t; void bl00mbox_audio_init(); bl00mbox_channel_t * bl00mbox_channel_create(); -void bl00mbox_audio_plugin_render(bl00mbox_plugin_t * plugin); bool bl00mbox_channel_get_foreground(bl00mbox_channel_t * chan); void bl00mbox_channel_set_foreground(bl00mbox_channel_t * chan, bool enable); void bl00mbox_channel_set_background_mute_override(bl00mbox_channel_t * chan, bool enable); @@ -103,3 +118,23 @@ void bl00mbox_channel_clear(bl00mbox_channel_t * chan); void bl00mbox_channel_destroy(bl00mbox_channel_t * chan); void bl00mbox_channel_event(bl00mbox_channel_t * channel); bl00mbox_array_t * bl00mbox_collect_channels(bool active); + +// pointer is unique identifier, no memcpy of this! +typedef struct _bl00mbox_patch_t { + uint32_t id; // unique number in channel to for UI purposes + + struct _bl00mbox_channel_t * channel; // channel that owns the patch + + struct _bl00mbox_patch_container_t patches; + + struct _bl00mbox_patch_t * container; + + void * parent; + bl00mbox_ref_t ref; +} bl00mbox_patch_t; + +bl00mbox_patch_t * bl00mbox_patch_create(bl00mbox_channel_t * chan, bl00mbox_patch_t * container); +void bl00mbox_patch_destroy(bl00mbox_patch_t * patch); +void bl00mbox_clear_patch_container(bl00mbox_patch_container_t * container); +bl00mbox_array_t * bl00mbox_parents_from_patch_container(bl00mbox_patch_container_t * container); + diff --git a/components/bl00mbox/include/bl00mbox_containers.h b/components/bl00mbox/include/bl00mbox_containers.h index 71dfb6ea3925abaf6628333b78fa1edc577d82b6..bd4ef52110716f332b12a0486f98e350db2ce993 100644 --- a/components/bl00mbox/include/bl00mbox_containers.h +++ b/components/bl00mbox/include/bl00mbox_containers.h @@ -22,7 +22,7 @@ typedef struct { typedef struct { bl00mbox_ll_t * next; -}bl00mbox_set_iter_t; +} bl00mbox_set_iter_t; bool bl00mbox_set_contains(bl00mbox_set_t * set, void * content); bool bl00mbox_set_add_skip_unique_check(bl00mbox_set_t * set, void * content); @@ -34,3 +34,9 @@ void bl00mbox_set_iter_start(bl00mbox_set_iter_t * iter, bl00mbox_set_t * set); void * bl00mbox_set_iter_next(bl00mbox_set_iter_t * iter); bl00mbox_array_t * bl00mbox_set_to_array(bl00mbox_set_t * set); + +typedef struct { + void ** self_ref; +} bl00mbox_ref_t; + +void bl00mbox_deref(bl00mbox_ref_t * ref, void * self, char * name); diff --git a/components/bl00mbox/include/bl00mbox_os.h b/components/bl00mbox/include/bl00mbox_os.h index 59964962a9c7b7493b46b0eb95a5783964eacaca..6fdf4f688b4368f0248f267ec02a81694a9985d6 100644 --- a/components/bl00mbox/include/bl00mbox_os.h +++ b/components/bl00mbox/include/bl00mbox_os.h @@ -26,6 +26,8 @@ void bl00mbox_wait(); #ifdef BL00MBOX_ESPIDF #include "esp_log.h" +#define bl00mbox_get_time() esp_timer_get_time() +#define BL00MBOX_REF_TIME ((1000000. * 64 * BL00MBOX_BUFFER_LEN) / BL00MBOX_SAMPLE_RATE) #define bl00mbox_log_error(txt, ...) ESP_LOGE("bl00mbox", txt, ##__VA_ARGS__); #ifdef BL00MBOX_DEBUG #define bl00mbox_log_info(txt, ...) ESP_LOGE("bl00mbox", txt, ##__VA_ARGS__); diff --git a/components/bl00mbox/include/bl00mbox_patches.h b/components/bl00mbox/include/bl00mbox_patches.h new file mode 100644 index 0000000000000000000000000000000000000000..f1e5fef2dadf51957a1edf3e8952c35fd89e9516 --- /dev/null +++ b/components/bl00mbox/include/bl00mbox_patches.h @@ -0,0 +1,29 @@ +//SPDX-License-Identifier: CC0-1.0 +#pragma once +#include "bl00mbox_containers.h" +#include "bl00mbox_audio.h" + +extern int16_t * bl00mbox_line_in_interlaced; + +typedef struct { + bl00mbox_set_t plugin_t; + bl00mbox_set_t patch_t; +} bl00mbox_patch_container_t; + +// pointer is unique identifier, no memcpy of this! +typedef struct _bl00mbox_patch_t{ + uint32_t id; // unique number in channel to for UI purposes + + struct _bl00mbox_channel_t * channel; // channel that owns the patch + + bl00mbox_patch_container_t * patches; + + struct _bl00mbox_patch_t * container; + + void * parent; + bl00mbox_ref_t ref; +} bl00mbox_patch_t; + +bl00mbox_patch_t * bl00mbox_patch_create(bl00mbox_channel_t * chan, bl00mbox_patch_t * container); +void bl00mbox_patch_destroy(bl00mbox_patch_t * patch); +void bl00mbox_clear_patch_container(bl00mbox_patch_container_t * container); diff --git a/components/bl00mbox/include/bl00mbox_user.h b/components/bl00mbox/include/bl00mbox_user.h index 254720aef1cc63ed43888df8262336cf44bd5736..d3f6961e22f67bd888e8b6ba3bf25a4800255b30 100644 --- a/components/bl00mbox/include/bl00mbox_user.h +++ b/components/bl00mbox/include/bl00mbox_user.h @@ -19,11 +19,13 @@ uint16_t bl00mbox_channel_plugins_num(bl00mbox_channel_t * chan); uint16_t bl00mbox_channel_conns_num(bl00mbox_channel_t * chan); uint16_t bl00mbox_channel_mixer_num(bl00mbox_channel_t * chan); + bl00mbox_array_t * bl00mbox_channel_collect_plugins(bl00mbox_channel_t * chan); bl00mbox_array_t * bl00mbox_channel_collect_connections_mx(bl00mbox_channel_t * chan); bl00mbox_plugin_t * bl00mbox_plugin_create_unlisted(bl00mbox_channel_t * chan, radspa_descriptor_t * desc, uint32_t init_var); -bl00mbox_plugin_t * bl00mbox_plugin_create(bl00mbox_channel_t * chan, uint32_t id, uint32_t init_var); +bl00mbox_plugin_t * bl00mbox_plugin_create(bl00mbox_channel_t * chan, bl00mbox_patch_t * container, uint32_t id, uint32_t init_var); +void bl00mbox_plugin_destroy_unlisted(bl00mbox_plugin_t * plugin); void bl00mbox_plugin_destroy(bl00mbox_plugin_t * plugin); void bl00mbox_plugin_set_always_render(bl00mbox_plugin_t * plugin, bool value); diff --git a/components/bl00mbox/micropython/bl00mbox/__init__.py b/components/bl00mbox/micropython/bl00mbox/__init__.py index 6f4058f79d0c57320640a8c483e797c273f29cc1..ffa92e39700b548168b591ebc53bbc804af3a95f 100644 --- a/components/bl00mbox/micropython/bl00mbox/__init__.py +++ b/components/bl00mbox/micropython/bl00mbox/__init__.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: CC0-1.0 from bl00mbox._user import * -import bl00mbox._patches as patches import bl00mbox._helpers as helpers from bl00mbox._plugins import plugins +import bl00mbox._patches as patches diff --git a/components/bl00mbox/micropython/bl00mbox/_helpers.py b/components/bl00mbox/micropython/bl00mbox/_helpers.py index 9ae8b1f621596dfa98ec132dbfeb95dfd1a9bbf5..0bba3323de9d8c385977bec0c2b66720861db285 100644 --- a/components/bl00mbox/micropython/bl00mbox/_helpers.py +++ b/components/bl00mbox/micropython/bl00mbox/_helpers.py @@ -1,6 +1,13 @@ # SPDX-License-Identifier: CC0-1.0 import time +indent = " " +indent_nl = "\n" + indent + +def indentify(text): + if isinstance(text, str): + text = text.split("\n") + return indent + indent_nl.join(text) def terminal_scope( signal, @@ -72,3 +79,18 @@ def note_name_to_sct(name): def sct_to_freq(sct): return 440 * 2 ** ((sct - 18367) / 2400) + +class _CoreKeyFallthrough: + _core_keys = {} + + def __setattr__(self, key, value): + if key in self._core_keys: + setattr(self._core, key, value) + else: + super().__setattr__(key, value) + + def __getattr__(self, key): + if key in self._core_keys: + return getattr(self._core, key) + else: + raise AttributeError(f"'{type(self)}' object has no attribute {key}") diff --git a/components/bl00mbox/micropython/bl00mbox/_patches.py b/components/bl00mbox/micropython/bl00mbox/_patches.py index b63552ea22db6b6c1f07caf1cef7e4c8b17cb5b1..7ed9f2c42bd881cd0f210f28f58f0b93bb5a31d7 100644 --- a/components/bl00mbox/micropython/bl00mbox/_patches.py +++ b/components/bl00mbox/micropython/bl00mbox/_patches.py @@ -3,48 +3,44 @@ import math import os import bl00mbox import cpython.wave as wave +import sys_bl00mbox +from bl00mbox import _plugins as plugins +from bl00mbox._helpers import indentify as dent - -class _Patch: +class _Patch(plugins.PluginSpawner): + _core_keys = ("name", "container", "delete") + _patch_name = None def __init__(self, chan): - self.signals = _PatchSignalList() - self._channel = chan - # old style - self.plugins = _PatchPluginList() - # new style - self._plugins = [] - - def new(self, *args, **kwargs): - plugin = self._channel.new(*args, **kwargs) - self._plugins.append(plugin) - return plugin + # due to backwards compatibility reasons we're doing some crimes in chan here + kw = chan._hacky_kwargs + if self._patch_name is None: + self._patch_name = self.__class__.__name__ + self._core = sys_bl00mbox.PatchCore(kw.core, self, kw.container, self._patch_name, kw.name) + self._spawn_core = kw.core + self._dev = chan.dev + if not self._dev: + self.signals = _PatchSignalList() + self.plugins = _PatchPluginList() + self._channel = chan + else: + self.signals = bl00mbox.SignalContainer() + self._weak_channel = chan._weak_channel + self._container = self._core def __repr__(self): - ret = "[patch] " + type(self).__name__ - ret += "\n [signals:] " + "\n ".join(repr(self.signals).split("\n")) - # old style - plugin_repr = repr(self.plugins) - # new style - for plugin in self._plugins: - plugin_repr += "\n" + repr(plugin) - ret += "\n [plugins:] " + "\n ".join(plugin_repr.split("\n")) + return self.show() + + def show(self, *, oneliner = False, patches = False, **kwargs): + ret = f"[{self._patch_name}]" + if self.name: + ret += " " + self.name + if patches: + ret += "\n" + dent(dent([p.show(oneliner = oneliner, patches = True) for p in self._core.get_patches()])) + if oneliner: + return ret + ret += "\n" + dent("[signals]\n" + dent(repr(self.signals))) return ret - def delete(self): - # new style - plugins = self._plugins[:] - # old style - for plugin_name in self.plugins.__dict__: - if not plugin_name.startswith("_"): - plugin_list = self.plugins.__dict__[plugin_name] - if (type(plugin_list)) != list: - plugin_list = [plugin_list] - plugins += plugin_list - - for plugin in set(plugins): - plugin.delete() - - class _PatchItemList: def __init__(self): self._items = [] @@ -54,6 +50,9 @@ class _PatchItemList: return iter(self._items) def __repr__(self): + return self.show() + + def show(self, **kwargs): ret = "" for x in self._items: a = ("\n" + repr(getattr(self, x))).split("]") @@ -401,10 +400,10 @@ class fuzz(_Patch): class karplus_strong(_Patch): def __init__(self, chan): super().__init__(chan) - self.plugins.noise = chan._new_plugin(bl00mbox.plugins.noise_burst) + self.plugins.noise = chan.new(bl00mbox.plugins.noise_burst) self.plugins.noise.signals.length = 25 - self.plugins.flanger = chan._new_plugin(bl00mbox.plugins.flanger) + self.plugins.flanger = chan.new(bl00mbox.plugins.flanger) self.plugins.flanger.signals.resonance = 0 self.plugins.flanger.signals.decay = 1000 diff --git a/components/bl00mbox/micropython/bl00mbox/_plugins.py b/components/bl00mbox/micropython/bl00mbox/_plugins.py index a1aacf6c80842550fbf0b2ef6e96a64d1e1f3e26..f41053b350aa6737482893e5e49a7f8bd886288f 100644 --- a/components/bl00mbox/micropython/bl00mbox/_plugins.py +++ b/components/bl00mbox/micropython/bl00mbox/_plugins.py @@ -6,6 +6,43 @@ import uctypes import os import cpython.wave as wave +from bl00mbox import _helpers as helpers + +class _Container: + pass + +class PluginSpawner(helpers._CoreKeyFallthrough): + def new(self, thing, *args, name = None, **kwargs): + if type(thing) == type and issubclass(thing, bl00mbox.patches._Patch): + # patches don't pass *args/**kwargs in the field atm + # they should tho + # but for now we have to do this lil workaround + hacky_kwargs = _Container() + hacky_kwargs.name = name + hacky_kwargs.container = self._container + hacky_kwargs.core = self._spawn_core + self._weak_channel._hacky_kwargs = hacky_kwargs + return thing(self._weak_channel, *args, **kwargs) + elif isinstance(thing, bl00mbox._plugins._PluginDescriptor): + return bl00mbox._plugins._make_plugin( + self._spawn_core, self._container, thing.plugin_id, *args, name = name, **kwargs + ) + else: + raise TypeError("invalid plugin/patch") + +def _make_plugin(channel_core, container, plugin_id, *args, **kwargs): + if plugin_id in _plugin_subclasses: + return _plugin_subclasses[plugin_id](channel_core, container, plugin_id, *args, **kwargs) + else: + init_var = 0 + _init_var = kwargs.get("init_var", None) + if _init_var is None: + if len(args) == 1: + init_var = int(args[0]) + else: + init_var = _init_var + name = kwargs.get("name", None) + return _Plugin(channel_core, container, plugin_id, init_var, name) class _PluginDescriptor: def __init__(self, index): @@ -25,11 +62,7 @@ class _PluginDescriptor: ) -class _PluginDescriptors: - pass - - -plugins = _PluginDescriptors() +plugins = _Container() def _fill(): @@ -50,36 +83,53 @@ def _fill(): _fill() -class _Plugin: +class _Plugin(helpers._CoreKeyFallthrough): _core_keys = ( "always_render", "delete", "init_var", "table_len", "name", + "channel", "plugin_id", ) - def __setattr__(self, key, value): - if key in self._core_keys: - setattr(self._core, key, value) - else: - super().__setattr__(key, value) + class Render: + def __init__(self, core): + self._core = core + #self.cpu = self.CPU(core) - def __getattr__(self, key): - if key in self._core_keys: - return getattr(self._core, key) - else: - raise AttributeError(f"'{type(self)}' object has no attribute {key}") + @property + def always(self): + return self._core.always_render - def __init__(self, channel, core=None, plugin_id=None, init_var=0): - if core: - self._core = core - elif plugin_id is not None: - self._core = sys_bl00mbox.PluginCore(channel._core, plugin_id, init_var) + class CPU: + def __init__(self, core): + self._core = core + + @property + def compute(self): + return self._core.compute_render_time + + @compute.setter + def compute(self, val): + self._core.compute_render_time = bool(val) + + @property + def percent(self): + return self._core.render_time + @property + def render(self): + if not hasattr(self, "_render"): + self._render = self.Render(self._core) + return self._render + + def __init__(self, channel_core, container, plugin_id, init_var=0, name = None): + self._core = sys_bl00mbox.PluginCore(channel_core, self, container, plugin_id, init_var, name) + if self.channel.dev: + self.signals = bl00mbox.SignalContainer._from_plugin(self) else: - raise ValueError("must supply core or plugin id") - self._signals = bl00mbox.SignalList(self) + self.signals = bl00mbox.SignalList(self) def _repr_no_signals(self): id_num = self._core.id @@ -90,19 +140,24 @@ class _Plugin: return f"[{self._core.name}]" def __repr__(self): + return self.show() + + def show(self, *, oneliner = False, **kwargs): ret = self._repr_no_signals() - for sig in self.signals._list: - ret += "\n " + "\n ".join(sig._no_desc().split("\n")) - return ret + if oneliner: + return ret + if isinstance(self.signals, bl00mbox.SignalList): + sig_ret = [] + for sig in self.signals._list: + sig_ret.append(sig._no_desc()) + else: + sig_ret = self.signals.show() + return ret + "\n" + helpers.indentify(sig_ret) def _check_existence(self): # will fail if plugin was deleted _ = self._core.plugin_id - @property - def signals(self): - return self._signals - @property def table(self): _table = self.table_int16_array @@ -154,33 +209,11 @@ class _Plugin: _plugin_subclasses = {} -def _make_plugin(channel, plugin_id, *args, **kwargs): - if plugin_id in _plugin_subclasses: - return _plugin_subclasses[plugin_id](channel, None, plugin_id, *args, **kwargs) - else: - init_var = 0 - _init_var = kwargs.get("init_var", None) - if _init_var is None: - if len(args) == 1: - init_var = int(args[0]) - else: - init_var = _init_var - return _Plugin(channel, None, plugin_id, init_var) - - -def _get_plugin(core): - plugin_id = core.plugin_id - if plugin_id in _plugin_subclasses: - return _plugin_subclasses[plugin_id](None, core, plugin_id, core.init_var) - else: - return _Plugin(None, core, plugin_id, core.init_var) - def _plugin_set_subclass(plugin_id): def decorator(cls): _plugin_subclasses[plugin_id] = cls return cls - return decorator @@ -195,19 +228,16 @@ class _Sampler(_Plugin): _STATUS = 10 _BUFFER = 11 - def __init__(self, channel, core, plugin_id, init_var=1000): + def __init__(self, channel_core, container, plugin_id, init_var=1000, name = None): self._filename = "" - if core is not None: - super().__init__(channel, core, None) - self._memory_len = self.init_var - elif type(init_var) is str: + if type(init_var) is str: with wave.open(init_var, "r") as f: self._memory_len = f.getnframes() - super().__init__(channel, None, plugin_id, init_var=self._memory_len) + super().__init__(channel_core, container, plugin_id, init_var=self._memory_len, name = name) self.load(init_var) else: self._memory_len = int(48 * init_var) - super().__init__(channel, None, plugin_id, init_var=self._memory_len) + super().__init__(channel_core, container, plugin_id, init_var=self._memory_len, name = name) def __repr__(self): ret = super().__repr__() @@ -266,7 +296,7 @@ class _Sampler(_Plugin): assert f.getnchannels() in (1, 2) assert f.getcomptype() == "NONE" except AssertionError: - raise Bl00mboxError("incompatible file format") + raise TypeError("incompatible file format") frames = f.getnframes() if frames > self._memory_len: @@ -498,14 +528,11 @@ class _Distortion(_Plugin): @_plugin_set_subclass(172) class _PolySqueeze(_Plugin): - def __init__(self, channel, core, plugin_id, num_outputs=3, num_inputs=10): - if core is None: - outs = max(min(num_outputs, 16), 1) - ins = max(min(num_inputs, 32), num_outputs) - init_var = outs + (ins * 256) - super().__init__(channel, core, plugin_id, init_var=init_var) - else: - super().__init__(channel, core, None) + def __init__(self, channel_core, container, plugin_id, num_outputs=3, num_inputs=10, name = None): + outs = max(min(num_outputs, 16), 1) + ins = max(min(num_inputs, 32), num_outputs) + init_var = outs + (ins * 256) + super().__init__(channel_core, container, plugin_id, init_var=init_var, name = name) @_plugin_set_subclass(0) @@ -632,20 +659,15 @@ class _Osc(_Plugin): @_plugin_set_subclass(56709) class _Sequencer(_Plugin): - def __init__(self, channel, core, plugin_id, num_tracks=4, num_steps=16): - if core is None: - self.num_steps = num_steps % 256 - self.num_tracks = num_tracks % 256 - init_var = (self.num_steps * 256) + (self.num_tracks) + def __init__(self, channel_core, container, plugin_id, num_tracks=4, num_steps=16, name = None): + self.num_steps = num_steps % 256 + self.num_tracks = num_tracks % 256 + init_var = (self.num_steps * 256) + (self.num_tracks) - super().__init__(channel, core, plugin_id, init_var=init_var) + super().__init__(channel_core, container, plugin_id, init_var=init_var, name = name) - tracktable = [-32767] + ([0] * self.num_steps) - self.table = tracktable * self.num_tracks - else: - super().__init__(channel, core, None) - self.num_tracks = self.init_var % 256 - self.num_steps = (self.init_var // 256) % 256 + tracktable = [-32767] + ([0] * self.num_steps) + self.table = tracktable * self.num_tracks def __repr__(self): ret = super().__repr__() diff --git a/components/bl00mbox/micropython/bl00mbox/_user.py b/components/bl00mbox/micropython/bl00mbox/_user.py index 2f99bca564c0f347ba1503fcd082c24b23ba1d8c..1d305bdd195859ce42a931eaeeab31a3e4ea9c28 100644 --- a/components/bl00mbox/micropython/bl00mbox/_user.py +++ b/components/bl00mbox/micropython/bl00mbox/_user.py @@ -8,45 +8,72 @@ import math import uctypes import bl00mbox from bl00mbox import _helpers as helpers +from bl00mbox import _plugins from bl00mbox._patches import _Patch as Patch +from collections import OrderedDict class Bl00mboxError(Exception): pass +class SignalTuple(tuple): + def __repr__(self): + return self.show() -def _make_signal(plugin, signal_num=0, core=None): - if core is None: - core = sys_bl00mbox.SignalCore(plugin._core, signal_num) - is_input = bool(core.hints & sys_bl00mbox.SIGNAL_HINT_INPUT) - is_output = bool(core.hints & sys_bl00mbox.SIGNAL_HINT_OUTPUT) - if is_output == is_input: - raise Bl00mboxError("signal must be either input or output") - if is_input: - signal = SignalInput(plugin, core) - else: - signal = SignalOutput(plugin, core) - return signal + def show(self, *, name = None): + lines = [] + for sig in self: + lines.append(sig.show(name = "")) + ret = helpers.indentify(lines) + title = "signals" if name is None else name + return f"[{title}]\n{ret}" +class SignalContainer: + def __init__(self): + self._ordereddict = OrderedDict() -class ChannelMixer: - def __init__(self, core): - self._core = core + def __setattr__(self, key, value): + if hasattr(self, "_ordereddict"): + self._ordereddict[key] = value + super().__setattr__(key, value) - def __repr__(self): - ret = f"[channel mixer] ({len(self.connections)} connections)" - for con in self.connections: - ret += f"\n {con.name} in {con._plugin._repr_no_signals()}" + @staticmethod + def _from_plugin(plugin): + ret = SignalContainer() + mpxd = OrderedDict() + for signal_num in range(plugin._core.num_signals): + signal = Signal._from_plugin(plugin, signal_num) + name = signal.name.split(" ")[0] + if signal._mpx == -1: + setattr(ret, name, signal) + else: + mpx_list = mpxd.get(name) + if mpx_list is None: + mpx_list = list() + mpxd[name] = mpx_list + extra_len = 1 + signal._mpx - len(mpx_list) + if extra_len > 0: + mpx_list += [None] * extra_len + mpx_list[signal._mpx] = signal + for name in mpxd: + sigs = SignalTuple(mpxd[name]) + setattr(ret, name, sigs) return ret - @property - def connections(self): - cons = [] - signal_cores = self._core.get_connected_mx() - for core in signal_cores: - plugin = bl00mbox._plugins._get_plugin(core.plugin_core) - cons.append(_make_signal(plugin, core=core)) - return cons + def __repr__(self): + return self.show() + + def show(self, *, name = None): + lines = [] + for key in self._ordereddict: + lines += getattr(self, key).show(name = key).split("\n") + for key in self.__dict__: + if key.startswith("_") or key in self._ordereddict: + continue + lines += getattr(self, key).show(name = key).split("\n") + ret = helpers.indentify(lines) + title = "signals" if name is None else name + return f"[{title}]\n{ret}" class ValueSwitch: @@ -72,14 +99,39 @@ class ValueSwitch: return k -class Signal: +class Signal(helpers._CoreKeyFallthrough): + _core_keys = ( + "name", + "description", + "unit", + "plugin", + ) + + @staticmethod + def _from_plugin(plugin, signal_num): + core = plugin._core.signal_cores[signal_num] + is_input = bool(core.hints & sys_bl00mbox.SIGNAL_HINT_INPUT) + is_output = bool(core.hints & sys_bl00mbox.SIGNAL_HINT_OUTPUT) + if is_output == is_input: + raise Bl00mboxError("signal must be either input or output") + if is_input: + signal = SignalInput(plugin, core) + else: + signal = SignalOutput(plugin, core) + return signal + def __init__(self, plugin, core): + if core.outer is not None: + raise Bl00mboxError("double signal initialization error") self._core = core - self._plugin = plugin + core.outer = self self._mpx = core.mpx self._unit = core.unit self._description = core.description constants = {} + self._dev = plugin.channel.dev + if not self._dev: + self._plugin = plugin another_round = True while another_round: @@ -117,34 +169,40 @@ class Signal: hint_list.append("deprecated") self._hints = "/".join(hint_list) + @property + def hints(self): + return self._hints + @property def connections(self): - cons = [] - signal_cores = self._core.get_connected() - for core in signal_cores: - plugin = bl00mbox._plugins._get_plugin(core.plugin_core) - cons.append(_make_signal(plugin, core=core)) + cons = self._core.get_connected() if self._core.connected_mx: cons.append(ChannelMixer(None)) return cons + def show(self, *, name = None, description = False): + ret = self._no_desc() + if description and len(self._description): + ret += "\n " + "\n ".join(self._description.split("\n")) + return ret + def __repr__(self): ret = self._no_desc() if len(self._description): ret += "\n " + "\n ".join(self._description.split("\n")) return ret - def _no_desc(self): - self._plugin._check_existence() + def _no_desc(self, name = None): + self.plugin._check_existence() - ret = self.name + ret = self.name if name is None else name if self._mpx != -1: - ret += "[" + str(self._mpx) + "]" + ret += f"[{self._mpx}]" if len(self.unit): - ret += " [" + self.unit + "]" + ret += f" [{self.unit}]" - ret += " [" + self.hints + "]: " + ret += f" [{self.hints}]: " direction = " <?> " val = self.value @@ -174,7 +232,7 @@ class Signal: conret = [] for con in self.connections: if isinstance(con, Signal): - conret += [f"{direction}{con.name} in {con._plugin._repr_no_signals()}"] + conret += [f"{direction}{con.name} in {con.plugin.show(oneliner = True)}"] if isinstance(con, ChannelMixer): conret += [f"{direction}[channel mixer]"] if len(conret) > 1: @@ -184,22 +242,6 @@ class Signal: ret += conret[0] return ret - @property - def name(self): - return self._core.name - - @property - def description(self): - return self._core.description - - @property - def unit(self): - return self._core.unit - - @property - def hints(self): - return self._hints - @property def value(self): return self._core.value @@ -210,13 +252,10 @@ class Signal: @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") + 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) @property def freq(self): @@ -225,11 +264,8 @@ class Signal: @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") + tone = 12 * math.log(val / 440, 2) + self.value = (32767 - 2400 * 6) + 200 * tone @property def dB(self): @@ -239,10 +275,7 @@ class Signal: @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") + self.value = int(4096 * (10 ** (val / 20))) @property def mult(self): @@ -250,10 +283,7 @@ class Signal: @mult.setter def mult(self, val): - if isinstance(self, SignalInput): - self.value = int(4096 * val) - else: - raise AttributeError("can't set output signal") + self.value = int(4096 * val) def start(self, velocity=32767): if self.value > 0: @@ -269,11 +299,16 @@ class SignalOutput(Signal): @Signal.value.setter def value(self, val): if val is None: + conns = self.connections self._core.disconnect() + if conns and self._dev: + return conns elif isinstance(val, SignalInput): val << self elif isinstance(val, ChannelMixer): self._core.connect_mx() + else: + raise AttributeError("can't set output signal") # fails silently bc of backwards compatibility :/ # we'll deprecate this setter entirely someday, use rshift instead @@ -293,13 +328,17 @@ class SignalOutput(Signal): class SignalInput(Signal): @Signal.value.setter def value(self, val): + conns = self.connections if val is None: self._core.disconnect() elif isinstance(val, SignalOutput): self._core.connect(val._core) elif (type(val) == int) or (type(val) == float): self._core.value = int(val) - # fails silently bc of backwards compatibility :/ + elif self._dev: + raise TypeError(f"can't connect SignalInput to {type(other)}") + if conns and self._dev: + return conns def __lshift__(self, other): if not ( @@ -315,87 +354,6 @@ class SignalInput(Signal): raise TypeError("input signals can't send data to other signals") -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): - self._list = [] - for signal_num in range(plugin._core.num_signals): - signal = _make_signal(plugin, signal_num=signal_num) - self._list.append(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 - elif getattr(self, "_setattr_allowed", True): - super().__setattr__(key, value) - else: - raise AttributeError("signal does not exist") _channel_init_callback = None @@ -406,8 +364,7 @@ def set_channel_init_callback(callback): global _channel_init_callback _channel_init_callback = callback - -class Channel: +class Channel(_plugins.PluginSpawner): _core_keys = ( "name", "num_plugins", @@ -418,93 +375,179 @@ class Channel: "callback", "compute_rms", "delete", + "dev", ) - # we are passing through a lot of methods/properties to _core, so why not subclass? - # well, the core needs to run a destructor in the engine when it is garbage collected, - # and we're not so sure if it still does that when subclassed. we never actually tested - # it, but we made bad experiences. also this allows us to hide the sys_ methods from users. - # - # maybe the proper solution would be to move this entire thing to the backend, but if we - # ever wanna play around with fancy things like (de)serialization this might lead to a bigger - # code size. it's fine for now. + class Render: + def __init__(self, core): + self._core = core + self.rms = self.RMS(core) + + def __repr__(self): + ret = self.rms.__repr__() + #ret += self.cpu.__repr__() + ret = "[render]\n" + helpers.indentify(ret) + return ret + + @property + def foreground(self): + return self._core.foreground + + @foreground.setter + def foreground(self, val): + self._core.foreground = bool(val) + + @property + def background(self): + return self._core.background_mute_override + + @background.setter + def background(self, val): + self._core.background_mute_override = bool(val) + + @property + def rms_dB(self): + if not self._core.compute_rms: + return None + ret = self._core.mean_square + if ret == 0: + return -math.inf + mult = abs(self._core.volume) / 32768 + if mult == 0: + return -math.inf + ret *= mult * mult + return 10 * math.log(ret, 10) + _rms_base + + @rms_dB.setter + def rms_dB(self, val): + self._core.compute_rms = bool(val) + + @property + def load(self): + if not self._core.compute_load: + return None + return self._core.load + + @load.setter + def load(self, val): + self._core.compute_load = bool(val) + + class RMS(): + def __init__(self, core): + self._core = core + + @property + def collect(self): + return self._core.compute_rms + + + @property + def rms_dB(self): + if not self._core.compute_rms: + return None + ret = self._core.mean_square + if ret == 0: + return -math.inf + mult = abs(self._core.volume) / 32768 + if mult == 0: + return -math.inf + ret *= mult * mult + return 10 * math.log(ret, 10) + _rms_base - def __setattr__(self, key, value): - if key in self._core_keys: - setattr(self._core, key, value) - else: - super().__setattr__(key, value) + @property + def dB(self): + if not self._core.compute_rms: + return None + ret = self._core.mean_square + if ret == 0: + return -math.inf + mult = abs(self._core.volume) / 32768 + if mult == 0: + return -math.inf + ret *= mult * mult + return 10 * math.log(ret, 10) + _rms_base - def __getattr__(self, key): - # __getattr__ is only fallback, but since we don't allow for keys in _core_keys - # to be stored within Channel this should suffice - if key in self._core_keys: - return getattr(self._core, key) - else: - raise AttributeError(f"'{type(self)}' object has no attribute {key}") + def __repr__(self): + if self.collect: + return f"rms volume: {self.dB}dB" + else: + return "rms volume: not collected" - def __init__(self, name="repl"): + class _ChannelPlugin(_plugins._Plugin): + def __init__(self): + self._core = None + + def _attach_core(self, core): + if self._core: + raise Bl00mboxError("core is already set") + self._core = core + if self.channel.dev: + self.signals = bl00mbox.SignalContainer._from_plugin(self) + else: + self.signals = bl00mbox.SignalList(self) + + @property + def render(self): + return self._render + + def __init__(self, name = "repl", dev = 0): # never ever hand out the deep core to somebody else to make sure channel gets gc'd right - self._deep_core = sys_bl00mbox.ChannelCore(name) + self._channel_plugin = self._ChannelPlugin() + self._deep_core = sys_bl00mbox.ChannelCore(name, dev, self, self._channel_plugin) self._core = self._deep_core.get_weak() + self._channel_plugin._attach_core(self._core.channel_plugin) # also don't hand out self, use this one instead self._weak_channel = WeakChannel(self._core) + if _channel_init_callback is not None: _channel_init_callback(self) - self._channel_plugin = bl00mbox._plugins._get_plugin(self._core.channel_plugin) + self._render = self.Render(self._core) + + @property + def _container(self): + return None + @property + def _spawn_core(self): + return self._core + @property def signals(self): - return self._channel_plugin._signals + return self._channel_plugin.signals def __repr__(self): - ret = f'[channel "{self.name}"]' - if self.foreground: - ret += " (foreground)" - if self.background_mute_override: - ret += " (background mute override)" - ret += "\n gain: " + str(self.gain_dB) + "dB" - b = self.num_plugins - ret += "\n plugins: " + str(b) - ret += "\n " + "\n ".join(repr(self.mixer).split("\n")) + return self.show() + + def show(self, *,patches = True, **kwargs): + ret = self.render.__repr__() + ret += "\n[patches]:" + if patches: + patches = [p.show(oneliner = True, patches = True) for p in self._core.get_patches()] + ret += "\n" + helpers.indentify(patches) + + title = f'channel "{self.name}"' + ret = f"[{title}]\n{helpers.indentify(ret)}" return ret @property def free(self): - # legacy oof - return self._core is None + # DEPRECATED + try: + self.foreground + return True + except: + return False @free.setter def free(self, val): - # bigger legacy oof + # DEPRECATED if val: - self.clear() - self._core = None - - def _new_plugin(self, thing, *args, **kwargs): - if isinstance(thing, bl00mbox._plugins._PluginDescriptor): - return bl00mbox._plugins._make_plugin( - self._weak_channel, thing.plugin_id, *args, **kwargs - ) - else: - raise TypeError("not a plugin") - - def new(self, thing, *args, **kwargs): - self.free = False - if type(thing) == type: - if issubclass(thing, bl00mbox.patches._Patch): - return thing(self._weak_channel, *args, **kwargs) - elif isinstance(thing, bl00mbox._plugins._PluginDescriptor) or ( - type(thing) == int - ): - return self._new_plugin(thing, *args, **kwargs) - else: - raise TypeError("invalid plugin/patch") + self.delete() @property def plugins(self): - for core in self._core.get_plugins(): - yield bl00mbox._plugins._get_plugin(core) + for plugin in self._core.get_plugins(): + yield plugin @property def gain_dB(self): @@ -525,31 +568,19 @@ class Channel: @property def rms_dB(self): - if self.compute_rms: - ret = self._core.mean_square - if ret == 0: - return -math.inf - else: - # volume is applied together with sys_volume - # after rms is calculated. we do want the output - # before sys_volume but after regular volume, - # so we're compensating here - mult = abs(self._core.volume) / 32768 - if mult == 0: - return -math.inf - # squaring because we're getting root later - ret *= mult * mult - return 10 * math.log(ret, 10) + _rms_base - else: - return None + return self.render.rms.dB @property def mixer(self): + if self.dev: + return None return ChannelMixer(self._core) @mixer.setter def mixer(self, val): - if isinstance(val, SignalOutput): + if self.dev: + raise Bl00mboxError("mixer is deprecated, use signals.line_out instead") + elif isinstance(val, SignalOutput): val.value = ChannelMixer(self._core) elif val is not None: # val is None: backwards compatibility, not allowed to throw exception ;w; @@ -559,16 +590,18 @@ class Channel: class WeakChannel(Channel): def __init__(self, core): self._core = core.get_weak() - self._channel_plugin = bl00mbox._plugins._get_plugin(self._core.channel_plugin) + self._channel_plugin = self._core.channel_plugin.outer self._weak_channel = self + self._render = self.Render(self._core) class SysChannel(Channel): def __init__(self, core): self._deep_core = core self._core = core.get_weak() - self._channel_plugin = bl00mbox._plugins._get_plugin(self._core.channel_plugin) + self._channel_plugin = self._core.channel_plugin.outer self._weak_channel = WeakChannel(self._core) + self._render = self.Render(self._core) @property def sys_gain_dB(self): @@ -658,3 +691,110 @@ class Sys: for core in sys_bl00mbox.collect_channels(True): if core.callback and core.sys_gain: yield core.callback + +# +# +# END OF NONDEPRECATED CODE +# +# ONLY LEGACY GARBAGE DOWN HERE +# +# + +class ChannelMixer: + # DEPRECATED + def __init__(self, core): + self._core = core + + def __repr__(self): + ret = f"[channel mixer] ({len(self.connections)} connections)" + for con in self.connections: + ret += f"\n {con.name} in {con.plugin.show(oneliner = True)}" + return ret + + @property + def connections(self): + return self._core.get_connected_mx() + +class SignalMpxList: + # DEPRECATED + 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: + # DEPRECATED + def __init__(self, plugin): + self._list = [] + for signal_num in range(plugin._core.num_signals): + signal = Signal._from_plugin(plugin, signal_num) + self._list.append(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 + elif getattr(self, "_setattr_allowed", True): + super().__setattr__(key, value) + else: + raise AttributeError("signal does not exist") diff --git a/components/bl00mbox/micropython/mp_sys_bl00mbox.c b/components/bl00mbox/micropython/mp_sys_bl00mbox.c index 17bdc2981736c7087529676f15800bcdaded981d..76b3e75ae1d3c3cadaf066536b1cb0e13ab3a794 100644 --- a/components/bl00mbox/micropython/mp_sys_bl00mbox.c +++ b/components/bl00mbox/micropython/mp_sys_bl00mbox.c @@ -19,19 +19,19 @@ MP_DEFINE_EXCEPTION(ReferenceError, Exception) typedef struct _channel_core_obj_t { mp_obj_base_t base; + mp_obj_t outer; + // will be NULLed on original if channel has been manually deleted // both for weak and regular - bl00mbox_channel_t *chan; - + bl00mbox_channel_t * chan; // pointer to object that weakly references original channel object // there is no more than one weak channel reference obj per channel mp_obj_t weak; + // list of all sources connect to the mixer to avoid gc + mp_obj_t sources_mx; - // things we don't want garbage collected: - // - channel plugin mp_obj_t channel_plugin; - // - list of all sources connect to the mixer - mp_obj_t sources_mx; + mp_obj_t name; #ifdef BL00MBOX_CALLBACKS_FUNSAFE // the channel may be become reachable after having been unreachable. @@ -53,11 +53,17 @@ typedef struct _plugin_core_obj_t { // important note: the plugin may have been garbage collected along with // its channel or it might have been deleted, in either case this pointer // is set to NULL, so you need to check before using it. if you do anything - // that might trigger a gc (like creating objects) you need to check this - // pointer for NULL again. - bl00mbox_plugin_t *plugin; - // list of all source plugins to avoid gc + // that might trigger a gc (like creating objects) you need to check this pointer + // for NULL again. + bl00mbox_plugin_t * plugin; + mp_obj_t outer; + // list of all signals + mp_obj_t signals; + mp_obj_t name; + + // refs purely to avoid gc mp_obj_t sources; + mp_obj_t container; } plugin_core_obj_t; STATIC const mp_obj_type_t plugin_core_type; @@ -65,101 +71,164 @@ STATIC const mp_obj_type_t plugin_core_type; typedef struct _signal_core_obj_t { mp_obj_base_t base; mp_obj_t plugin_core; - // same rules for garbage collection as for plugin_core_obj_t apply here - // too, call plugin_core_verify() on plugin_core after each potential - // garbage collection keeping a direct reference to keep the plugin alive as - // long as there's a signal in reach (unless the channel gets gc'd of - // course) + mp_obj_t outer; + // same rules for garbage collection as for plugin_core_obj_t apply here too, + // call plugin_core_verify() on plugin_core after each potential garbage collection + // keeping a direct reference to keep the plugin alive as long as there's + // a signal in reach (unless the channel gets gc'd of course) bl00mbox_signal_t signal; } signal_core_obj_t; STATIC const mp_obj_type_t signal_core_type; -STATIC mp_obj_t signal_core_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *args); +typedef struct _patch_core_obj_t { + mp_obj_base_t base; + mp_obj_t outer; + mp_obj_t weak_channel; + bl00mbox_patch_t * patch; + mp_obj_t name; + mp_obj_t patch_name; + mp_obj_t container; +} patch_core_obj_t; + +STATIC const mp_obj_type_t patch_core_type; + +// ======================== +// HELPERS +// ======================== -static inline void channel_core_verify(channel_core_obj_t *channel_core) { - if (!channel_core->chan) - mp_raise_msg(&mp_type_ReferenceError, - MP_ERROR_TEXT("channel was deleted")); +STATIC mp_obj_t _signal_core_make_new(plugin_core_obj_t * plugin_core, int index); +static mp_obj_t create_channel_plugin(channel_core_obj_t * chan_core, mp_obj_t outer); + +static inline void channel_core_verify(channel_core_obj_t * channel_core){ + if(!channel_core->chan) mp_raise_msg(&mp_type_ReferenceError, MP_ERROR_TEXT("channel was deleted")); +} + +static inline void plugin_core_verify(plugin_core_obj_t * plugin_core){ + // note: PluginCore.channel assumes this also verifies channel + if(!plugin_core->plugin) mp_raise_msg(&mp_type_ReferenceError, MP_ERROR_TEXT("plugin was deleted")); +} + +static inline void patch_core_verify(patch_core_obj_t * patch_core){ + // note: PatchCore.channel assumes this also verifies channel + if(!patch_core->patch) mp_raise_msg(&mp_type_ReferenceError, MP_ERROR_TEXT("patch was deleted")); +} + +static inline channel_core_obj_t * get_channel_core(mp_obj_t channel_core){ + channel_core_obj_t * self = MP_OBJ_TO_PTR(channel_core); + if(self->base.type != &channel_core_type){ + mp_raise_TypeError(MP_ERROR_TEXT("argument must be ChannelCore")); + } + channel_core_verify(self); + return self; } -static inline void plugin_core_verify(plugin_core_obj_t *plugin_core) { - if (!plugin_core->plugin) - mp_raise_msg(&mp_type_ReferenceError, - MP_ERROR_TEXT("plugin was deleted")); +static inline bl00mbox_patch_t * get_patch(mp_obj_t container){ + if (container == mp_const_none) return NULL; + patch_core_obj_t * self = MP_OBJ_TO_PTR(container); + if(self->base.type == &channel_core_type) return NULL; + if(self->base.type == &patch_core_type){ + patch_core_verify(self); + return self->patch; + } + mp_raise_TypeError(MP_ERROR_TEXT("argument must be PatchCore, ChannelCore or None")); } -static void bl00mbox_error_unwrap(bl00mbox_error_t error) { - switch (error) { +static void bl00mbox_error_unwrap(bl00mbox_error_t error){ + switch(error){ case BL00MBOX_ERROR_OOM: mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("out of memory")); case BL00MBOX_ERROR_INVALID_CONNECTION: mp_raise_TypeError(MP_ERROR_TEXT("can't connect that")); case BL00MBOX_ERROR_INVALID_IDENTIFIER: mp_raise_TypeError(MP_ERROR_TEXT("bad identifier")); - default:; + default: + ; } } -void bl00mbox_disconnect_rx_callback(void *rx, uint16_t signal_index) { - plugin_core_obj_t *self = rx; - mp_obj_list_t *list = MP_OBJ_TO_PTR(self->sources); - if (signal_index < list->len) { +void bl00mbox_disconnect_rx_callback(void * rx, uint16_t signal_index){ + plugin_core_obj_t * self = rx; + mp_obj_list_t * list = MP_OBJ_TO_PTR(self->sources); + if(signal_index < list->len){ list->items[signal_index] = mp_const_none; } else { bl00mbox_log_error("plugin signal list too short"); } } -void bl00mbox_connect_rx_callback(void *rx, void *tx, uint16_t signal_index) { - plugin_core_obj_t *self = rx; - mp_obj_list_t *list = MP_OBJ_TO_PTR(self->sources); - if (signal_index < list->len) { +void bl00mbox_connect_rx_callback(void * rx, void * tx, uint16_t signal_index){ + plugin_core_obj_t * self = rx; + mp_obj_list_t * list = MP_OBJ_TO_PTR(self->sources); + if(signal_index < list->len){ list->items[signal_index] = MP_OBJ_FROM_PTR(tx); } else { bl00mbox_log_error("plugin signal list too short"); } } -void bl00mbox_disconnect_mx_callback(void *chan, void *tx) { - channel_core_obj_t *self = chan; +void bl00mbox_disconnect_mx_callback(void * chan, void * tx){ + channel_core_obj_t * self = chan; // don't have to check for duplicates, bl00mbox_user does that for us mp_obj_list_remove(self->sources_mx, MP_OBJ_FROM_PTR(tx)); } -void bl00mbox_connect_mx_callback(void *chan, void *tx) { - channel_core_obj_t *self = chan; +void bl00mbox_connect_mx_callback(void * chan, void * tx){ + channel_core_obj_t * self = chan; // don't have to check for duplicates, bl00mbox_user does that for us mp_obj_list_append(self->sources_mx, MP_OBJ_FROM_PTR(tx)); } -static char *strdup_raise(char *str) { - char *ret = strdup(str); - if (!ret) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); +static char * strdup_raise(char * str){ + char * ret = strdup(str); + if(!ret) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); return ret; } -static mp_obj_t get_connections_from_array(bl00mbox_array_t *array) { - if (!array) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); - if (array->len) { +static mp_obj_t get_patches_from_container(bl00mbox_patch_container_t * container){ + bl00mbox_array_t * array = bl00mbox_parents_from_patch_container(container); + if(!array) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); + if(array->len){ + int len = array->len; + mp_obj_t elems[len]; + bool fail = false; + for(int i = 0; i < len; i++){ + plugin_core_obj_t * core = MP_OBJ_TO_PTR(array->elems[i]); + if(core->base.type == &plugin_core_type){ + elems[i] = core->outer; + } else if(core->base.type == &patch_core_type){ + elems[i] = ((patch_core_obj_t * ) core)->outer; + } else { + fail = true; + } + } + free(array); + if(fail) mp_raise_TypeError(MP_ERROR_TEXT("patch list core type mismatch")); + + return mp_obj_new_list(len, elems); + } else { + free(array); + return mp_obj_new_list(0, NULL); + } +} + +static mp_obj_t get_connections_from_array(bl00mbox_array_t * array){ + if(!array) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); + if(array->len){ int len = array->len; - bl00mbox_signal_t *signals[len]; + bl00mbox_signal_t * signals[len]; memcpy(&signals, &array->elems, sizeof(void *) * len); // need to free before we can longjump free(array); mp_obj_t elems[len]; int output_index = 0; - for (int i = 0; i < len; i++) { - plugin_core_obj_t *core = signals[i]->plugin->parent; + for(int i = 0; i < len; i++){ + plugin_core_obj_t * pc = signals[i]->plugin->parent; // gc can happen during this loop. the objects we created are safe - // as they are on the stack, but unprocessed signals might've been - // collected - if (!core->plugin) continue; - mp_obj_t args[2] = { MP_OBJ_FROM_PTR(core), - mp_obj_new_int(signals[i]->index) }; - elems[output_index] = - signal_core_make_new(&signal_core_type, 2, 0, args); + // as they are on the stack, but unprocessed signals might've been collected + if(!pc->plugin) continue; + signal_core_obj_t * sc = MP_OBJ_TO_PTR(mp_obj_subscr(pc->signals, mp_obj_new_int(i), MP_OBJ_SENTINEL)); + elems[output_index] = sc->outer; output_index++; } return mp_obj_new_list(output_index, elems); @@ -169,21 +238,21 @@ static mp_obj_t get_connections_from_array(bl00mbox_array_t *array) { } } -static mp_obj_t get_plugins_from_array(bl00mbox_array_t *array) { - if (!array) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); - if (array->len) { +static mp_obj_t get_plugins_from_array(bl00mbox_array_t * array){ + if(!array) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); + if(array->len){ int len = array->len; - bl00mbox_plugin_t *plugins[len]; + bl00mbox_plugin_t * plugins[len]; memcpy(&plugins, &array->elems, sizeof(void *) * len); // need to free before we can longjump free(array); mp_obj_t elems[len]; int output_index = 0; - for (int i = 0; i < len; i++) { - plugin_core_obj_t *core = plugins[i]->parent; + for(int i = 0; i < len; i++){ + plugin_core_obj_t * core = plugins[i]->parent; // gc shouldn't happen during this loop but we keep it in anyways :3 - if (!core->plugin) continue; - elems[output_index] = MP_OBJ_FROM_PTR(core); + if(!core->plugin) continue; + elems[output_index] = core->outer; output_index++; } return mp_obj_new_list(output_index, elems); @@ -241,27 +310,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_plugin_registry_num_plugins_obj, // CHANNELS // ======================== -static mp_obj_t create_channel_plugin(bl00mbox_channel_t *chan) { - plugin_core_obj_t *self = m_new_obj_with_finaliser(plugin_core_obj_t); - self->base.type = &plugin_core_type; - self->plugin = chan->channel_plugin; - self->plugin->parent = self; - self->plugin->parent_self_ref = &self->plugin; - - size_t num_signals = self->plugin->rugin->len_signals; - mp_obj_t nones[num_signals]; - for (size_t i = 0; i < num_signals; i++) nones[i] = mp_const_none; - self->sources = mp_obj_new_list(num_signals, nones); - - return MP_OBJ_FROM_PTR(self); -} - -static mp_obj_t create_weak_channel_core(channel_core_obj_t *self) { - channel_core_obj_t *weak = m_new_obj_with_finaliser(channel_core_obj_t); +static mp_obj_t create_weak_channel_core(channel_core_obj_t * self) { + channel_core_obj_t * weak = m_new_obj_with_finaliser(channel_core_obj_t); weak->base.type = &channel_core_type; weak->weak = MP_OBJ_FROM_PTR(weak); weak->chan = self->chan; - weak->chan->weak_parent_self_ref = &weak->chan; + weak->chan->weak_ref.self_ref = &weak->chan; + + weak->outer = MP_OBJ_NULL; + weak->name = MP_OBJ_NULL; // only the real channel should prevent these from being gc'd weak->sources_mx = MP_OBJ_NULL; @@ -274,43 +331,45 @@ static mp_obj_t create_weak_channel_core(channel_core_obj_t *self) { STATIC mp_obj_t channel_core_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, 1, false); - channel_core_obj_t *self = m_new_obj_with_finaliser(channel_core_obj_t); - self->chan = NULL; // must initialize if obj gets gc'd due to exception + mp_arg_check_num(n_args, n_kw, 4, 4, false); + channel_core_obj_t * self = m_new_obj_with_finaliser(channel_core_obj_t); + self->chan = NULL; // must initialize if obj gets gc'd due to exception self->base.type = &channel_core_type; self->sources_mx = mp_obj_new_list(0, NULL); - const char *name = strdup_raise(mp_obj_str_get_str(args[0])); + self->name = args[0]; + char * name = mp_obj_str_get_str(self->name); + int32_t dev = mp_obj_get_int(args[1]); - bl00mbox_channel_t *chan = bl00mbox_channel_create(); - if (!chan) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); + bl00mbox_channel_t * chan = bl00mbox_channel_create(); + if(!chan) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); - chan->name = name; - chan->parent_self_ref = &self->chan; + chan->dev = dev; + chan->ref.self_ref = &self->chan; chan->parent = self; + self->outer = args[2]; self->chan = chan; self->weak = create_weak_channel_core(self); - self->channel_plugin = create_channel_plugin(chan); + self->channel_plugin = create_channel_plugin(self, args[3]); #ifdef BL00MBOX_CALLBACKS_FUNSAFE self->callback = mp_const_none; #endif - bl00mbox_log_info("created channel %s", chan->name); + bl00mbox_log_info("created channel %s", name); return MP_OBJ_FROM_PTR(self); } STATIC mp_obj_t mp_channel_core_get_weak(mp_obj_t self_in) { - channel_core_obj_t *self = MP_OBJ_TO_PTR(self_in); + channel_core_obj_t * self = MP_OBJ_TO_PTR(self_in); channel_core_verify(self); return self->weak; } -MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_get_weak_obj, - mp_channel_core_get_weak); +MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_get_weak_obj, mp_channel_core_get_weak); mp_obj_t mp_channel_core_del(mp_obj_t self_in) { - channel_core_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->chan && (self->weak != self_in)) { - bl00mbox_log_info("destroyed channel %s", self->chan->name); + channel_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + if(self->chan && (self->weak != self_in)){ + bl00mbox_log_info("destroyed channel"); bl00mbox_channel_destroy(self->chan); } return mp_const_none; @@ -318,16 +377,16 @@ mp_obj_t mp_channel_core_del(mp_obj_t self_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_del_obj, mp_channel_core_del); mp_obj_t mp_channel_core_delete(mp_obj_t self_in) { - channel_core_obj_t *self = MP_OBJ_TO_PTR(self_in); + channel_core_obj_t * self = MP_OBJ_TO_PTR(self_in); channel_core_verify(self); - bl00mbox_log_info("destroyed channel %s", self->chan->name); + bl00mbox_log_info("destroyed channel"); bl00mbox_channel_destroy(self->chan); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_delete_obj, mp_channel_core_delete); -mp_obj_t mp_channel_core_clear(mp_obj_t self_in) { - channel_core_obj_t *self = MP_OBJ_TO_PTR(self_in); +mp_obj_t mp_channel_core_clear(mp_obj_t self_in){ + channel_core_obj_t * self = MP_OBJ_TO_PTR(self_in); channel_core_verify(self); self->callback = mp_const_none; bl00mbox_channel_clear(self->chan); @@ -335,32 +394,36 @@ mp_obj_t mp_channel_core_clear(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_clear_obj, mp_channel_core_clear); -STATIC mp_obj_t mp_channel_core_get_connected_mx(mp_obj_t self_in) { - channel_core_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t mp_channel_core_get_connected_mx(mp_obj_t self_in){ + channel_core_obj_t * self = MP_OBJ_TO_PTR(self_in); channel_core_verify(self); - bl00mbox_array_t *array = - bl00mbox_channel_collect_connections_mx(self->chan); + bl00mbox_array_t * array = bl00mbox_channel_collect_connections_mx(self->chan); return get_connections_from_array(array); } -MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_get_connected_mx_obj, - mp_channel_core_get_connected_mx); +MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_get_connected_mx_obj, mp_channel_core_get_connected_mx); -STATIC mp_obj_t mp_channel_core_get_plugins(mp_obj_t self_in) { - channel_core_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t mp_channel_core_get_patches(mp_obj_t self_in){ + channel_core_obj_t * self = MP_OBJ_TO_PTR(self_in); channel_core_verify(self); - bl00mbox_array_t *array = bl00mbox_channel_collect_plugins(self->chan); - return get_plugins_from_array(array); + return get_patches_from_container(&self->chan->patches); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_get_patches_obj, mp_channel_core_get_patches); + +static inline channel_core_obj_t * strong(bl00mbox_channel_t * chan){ + return chan->parent; +} + +static inline channel_core_obj_t * strong_obj(mp_obj_t core){ + return ((channel_core_obj_t *) MP_OBJ_TO_PTR(core))->chan->parent; } -MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_core_get_plugins_obj, - mp_channel_core_get_plugins); -STATIC void channel_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - channel_core_obj_t *self = MP_OBJ_TO_PTR(self_in); - bl00mbox_channel_t *chan = self->chan; +STATIC void channel_core_attr(mp_obj_t self_in, qstr attr, + mp_obj_t *dest) { + channel_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + bl00mbox_channel_t * chan = self->chan; - // if gc_sweep tries to load __del__ we mustn't raise exceptions, setjmp - // isn't set up - if (attr != MP_QSTR___del__) channel_core_verify(self); + // if gc_sweep tries to load __del__ we mustn't raise exceptions, setjmp isn't set up + if(attr != MP_QSTR___del__) channel_core_verify(self); if (dest[0] != MP_OBJ_NULL) { bool attr_exists = true; @@ -370,24 +433,27 @@ STATIC void channel_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } else if (attr == MP_QSTR_sys_gain) { int gain = abs(mp_obj_get_int(dest[1])); chan->sys_gain = gain > 32767 ? 32767 : gain; + } else if (attr == MP_QSTR_compute_load) { + chan->compute_time = mp_obj_is_true(dest[1]); } else if (attr == MP_QSTR_compute_rms) { chan->compute_rms = mp_obj_is_true(dest[1]); - if (!chan->compute_rms) chan->mean_square = 0; + if(!chan->compute_rms) chan->mean_square = 0; } else if (attr == MP_QSTR_background_mute_override) { - bl00mbox_channel_set_background_mute_override( - chan, mp_obj_is_true(dest[1])); + bl00mbox_channel_set_background_mute_override(chan, mp_obj_is_true(dest[1])); } else if (attr == MP_QSTR_foreground) { bl00mbox_channel_set_foreground(chan, mp_obj_is_true(dest[1])); #ifdef BL00MBOX_CALLBACKS_FUNSAFE } else if (attr == MP_QSTR_callback) { - ((channel_core_obj_t *)chan->parent)->callback = dest[1]; + strong(chan)->callback = dest[1]; #endif } else { attr_exists = false; } - if (attr_exists) dest[0] = MP_OBJ_NULL; + if(attr_exists) dest[0] = MP_OBJ_NULL; } else { - if (attr == MP_QSTR_volume) { + if (attr == MP_QSTR_outer){ + dest[0] = strong(chan)->outer; + } else if (attr == MP_QSTR_volume) { dest[0] = mp_obj_new_int(chan->volume); } else if (attr == MP_QSTR_sys_gain) { dest[0] = mp_obj_new_int(chan->sys_gain); @@ -395,15 +461,19 @@ STATIC void channel_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = mp_obj_new_int(chan->mean_square); } else if (attr == MP_QSTR_compute_rms) { dest[0] = mp_obj_new_bool(chan->compute_rms); + } else if (attr == MP_QSTR_dev) { + dest[0] = mp_obj_new_int(chan->dev); + } else if (attr == MP_QSTR_compute_load) { + dest[0] = mp_obj_new_bool(chan->compute_time); + } else if (attr == MP_QSTR_load) { + dest[0] = mp_obj_new_float(((float) chan->time)/BL00MBOX_REF_TIME); } else if (attr == MP_QSTR_name) { - char *ret = strdup_raise(chan->name); - dest[0] = mp_obj_new_str(ret, strlen(ret)); - free(ret); + dest[0] = strong(chan)->name; } else if (attr == MP_QSTR_channel_plugin) { - dest[0] = ((channel_core_obj_t *)chan->parent)->channel_plugin; + dest[0] = strong(chan)->channel_plugin; } else if (attr == MP_QSTR_callback) { #ifdef BL00MBOX_CALLBACKS_FUNSAFE - dest[0] = ((channel_core_obj_t *)chan->parent)->callback; + dest[0] = ((channel_core_obj_t *) chan->parent)->callback; #else dest[0] = mp_const_none; #endif @@ -421,41 +491,36 @@ STATIC void channel_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[1] = MP_OBJ_SENTINEL; } } -} +} STATIC const mp_rom_map_elem_t channel_core_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_channel_core_del_obj) }, { MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&mp_channel_core_delete_obj) }, { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&mp_channel_core_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_weak), - MP_ROM_PTR(&mp_channel_core_get_weak_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_connected_mx), - MP_ROM_PTR(&mp_channel_core_get_connected_mx_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_plugins), - MP_ROM_PTR(&mp_channel_core_get_plugins_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_weak), MP_ROM_PTR(&mp_channel_core_get_weak_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_connected_mx), MP_ROM_PTR(&mp_channel_core_get_connected_mx_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_patches), MP_ROM_PTR(&mp_channel_core_get_patches_obj) }, }; STATIC MP_DEFINE_CONST_DICT(channel_core_locals_dict, channel_core_locals_dict_table); -STATIC MP_DEFINE_CONST_OBJ_TYPE(channel_core_type, MP_QSTR_ChannelCore, - MP_TYPE_FLAG_NONE, make_new, - channel_core_make_new, locals_dict, - &channel_core_locals_dict, attr, - channel_core_attr); - -static mp_obj_t mp_collect_channels(mp_obj_t active_in) { - // critical phase: make sure to not trigger any garbage collection until - // these are on the stack!! - bl00mbox_array_t *chans = - bl00mbox_collect_channels(mp_obj_is_true(active_in)); +STATIC MP_DEFINE_CONST_OBJ_TYPE(channel_core_type, MP_QSTR_ChannelCore, MP_TYPE_FLAG_NONE, + make_new, channel_core_make_new, + locals_dict, &channel_core_locals_dict, + attr, channel_core_attr); + +static mp_obj_t mp_collect_channels(mp_obj_t active_in){ + // critical phase: make sure to not trigger any garbage collection until these + // are on the stack!! + bl00mbox_array_t * chans = bl00mbox_collect_channels(mp_obj_is_true(active_in)); mp_obj_t ret = MP_OBJ_NULL; - if (chans && chans->len) { + if(chans && chans->len){ mp_obj_t elems[chans->len]; size_t output_index = 0; - for (size_t input_index = 0; input_index < chans->len; input_index++) { - bl00mbox_channel_t *chan = chans->elems[input_index]; - channel_core_obj_t *core = chan->parent; - if (core->base.type != &channel_core_type) { + for(size_t input_index = 0; input_index < chans->len; input_index++){ + bl00mbox_channel_t * chan = chans->elems[input_index]; + channel_core_obj_t * core = chan->parent; + if(core->base.type != &channel_core_type){ bl00mbox_log_error("channel core corrupted"); continue; } @@ -469,56 +534,84 @@ static mp_obj_t mp_collect_channels(mp_obj_t active_in) { free(chans); return ret; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_collect_channels_obj, mp_collect_channels); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_collect_channels_obj, + mp_collect_channels); // ======================== // PLUGINS // ======================== +static mp_obj_t create_channel_plugin(channel_core_obj_t * chan_core, mp_obj_t outer){ + bl00mbox_channel_t * chan = chan_core->chan; + plugin_core_obj_t * self = m_new_obj_with_finaliser(plugin_core_obj_t); + self->base.type = &plugin_core_type; + self->plugin = chan->channel_plugin; + self->plugin->parent = self; + self->plugin->ref.self_ref = &self->plugin; + + self->outer = outer; + + size_t num_signals = self->plugin->rugin->len_signals; + mp_obj_t elems[num_signals]; + for(size_t i = 0; i < num_signals; i++) elems[i] = mp_const_none; + self->sources = mp_obj_new_list(num_signals, elems); + for(size_t i = 0; i < num_signals; i++) elems[i] = _signal_core_make_new(self, i); + self->signals = mp_obj_new_tuple(num_signals, elems); + + return MP_OBJ_FROM_PTR(self); +} + STATIC mp_obj_t plugin_core_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 3, 3, false); - plugin_core_obj_t *self = m_new_obj_with_finaliser(plugin_core_obj_t); + size_t n_kw, const mp_obj_t *args) { + // args: ChannelCore, outer, container, plugin_type_id, init_var, [nick] + mp_arg_check_num(n_args, n_kw, 5, 6, false); + plugin_core_obj_t * self = m_new_obj_with_finaliser(plugin_core_obj_t); self->base.type = &plugin_core_type; + self->outer = args[1]; - channel_core_obj_t *chan_core = MP_OBJ_TO_PTR(args[0]); - if (chan_core->base.type != &channel_core_type) { - mp_raise_TypeError(MP_ERROR_TEXT("first argument must be ChannelCore")); - } - channel_core_verify(chan_core); - bl00mbox_channel_t *chan = chan_core->chan; - int plugin_kind = mp_obj_get_int(args[1]); - int init_var = mp_obj_get_int(args[2]); + channel_core_obj_t * chan_core = get_channel_core(args[0]); + bl00mbox_channel_t * chan = chan_core->chan; - bl00mbox_plugin_t *plugin = - bl00mbox_plugin_create(chan, plugin_kind, init_var); + bl00mbox_patch_t * container = get_patch(args[2]); + self->container = container ? args[2] : mp_const_none; - if (!plugin) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); + int plugin_type_id = mp_obj_get_int(args[3]); + int init_var = mp_obj_get_int(args[4]); + + bl00mbox_plugin_t * plugin = bl00mbox_plugin_create(chan, container, plugin_type_id, init_var); + + if(!plugin) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); self->plugin = plugin; plugin->parent = self; - plugin->parent_self_ref = &self->plugin; + plugin->ref.self_ref = &self->plugin; + + if(n_kw > 5 && args[5] != mp_const_none){ + self->name = args[5]; + } else { + char * name = plugin->rugin->descriptor->name; + self->name = mp_obj_new_str(name, strlen(name)); + } - // create empty source list size_t num_signals = plugin->rugin->len_signals; - mp_obj_t nones[num_signals]; - for (size_t i = 0; i < num_signals; i++) nones[i] = mp_const_none; - self->sources = mp_obj_new_list(num_signals, nones); + mp_obj_t elems[num_signals]; + + for(size_t i = 0; i < num_signals; i++) elems[i] = mp_const_none; + self->sources = mp_obj_new_list(num_signals, elems); - bl00mbox_log_info("created plugin %s", - self->plugin->rugin->descriptor->name); + for(size_t i = 0; i < num_signals; i++) elems[i] = _signal_core_make_new(self, i); + self->signals = mp_obj_new_tuple(num_signals, elems); + + bl00mbox_log_info("created plugin %s", self->plugin->rugin->descriptor->name); return MP_OBJ_FROM_PTR(self); } mp_obj_t mp_plugin_core_del(mp_obj_t self_in) { - plugin_core_obj_t *self = MP_OBJ_TO_PTR(self_in); - // do not verify here as it will result in prints from the gc if the channel - // object was already collected. don't gc the channel plugin, it is deleted - // with the channel. - if (self->plugin && - (self->plugin->rugin->descriptor->id != BL00MBOX_CHANNEL_PLUGIN_ID)) { - bl00mbox_log_info("deleted plugin %s", - self->plugin->rugin->descriptor->name); + plugin_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + // do not verify here as it will result in prints from the gc if the channel object + // was already collected. don't gc the channel plugin, it is deleted with the channel. + if(self->plugin && (self->plugin->rugin->descriptor->id != BL00MBOX_CHANNEL_PLUGIN_ID)){ + bl00mbox_log_info("deleted plugin %s", self->plugin->rugin->descriptor->name); bl00mbox_plugin_destroy(self->plugin); } return mp_const_none; @@ -526,11 +619,10 @@ mp_obj_t mp_plugin_core_del(mp_obj_t self_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_plugin_core_del_obj, mp_plugin_core_del); mp_obj_t mp_plugin_core_delete(mp_obj_t self_in) { - plugin_core_obj_t *self = MP_OBJ_TO_PTR(self_in); + plugin_core_obj_t * self = MP_OBJ_TO_PTR(self_in); plugin_core_verify(self); - if (self->plugin->rugin->descriptor->id == BL00MBOX_CHANNEL_PLUGIN_ID) { - mp_raise_TypeError( - MP_ERROR_TEXT("cannot manually delete channel plugin")); + if(self->plugin->rugin->descriptor->id == BL00MBOX_CHANNEL_PLUGIN_ID){ + mp_raise_TypeError(MP_ERROR_TEXT("cannot manually delete channel plugin")); } bl00mbox_log_info("deleted plugin"); bl00mbox_plugin_destroy(self->plugin); @@ -538,30 +630,57 @@ mp_obj_t mp_plugin_core_delete(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(mp_plugin_core_delete_obj, mp_plugin_core_delete); -STATIC void plugin_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - plugin_core_obj_t *self = MP_OBJ_TO_PTR(self_in); - bl00mbox_plugin_t *plugin = self->plugin; +mp_obj_t mp_plugin_core_get_sources(mp_obj_t self_in) { + plugin_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + bl00mbox_plugin_t * plugin = self->plugin; + plugin_core_verify(self); + int max_len = plugin->rugin->len_signals; + int index = 0; + mp_obj_t elems[max_len]; + mp_obj_list_t * list = MP_OBJ_TO_PTR(self->sources); + for(int x = 0; x < max_len; x++){ + mp_obj_t elem = list->items[x]; + if(elem != mp_const_none){ + elems[index] = elem; + index++; + } + } + return mp_obj_new_list(index, elems); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_plugin_core_get_sources_obj, mp_plugin_core_get_sources); + +STATIC void plugin_core_attr(mp_obj_t self_in, qstr attr, + mp_obj_t *dest) { + plugin_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + bl00mbox_plugin_t * plugin = self->plugin; - // if gc_sweep tries to load __del__ we mustn't raise exceptions, setjmp - // isn't set up - if (attr != MP_QSTR___del__) plugin_core_verify(self); + // if gc_sweep tries to load __del__ we mustn't raise exceptions, setjmp isn't set up + if(attr != MP_QSTR___del__) plugin_core_verify(self); if (dest[0] != MP_OBJ_NULL) { if (attr == MP_QSTR_always_render) { bl00mbox_plugin_set_always_render(plugin, mp_obj_is_true(dest[1])); dest[0] = MP_OBJ_NULL; - } + } } else { if (attr == MP_QSTR_name) { + dest[0] = self->name; + } else if (attr == MP_QSTR_plugin_name) { // no need to strdup here, descriptors don't die - char *ret = plugin->rugin->descriptor->name; + char * ret = plugin->rugin->descriptor->name; dest[0] = mp_obj_new_str(ret, strlen(ret)); } else if (attr == MP_QSTR_id) { dest[0] = mp_obj_new_int(plugin->id); + } else if (attr == MP_QSTR_signal_cores) { + dest[0] = self->signals; } else if (attr == MP_QSTR_plugin_id) { dest[0] = mp_obj_new_int(plugin->rugin->descriptor->id); } else if (attr == MP_QSTR_init_var) { dest[0] = mp_obj_new_int(plugin->init_var); + } else if (attr == MP_QSTR_outer) { + dest[0] = self->outer; + } else if (attr == MP_QSTR_channel) { + dest[0] = strong(plugin->channel)->outer; } else if (attr == MP_QSTR_num_signals) { dest[0] = mp_obj_new_int(plugin->rugin->len_signals); } else if (attr == MP_QSTR_always_render) { @@ -570,51 +689,44 @@ STATIC void plugin_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = mp_obj_new_int(plugin->rugin->plugin_table_len); } else if (attr == MP_QSTR_table_pointer) { // if there's no table this returns 0, which is fine by us - int16_t *ret = plugin->rugin->plugin_table; - dest[0] = mp_obj_new_int_from_uint((uint32_t)ret); + int16_t * ret = plugin->rugin->plugin_table; + dest[0] = mp_obj_new_int_from_uint((uint32_t) ret); } else { dest[1] = MP_OBJ_SENTINEL; } } -} +} STATIC const mp_rom_map_elem_t plugin_core_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_plugin_core_del_obj) }, { MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&mp_plugin_core_delete_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_sources), MP_ROM_PTR(&mp_plugin_core_get_sources_obj) }, }; STATIC MP_DEFINE_CONST_DICT(plugin_core_locals_dict, plugin_core_locals_dict_table); -STATIC MP_DEFINE_CONST_OBJ_TYPE(plugin_core_type, MP_QSTR_PluginCore, - MP_TYPE_FLAG_NONE, make_new, - plugin_core_make_new, locals_dict, - &plugin_core_locals_dict, attr, - plugin_core_attr); +STATIC MP_DEFINE_CONST_OBJ_TYPE(plugin_core_type, MP_QSTR_PluginCore, MP_TYPE_FLAG_NONE, + make_new, plugin_core_make_new, + locals_dict, &plugin_core_locals_dict, + attr, plugin_core_attr); + // ======================== // SIGNALS // ======================== -STATIC mp_obj_t signal_core_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 2, 2, false); - - plugin_core_obj_t *plugin_core = MP_OBJ_TO_PTR(args[0]); - if (plugin_core->base.type != &plugin_core_type) { - mp_raise_TypeError(MP_ERROR_TEXT("first argument must be PluginCore")); - } +STATIC mp_obj_t _signal_core_make_new(plugin_core_obj_t * plugin_core, int index){ // do this before verification - signal_core_obj_t *self = m_new_obj(signal_core_obj_t); - int index = mp_obj_get_int(args[1]); + signal_core_obj_t * self = m_new_obj(signal_core_obj_t); plugin_core_verify(plugin_core); - - radspa_t *rugin = plugin_core->plugin->rugin; - if (index >= rugin->len_signals) { - mp_raise_msg(&mp_type_IndexError, - MP_ERROR_TEXT("signal index out of range")); + + radspa_t * rugin = plugin_core->plugin->rugin; + if(index >= rugin->len_signals){ + mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("signal index out of range")); } self->base.type = &signal_core_type; + self->outer = mp_const_none; self->plugin_core = plugin_core; self->signal.rignal = &rugin->signals[index]; self->signal.plugin = plugin_core->plugin; @@ -622,91 +734,105 @@ STATIC mp_obj_t signal_core_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(self); } -STATIC mp_obj_t mp_signal_core_connect(mp_obj_t self_in, mp_obj_t other_in) { - signal_core_obj_t *self = MP_OBJ_TO_PTR(self_in); +/* +STATIC mp_obj_t signal_core_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 2, false); + + plugin_core_obj_t * plugin_core = MP_OBJ_TO_PTR(args[0]); + int index = mp_obj_get_int(args[1]); + if(plugin_core->base.type != &plugin_core_type){ + mp_raise_TypeError(MP_ERROR_TEXT("first argument must be PluginCore")); + } + return mp_obj_subscr(plugin_core->signals, mp_obj_new_int(index), MP_OBJ_SENTINEL); +} +*/ + +STATIC mp_obj_t mp_signal_core_connect(mp_obj_t self_in, mp_obj_t other_in){ + signal_core_obj_t * self = MP_OBJ_TO_PTR(self_in); plugin_core_verify(MP_OBJ_TO_PTR(self->plugin_core)); - signal_core_obj_t *other = MP_OBJ_TO_PTR(other_in); + signal_core_obj_t * other = MP_OBJ_TO_PTR(other_in); plugin_core_verify(MP_OBJ_TO_PTR(other->plugin_core)); - bl00mbox_error_unwrap( - bl00mbox_signal_connect(&self->signal, &other->signal)); + bl00mbox_error_unwrap(bl00mbox_signal_connect(&self->signal, &other->signal)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(mp_signal_core_connect_obj, mp_signal_core_connect); // legacy support -STATIC mp_obj_t mp_signal_core_connect_mx(mp_obj_t self_in) { - signal_core_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t mp_signal_core_connect_mx(mp_obj_t self_in){ + signal_core_obj_t * self = MP_OBJ_TO_PTR(self_in); plugin_core_verify(MP_OBJ_TO_PTR(self->plugin_core)); bl00mbox_error_unwrap(bl00mbox_signal_connect_mx(&self->signal)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(mp_signal_core_connect_mx_obj, - mp_signal_core_connect_mx); +MP_DEFINE_CONST_FUN_OBJ_1(mp_signal_core_connect_mx_obj, mp_signal_core_connect_mx); -STATIC mp_obj_t mp_signal_core_disconnect(mp_obj_t self_in) { - signal_core_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t mp_signal_core_disconnect(mp_obj_t self_in){ + signal_core_obj_t * self = MP_OBJ_TO_PTR(self_in); plugin_core_verify(MP_OBJ_TO_PTR(self->plugin_core)); bl00mbox_signal_disconnect(&self->signal); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(mp_signal_core_disconnect_obj, - mp_signal_core_disconnect); +MP_DEFINE_CONST_FUN_OBJ_1(mp_signal_core_disconnect_obj, mp_signal_core_disconnect); -STATIC mp_obj_t mp_signal_core_get_connected(mp_obj_t self_in) { - signal_core_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t mp_signal_core_get_connected(mp_obj_t self_in){ + signal_core_obj_t * self = MP_OBJ_TO_PTR(self_in); plugin_core_verify(MP_OBJ_TO_PTR(self->plugin_core)); - bl00mbox_array_t *array = - bl00mbox_signal_collect_connections(&self->signal); + bl00mbox_array_t * array = bl00mbox_signal_collect_connections(&self->signal); return get_connections_from_array(array); } -MP_DEFINE_CONST_FUN_OBJ_1(mp_signal_core_get_connected_obj, - mp_signal_core_get_connected); +MP_DEFINE_CONST_FUN_OBJ_1(mp_signal_core_get_connected_obj, mp_signal_core_get_connected); -STATIC void signal_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - signal_core_obj_t *self = MP_OBJ_TO_PTR(self_in); - plugin_core_obj_t *plugin_core = MP_OBJ_TO_PTR(self->plugin_core); - bl00mbox_signal_t *signal = &self->signal; - radspa_signal_t *rignal = signal->rignal; +STATIC void signal_core_attr(mp_obj_t self_in, qstr attr, + mp_obj_t *dest) { + signal_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + plugin_core_obj_t * plugin_core = MP_OBJ_TO_PTR(self->plugin_core); + bl00mbox_signal_t * signal = &self->signal; + radspa_signal_t * rignal = signal->rignal; - // if gc_sweep tries to load __del__ we mustn't raise exceptions, setjmp - // isn't set up - if (attr != MP_QSTR___del__) plugin_core_verify(plugin_core); + // if gc_sweep tries to load __del__ we mustn't raise exceptions, setjmp isn't set up + if(attr != MP_QSTR___del__) plugin_core_verify(plugin_core); if (dest[0] != MP_OBJ_NULL) { if (attr == MP_QSTR_value) { - if (bl00mbox_signal_is_input(signal)) { - bl00mbox_error_unwrap( - bl00mbox_signal_set_value(signal, mp_obj_get_int(dest[1]))); + if(bl00mbox_signal_is_input(signal)){ + bl00mbox_error_unwrap(bl00mbox_signal_set_value(signal, mp_obj_get_int(dest[1]))); + dest[0] = MP_OBJ_NULL; + } + } else if (attr == MP_QSTR_outer) { + if(self->outer == mp_const_none){ + self->outer = dest[1]; dest[0] = MP_OBJ_NULL; } } } else { if (attr == MP_QSTR_index) { dest[0] = mp_obj_new_int(signal->index); - } else if (attr == MP_QSTR_plugin_core) { - dest[0] = plugin_core; + } else if (attr == MP_QSTR_plugin) { + dest[0] = plugin_core->outer; } else if (attr == MP_QSTR_name) { - char *ret = strdup_raise(rignal->name); + char * ret = strdup_raise(rignal->name); dest[0] = mp_obj_new_str(ret, strlen(ret)); free(ret); } else if (attr == MP_QSTR_mpx) { dest[0] = mp_obj_new_int(rignal->name_multiplex); + } else if (attr == MP_QSTR_outer) { + dest[0] = self->outer; } else if (attr == MP_QSTR_description) { - char *ret = strdup_raise(rignal->description); + char * ret = strdup_raise(rignal->description); dest[0] = mp_obj_new_str(ret, strlen(ret)); free(ret); } else if (attr == MP_QSTR_unit) { - char *ret = strdup_raise(rignal->unit); + char * ret = strdup_raise(rignal->unit); dest[0] = mp_obj_new_str(ret, strlen(ret)); free(ret); } else if (attr == MP_QSTR_value) { dest[0] = mp_obj_new_int(bl00mbox_signal_get_value(signal)); } else if (attr == MP_QSTR_connected_mx) { bool ret = false; - if (bl00mbox_signal_is_output(signal)) { - bl00mbox_connection_t *conn = - bl00mbox_connection_from_signal(signal); - if (conn) ret = conn->connected_to_mixer; + if(bl00mbox_signal_is_output(signal)){ + bl00mbox_connection_t * conn = bl00mbox_connection_from_signal(signal); + if(conn) ret = conn->connected_to_mixer; } dest[0] = mp_obj_new_bool(ret); } else if (attr == MP_QSTR_hints) { @@ -716,25 +842,118 @@ STATIC void signal_core_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[1] = MP_OBJ_SENTINEL; } } -} +} STATIC const mp_rom_map_elem_t signal_core_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&mp_signal_core_connect_obj) }, - { MP_ROM_QSTR(MP_QSTR_connect_mx), - MP_ROM_PTR(&mp_signal_core_connect_mx_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), - MP_ROM_PTR(&mp_signal_core_disconnect_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_connected), - MP_ROM_PTR(&mp_signal_core_get_connected_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect_mx), MP_ROM_PTR(&mp_signal_core_connect_mx_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&mp_signal_core_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_connected), MP_ROM_PTR(&mp_signal_core_get_connected_obj) }, }; STATIC MP_DEFINE_CONST_DICT(signal_core_locals_dict, signal_core_locals_dict_table); -STATIC MP_DEFINE_CONST_OBJ_TYPE(signal_core_type, MP_QSTR_SignalCore, - MP_TYPE_FLAG_NONE, make_new, - signal_core_make_new, locals_dict, - &signal_core_locals_dict, attr, - signal_core_attr); +STATIC MP_DEFINE_CONST_OBJ_TYPE(signal_core_type, MP_QSTR_SignalCore, MP_TYPE_FLAG_NONE, + //make_new, signal_core_make_new, + locals_dict, &signal_core_locals_dict, + attr, signal_core_attr); + +// ======================== +// PATCHES +// ======================== + +STATIC mp_obj_t patch_core_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + // args: ChannelCore, outer, container, patch_name, [name] + mp_arg_check_num(n_args, n_kw, 4, 5, false); + + channel_core_obj_t * chan_core = get_channel_core(args[0]); + + bl00mbox_patch_t * container = get_patch(args[2]); + + patch_core_obj_t * self = m_new_obj_with_finaliser(patch_core_obj_t); + self->base.type = &patch_core_type; + self->container = container ? args[2] : mp_const_none; + + bl00mbox_patch_t * patch = bl00mbox_patch_create(chan_core->chan, container); + + if(!patch) bl00mbox_error_unwrap(BL00MBOX_ERROR_OOM); + + patch->parent = self; + patch->ref.self_ref = &self->patch; + self->patch = patch; + self->weak_channel = chan_core->weak; + + self->outer = args[1]; + self->patch_name = args[3]; + + self->name = n_kw > 4 ? args[4] : mp_const_none; + + bl00mbox_log_info("created patch %s", mp_obj_str_get_str(self->patch_name)); + return MP_OBJ_FROM_PTR(self); +} + +STATIC void patch_core_attr(mp_obj_t self_in, qstr attr, + mp_obj_t *dest) { + patch_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + + if (dest[0] == MP_OBJ_NULL) { + if (attr == MP_QSTR_name) { + dest[0] = self->name; + } else if (attr == MP_QSTR_patch_name) { + dest[0] = self->patch_name; + } else if (attr == MP_QSTR_outer) { + dest[0] = self->outer; + } else if (attr == MP_QSTR_channel) { + channel_core_verify(self->weak_channel); + dest[0] = strong_obj(self->weak_channel)->outer; + } else { + dest[1] = MP_OBJ_SENTINEL; + } + } +} +mp_obj_t mp_patch_core_del(mp_obj_t self_in) { + patch_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + if(self->patch){ + bl00mbox_log_info("deleted patch"); + bl00mbox_patch_destroy(self->patch); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_patch_core_del_obj, mp_patch_core_del); + +mp_obj_t mp_patch_core_delete(mp_obj_t self_in) { + patch_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + patch_core_verify(self); + bl00mbox_log_info("deleted patch"); + bl00mbox_patch_destroy(self->patch); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_patch_core_delete_obj, mp_patch_core_delete); + +STATIC mp_obj_t mp_patch_core_get_patches(mp_obj_t self_in){ + patch_core_obj_t * self = MP_OBJ_TO_PTR(self_in); + patch_core_verify(self); + return get_patches_from_container(&self->patch->patches); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_patch_core_get_patches_obj, mp_patch_core_get_patches); + +STATIC const mp_rom_map_elem_t patch_core_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_patch_core_del_obj) }, + { MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&mp_patch_core_delete_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_patches), MP_ROM_PTR(&mp_patch_core_get_patches_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(patch_core_locals_dict, + patch_core_locals_dict_table); + +STATIC MP_DEFINE_CONST_OBJ_TYPE(patch_core_type, MP_QSTR_PatchCore, MP_TYPE_FLAG_NONE, + locals_dict, &patch_core_locals_dict, + make_new, patch_core_make_new, + attr, patch_core_attr); + +// ======================== +// MODULE +// ======================== STATIC const mp_rom_map_elem_t bl00mbox_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), @@ -750,16 +969,15 @@ STATIC const mp_rom_map_elem_t bl00mbox_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_plugin_index_get_description), MP_ROM_PTR(&mp_plugin_index_get_description_obj) }, - // CHANNELS + // CORES { MP_OBJ_NEW_QSTR(MP_QSTR_ChannelCore), (mp_obj_t)&channel_core_type }, - { MP_ROM_QSTR(MP_QSTR_collect_channels), - MP_ROM_PTR(&mp_collect_channels_obj) }, - - // PLUGINS { MP_OBJ_NEW_QSTR(MP_QSTR_PluginCore), (mp_obj_t)&plugin_core_type }, - - // SIGNALS { MP_OBJ_NEW_QSTR(MP_QSTR_SignalCore), (mp_obj_t)&signal_core_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PatchCore), (mp_obj_t)&patch_core_type }, + + // GLOBALS + { MP_ROM_QSTR(MP_QSTR_collect_channels), + MP_ROM_PTR(&mp_collect_channels_obj) }, // CONSTANTS { MP_ROM_QSTR(MP_QSTR_SIGNAL_HINT_OUTPUT), @@ -777,8 +995,7 @@ STATIC const mp_rom_map_elem_t bl00mbox_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BL00MBOX_CHANNEL_PLUGIN_ID), MP_ROM_INT(BL00MBOX_CHANNEL_PLUGIN_ID) }, - { MP_ROM_QSTR(MP_QSTR_ReferenceError), - MP_ROM_PTR(&mp_type_ReferenceError) }, + { MP_ROM_QSTR(MP_QSTR_ReferenceError), MP_ROM_PTR(&mp_type_ReferenceError) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_bl00mbox_globals, bl00mbox_globals_table); diff --git a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.c b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.c index b5a4c756193636dbb32a293967f6191d162455a4..2581b1868f39900df012cf960ab0dd58e3c708ac 100644 --- a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.c +++ b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.c @@ -14,7 +14,7 @@ radspa_descriptor_t bl00mbox_channel_plugin_desc = { // this could be faster at some point by adding a special case but we don't wanna think about it now. typedef struct { - int16_t buffer[BL00MBOX_MAX_BUFFER_LEN]; + int16_t buffer[RADSPA_BUFFER_LEN]; uint32_t buffer_render_pass_id; int16_t value; int16_t value_render_pass_id; @@ -22,9 +22,9 @@ typedef struct { static line_in_singleton_t line_in; -static inline void update_line_in_buffer(uint16_t num_samples, uint32_t render_pass_id){ +static inline void update_line_in_buffer(uint32_t render_pass_id){ if(line_in.buffer_render_pass_id == render_pass_id) return; - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t val = bl00mbox_line_in_interlaced[2*i]; val += bl00mbox_line_in_interlaced[2*i+1]; val = radspa_clip(val>>1); @@ -44,14 +44,14 @@ static inline void update_line_in_value(uint32_t render_pass_id){ line_in.value_render_pass_id = render_pass_id; } -void bl00mbox_channel_plugin_run(radspa_t * channel_plugin, uint16_t num_samples, uint32_t render_pass_id){ +void bl00mbox_channel_plugin_run(radspa_t * channel_plugin, uint32_t render_pass_id){ if(!bl00mbox_line_in_interlaced) return; // handle line in signal, only render full if requested radspa_signal_t * input_sig = radspa_signal_get_by_index(channel_plugin, 0); if(input_sig->buffer){ - update_line_in_buffer(num_samples, render_pass_id); - memcpy(input_sig->buffer, line_in.buffer, sizeof(int16_t) * num_samples); + update_line_in_buffer(render_pass_id); + memcpy(input_sig->buffer, line_in.buffer, sizeof(int16_t) * RADSPA_BUFFER_LEN); } // do NOT render output here, if somebody has requested channel this would be too early // we're accessing the source buffer directly if present to avoid needing memcpy diff --git a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.h b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.h index 0e5adefaf7da3e2fa55da3e8e14a23d8289d94ed..83ea14d56646376ef217afc9be4b2a7e8128b787 100644 --- a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.h +++ b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_channel_plugin.h @@ -8,6 +8,6 @@ extern radspa_descriptor_t bl00mbox_channel_plugin_desc; radspa_t * bl00mbox_channel_plugin_create(uint32_t init_var); -void bl00mbox_channel_plugin_run(radspa_t * channel_plugin, uint16_t num_samples, uint32_t render_pass_id); +void bl00mbox_channel_plugin_run(radspa_t * channel_plugin, uint32_t render_pass_id); void bl00mbox_channel_plugin_update_values(radspa_t * channel_plugin, uint32_t render_pass_id); diff --git a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.c b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.c index b0de70b2b66a2045d01ffabf571bfee75eb60cc5..b5bce1d088a9209559fa01bafcb383e6b349bb9d 100644 --- a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.c +++ b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.c @@ -14,14 +14,14 @@ radspa_descriptor_t bl00mbox_line_in_desc = { // pointer serves as a channel-specific source plugin identifier, but we could at least reduce // the overhead to a memcpy. -void bl00mbox_line_in_run(radspa_t * line_in, uint16_t num_samples, uint32_t render_pass_id){ +void bl00mbox_line_in_run(radspa_t * line_in, uint32_t render_pass_id){ if(bl00mbox_line_in_interlaced == NULL) return; radspa_signal_t * left_sig = radspa_signal_get_by_index(line_in, 0); radspa_signal_t * right_sig = radspa_signal_get_by_index(line_in, 1); radspa_signal_t * mid_sig = radspa_signal_get_by_index(line_in, 2); radspa_signal_t * gain_sig = radspa_signal_get_by_index(line_in, 3); - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t gain = radspa_signal_get_value(gain_sig, i, render_pass_id); if(left_sig->buffer != NULL){ int16_t left = radspa_gain(bl00mbox_line_in_interlaced[2*i], gain); diff --git a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.h b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.h index 1a895b646393e4c0df9be0c45cd7944d29548455..f2f87315f94853096af15628040acd25ae0abb1d 100644 --- a/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.h +++ b/components/bl00mbox/plugins/bl00mbox_specific/bl00mbox_line_in.h @@ -6,4 +6,4 @@ extern radspa_descriptor_t bl00mbox_line_in_desc; radspa_t * bl00mbox_line_in_create(uint32_t init_var); -void bl00mbox_line_in_run(radspa_t * line_in, uint16_t num_samples, uint32_t render_pass_id); +void bl00mbox_line_in_run(radspa_t * line_in, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/radspa.h b/components/bl00mbox/radspa/radspa.h index 0223beaae88019cf19dcbd7e48169d341a3c0390..f0befef404d9a44029f36f71a4ed34063ef8dc84 100644 --- a/components/bl00mbox/radspa/radspa.h +++ b/components/bl00mbox/radspa/radspa.h @@ -23,6 +23,8 @@ #include <string.h> #include <stdbool.h> #include <stdint.h> +#include <stdio.h> +#include "radspa_config.h" /* CONVENTIONS * @@ -50,9 +52,10 @@ struct _radspa_descriptor_t; struct _radspa_signal_t; +struct _radspa_buffer_t; struct _radspa_t; -typedef void (* radspa_render_t)(struct _radspa_t * plugin, uint16_t num_samples, uint32_t render_pass_id); +typedef void (* radspa_render_t)(struct _radspa_t * plugin, uint32_t render_pass_id); typedef struct _radspa_descriptor_t{ char * name; @@ -77,11 +80,10 @@ typedef struct _radspa_signal_t{ // -1 to disable signal multiplexing int8_t name_multiplex; // buffer full of samples, may be NULL. - int16_t * buffer; + struct _radspa_buffer_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; } radspa_signal_t; typedef struct _radspa_t{ @@ -107,6 +109,11 @@ typedef struct _radspa_t{ radspa_signal_t signals[]; } radspa_t; +typedef struct _radspa_buffer_t{ + int16_t data[RADSPA_BUFFER_LEN]; + radspa_t * plugin; +} radspa_buffer_t; + /* REQUIREMENTS * Hosts must provide implementations for the following functions: */ @@ -117,8 +124,14 @@ typedef struct _radspa_t{ */ extern uint32_t radspa_sct_to_rel_freq(int16_t sct, int16_t undersample_pow); -// Return 1 if the buffer wasn't rendered already, 0 otherwise. -extern bool radspa_host_request_buffer_render(int16_t * buf); +extern int16_t radspa_random(); +inline void radspa_render_plugin(radspa_t * plugin, uint32_t render_pass_id){ + if (plugin->render_pass_id == render_pass_id) return; + plugin->render_pass_id = render_pass_id; + plugin->render(plugin, render_pass_id); +} -extern int16_t radspa_random(); +inline void radspa_render_buffer(radspa_buffer_t * buf, uint32_t render_pass_id){ + radspa_render_plugin(buf->plugin, render_pass_id); +} diff --git a/components/bl00mbox/radspa/radspa_helpers.h b/components/bl00mbox/radspa/radspa_helpers.h index 4a0dd878d6963e855e3e4657b3526d1b35c8639e..b85264670983f02e4f404329ca5a416b4698b021 100644 --- a/components/bl00mbox/radspa/radspa_helpers.h +++ b/components/bl00mbox/radspa/radspa_helpers.h @@ -68,23 +68,22 @@ inline radspa_signal_t * radspa_signal_get_by_index(radspa_t * plugin, uint16_t return &(plugin->signals[signal_index]); } -/* returns the value that a signal has at a given moment in time. time is - * represented as the buffer index. requests rendering from host and requires implementation - * of radspa_host_request_buffer_render. - */ +inline void radspa_render_signal(radspa_signal_t * sig, uint32_t render_pass_id){ + radspa_render_buffer(sig->buffer, render_pass_id); +} inline int16_t radspa_signal_get_value(radspa_signal_t * sig, int16_t index, uint32_t render_pass_id){ if(sig->buffer){ - if(sig->render_pass_id != render_pass_id) radspa_host_request_buffer_render(sig->buffer); - if(sig->buffer[1] == -32768) return sig->buffer[0]; - return sig->buffer[index]; + radspa_render_signal(sig, render_pass_id); + if(sig->buffer->data[1] == -32768) return sig->buffer->data[0]; + return sig->buffer->data[index]; } return sig->value; } inline void radspa_signal_set_value_noclip(radspa_signal_t * sig, int16_t index, int16_t val){ if(sig->buffer != NULL){ - sig->buffer[index] = val; + sig->buffer->data[index] = val; } else if(!index){ sig->value = val; } @@ -92,24 +91,24 @@ inline void radspa_signal_set_value_noclip(radspa_signal_t * sig, int16_t index, 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); + sig->buffer->data[index] = radspa_clip(val); } else if(!index){ sig->value = radspa_clip(val); } } -inline void radspa_signal_copy(radspa_signal_t * input, radspa_signal_t * output, uint32_t buffer_len, uint32_t render_pass_id){ +inline void radspa_signal_copy(radspa_signal_t * input, radspa_signal_t * output, uint32_t render_pass_id){ if(!output->buffer){ output->value = radspa_signal_get_value(input, 0, render_pass_id); } else if(!input->buffer){ - output->buffer[0] = input->value; - output->buffer[1] = -32768; + output->buffer->data[0] = input->value; + output->buffer->data[1] = RADSPA_SIGNAL_NONCONST; } else { - if(input->render_pass_id != render_pass_id) radspa_host_request_buffer_render(input->buffer); - if(input->buffer[1] == -32768){ - memcpy(output->buffer, input->buffer, sizeof(int16_t) * 2); + radspa_render_signal(input, render_pass_id); + if(input->buffer->data[1] == RADSPA_SIGNAL_NONCONST){ + memcpy(&output->buffer->data, &input->buffer->data, sizeof(int16_t) * 2); } else { - memcpy(output->buffer, input->buffer, sizeof(int16_t) * buffer_len); + memcpy(&output->buffer->data, &input->buffer->data, sizeof(int16_t) * RADSPA_BUFFER_LEN); } } } @@ -125,18 +124,18 @@ inline void radspa_signal_set_value_check_const(radspa_signal_t * sig, int16_t i } val = radspa_clip(val); if(index == 0){ - sig->buffer[0] = val; + sig->buffer->data[0] = val; } else if(index == 1){ - if(val == sig->buffer[0]) sig->buffer[1] = -32768; + if(val == sig->buffer->data[0]) sig->buffer->data[1] = RADSPA_SIGNAL_NONCONST; } else { - if((sig->buffer[1] == -32768) && (val != sig->buffer[0])) sig->buffer[1] = sig->buffer[0]; - sig->buffer[index] = val; + if((sig->buffer->data[1] == -32768) && (val != sig->buffer->data[0])) sig->buffer->data[1] = sig->buffer->data[0]; + sig->buffer->data[index] = val; } } inline int16_t radspa_signal_set_value_check_const_result(radspa_signal_t * sig){ if(sig->buffer != NULL){ - if(sig->buffer[1] == -32768) return sig->buffer[0]; + if(sig->buffer->data[1] == RADSPA_SIGNAL_NONCONST) return sig->buffer->data[0]; return RADSPA_SIGNAL_NONCONST; } return sig->value; @@ -146,8 +145,8 @@ inline void radspa_signal_set_const_value(radspa_signal_t * sig, int32_t val){ if(sig->buffer == NULL){ sig->value = radspa_clip(val); } else { - sig->buffer[0] = radspa_clip(val); - sig->buffer[1] = -32768; + sig->buffer->data[0] = radspa_clip(val); + sig->buffer->data[1] = RADSPA_SIGNAL_NONCONST; } } @@ -157,29 +156,26 @@ inline void radspa_signal_set_values(radspa_signal_t * sig, uint16_t start, uint } else { val = radspa_clip(val); for(uint16_t i = start; i < stop; i++){ - sig->buffer[i] = val; + sig->buffer->data[i] = 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]; + radspa_render_signal(sig, render_pass_id); + if(sig->buffer->data[1] == RADSPA_SIGNAL_NONCONST) return sig->buffer->data[0]; return RADSPA_SIGNAL_NONCONST; } return sig->value; } -inline int16_t radspa_trigger_get_const(radspa_signal_t * sig, int16_t * hist, uint16_t * index, uint16_t num_samples, uint32_t render_pass_id){ +inline int16_t radspa_trigger_get_const(radspa_signal_t * sig, int16_t * hist, uint16_t * index, uint32_t render_pass_id){ (* index) = 0; int16_t ret_const = radspa_signal_get_const_value(sig, render_pass_id); if(ret_const != RADSPA_SIGNAL_NONCONST) return radspa_trigger_get(ret_const, hist); int16_t ret = 0; - for(uint16_t i = 0; i< num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int16_t tmp = radspa_trigger_get(radspa_signal_get_value(sig, i, render_pass_id), hist); if(tmp){ ret = tmp; diff --git a/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.c b/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.c index 8d6c2da6787e8b1579c73804a5883602760e950f..ce57ab5cd07d42a1cbe515e7166960813e277a67 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.c @@ -21,7 +21,7 @@ radspa_descriptor_t ampliverter_desc = { #define AMPLIVERTER_GAIN 2 #define AMPLIVERTER_BIAS 3 -void ampliverter_run(radspa_t * ampliverter, uint16_t num_samples, uint32_t render_pass_id){ +void ampliverter_run(radspa_t * ampliverter, uint32_t render_pass_id){ // step 1: get signal pointers. since these are stored in a linked list this is a rather // slow operation and should ideally be only be done once per call. // if no signals with output hint are being read the run function may exit early. @@ -33,7 +33,7 @@ void ampliverter_run(radspa_t * ampliverter, uint16_t num_samples, uint32_t rend static int16_t ret = 0; - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ // step 2: render the outputs. most of the time a simple for loop will be fine. // using {*radspa_signal_t}->get_value is required to automatically switch between // static values and streamed data at various sample rates, don't access the data directly diff --git a/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.h b/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.h index 4056316a25f9be994c20ebeb9ffd423ee3c03597..08e97c6319cdfd8f1b074a89d3088eff2e594e55 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/ampliverter.h @@ -4,5 +4,5 @@ extern radspa_descriptor_t ampliverter_desc; radspa_t * ampliverter_create(uint32_t init_var); -void ampliverter_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void ampliverter_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/buffer.c b/components/bl00mbox/radspa/standard_plugin_lib/buffer.c index 7672bf30bf5b03469242bb547d14711b468ef824..c4a372cc36dbcb8477e5c0b9d11f5b010df68295 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/buffer.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/buffer.c @@ -8,7 +8,7 @@ radspa_descriptor_t buffer_desc = { .destroy_plugin_instance = radspa_standard_plugin_destroy }; -void buffer_run(radspa_t * buffer, uint16_t num_samples, uint32_t render_pass_id){ +void buffer_run(radspa_t * buffer, uint32_t render_pass_id){ // note: this could be more lightweight by simply forwarding the buffer, // however at this point the radspa protocol has no built-in flag for this. // a host may still choose to simply do so to save CPU. @@ -17,7 +17,7 @@ void buffer_run(radspa_t * buffer, uint16_t num_samples, uint32_t render_pass_id // (running a single channel mixer). radspa_signal_t * output = radspa_signal_get_by_index(buffer, 0); radspa_signal_t * input = radspa_signal_get_by_index(buffer, 1); - radspa_signal_copy(input, output, num_samples, render_pass_id); + radspa_signal_copy(input, output, render_pass_id); } radspa_t * buffer_create(uint32_t init_var){ diff --git a/components/bl00mbox/radspa/standard_plugin_lib/buffer.h b/components/bl00mbox/radspa/standard_plugin_lib/buffer.h index 18b5344f3a7e065c35bcfb63180af58dba500b59..7c16f1bcb3882d3caf6f1ef14f31155d5801a6dd 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/buffer.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/buffer.h @@ -4,4 +4,4 @@ extern radspa_descriptor_t buffer_desc; radspa_t * buffer_create(uint32_t init_var); -void buffer_run(radspa_t * buffer, uint16_t num_samples, uint32_t render_pass_id); +void buffer_run(radspa_t * buffer, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/delay.c b/components/bl00mbox/radspa/standard_plugin_lib/delay.c index f6521569bb2af7190f700550b0214dca7d1d09a8..05d68b9df262455f3bd3c322cf619b9a51f5a534 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/delay.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/delay.c @@ -19,7 +19,7 @@ radspa_descriptor_t delay_desc = { #define DELAY_DRY_VOL 5 #define DELAY_REC_VOL 6 -void delay_run(radspa_t * delay, uint16_t num_samples, uint32_t render_pass_id){ +void delay_run(radspa_t * delay, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(delay, DELAY_OUTPUT); delay_data_t * data = delay->plugin_data; int16_t * buf = delay->plugin_table; @@ -49,7 +49,7 @@ void delay_run(radspa_t * delay, uint16_t num_samples, uint32_t render_pass_id){ int16_t rec_vol = radspa_signal_get_value(rec_vol_sig, 0, render_pass_id); - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ data->write_head_position++; while(data->write_head_position >= buffer_size) data->write_head_position -= buffer_size; // maybe faster than % diff --git a/components/bl00mbox/radspa/standard_plugin_lib/delay.h b/components/bl00mbox/radspa/standard_plugin_lib/delay.h index 6bd82790eb37fb58d15255995c4df13ed86a3fe3..8d3a7e43d1efa1c165eb1df39f254a1b8c13c5fb 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/delay.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/delay.h @@ -11,5 +11,5 @@ typedef struct { extern radspa_descriptor_t delay_desc; radspa_t * delay_create(uint32_t init_var); -void delay_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void delay_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/distortion.c b/components/bl00mbox/radspa/standard_plugin_lib/distortion.c index e5a9cc68b7253e6db8cf1a0e4678752024f480e0..adb8f05934f1cf43736e0870a45662d30591f0fc 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/distortion.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/distortion.c @@ -23,7 +23,7 @@ static inline int32_t distort(int32_t input, int16_t * dist, uint8_t lerp_glitch return ret >> lerp_glitch; } -void distortion_run(radspa_t * distortion, uint16_t num_samples, uint32_t render_pass_id){ +void distortion_run(radspa_t * distortion, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(distortion, DISTORTION_OUTPUT); if(output_sig->buffer == NULL) return; int16_t * dist = distortion->plugin_table; @@ -33,7 +33,7 @@ void distortion_run(radspa_t * distortion, uint16_t num_samples, uint32_t render if(input != RADSPA_SIGNAL_NONCONST){ radspa_signal_set_const_value(output_sig, distort(input, dist, lerp_glitch)); } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t input = radspa_signal_get_value(input_sig, i, render_pass_id); radspa_signal_set_value(output_sig, i, distort(input, dist, lerp_glitch)); } diff --git a/components/bl00mbox/radspa/standard_plugin_lib/distortion.h b/components/bl00mbox/radspa/standard_plugin_lib/distortion.h index 87455bad8d1e3a903d0bea099254ec9a6c3029ab..0dfe617f520584528c987f42a26a7941cbb64f87 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/distortion.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/distortion.h @@ -4,5 +4,5 @@ extern radspa_descriptor_t distortion_desc; radspa_t * distortion_create(uint32_t init_var); -void distortion_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void distortion_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.c b/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.c index f907e2d9e578198c116f26339b63e95fe1c294b5..43d989a7a13bf0d3f3e053a82efcda6ab794e382 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.c @@ -25,34 +25,32 @@ radspa_descriptor_t env_adsr_desc = { #define ENV_ADSR_PHASE_SUSTAIN 3 #define ENV_ADSR_PHASE_RELEASE 4 -#define SAMPLE_RATE_SORRY 48000 - -static inline uint32_t env_adsr_time_ms_to_val_rise(int16_t time_ms, uint32_t val, uint16_t num_samples){ +static inline uint32_t env_adsr_time_ms_to_val_rise(int16_t time_ms, uint32_t val){ if(!time_ms) return UINT32_MAX; if(time_ms < 0) time_ms = -time_ms; - uint32_t div = time_ms * ((SAMPLE_RATE_SORRY)/1000); + uint32_t div = time_ms * ((RADSPA_SAMPLE_RATE)/1000); uint32_t input = val/div; - if(((uint64_t) input * num_samples) >> 32){ + if(((uint64_t) input * RADSPA_BUFFER_LEN) >> 32){ return UINT32_MAX; // sat } else { - return input * num_samples; + return input * RADSPA_BUFFER_LEN; } } -static inline void update_attack_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){ +static inline void update_attack_coeffs(radspa_t * env_adsr, uint32_t render_pass_id){ env_adsr_data_t * data = env_adsr->plugin_data; int16_t attack = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_ATTACK], 0, render_pass_id); - if((data->attack_prev_ms != attack) || (data->num_samples_prev != num_samples)){ - data->attack_raw = env_adsr_time_ms_to_val_rise(attack, UINT32_MAX, num_samples); + if(data->attack_prev_ms != attack){ + data->attack_raw = env_adsr_time_ms_to_val_rise(attack, UINT32_MAX); data->attack_prev_ms = attack; } } -static inline void update_release_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){ +static inline void update_release_coeffs(radspa_t * env_adsr, uint32_t render_pass_id){ env_adsr_data_t * data = env_adsr->plugin_data; int16_t release = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_RELEASE], 0, render_pass_id); - if((data->release_prev_ms != release) || (data->num_samples_prev != num_samples) || data->release_init_val_prev != data->release_init_val){ - data->release_raw = env_adsr_time_ms_to_val_rise(release, data->release_init_val, num_samples); + if((data->release_prev_ms != release) || (data->release_init_val_prev != data->release_init_val)){ + data->release_raw = env_adsr_time_ms_to_val_rise(release, data->release_init_val); data->release_prev_ms = release; if(data->release_init_val_prev != data->release_init_val){; uint8_t phase = ENV_ADSR_PHASE_RELEASE; @@ -68,19 +66,19 @@ static inline void update_release_coeffs(radspa_t * env_adsr, uint16_t num_sampl } } -static inline void update_sustain_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){ +static inline void update_sustain_coeffs(radspa_t * env_adsr, uint32_t render_pass_id){ env_adsr_data_t * data = env_adsr->plugin_data; int16_t sustain = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_SUSTAIN], 0, render_pass_id); sustain = sustain < 0 ? -sustain : sustain; data->sustain = ((uint32_t) sustain) << 17UL; } -static inline void update_decay_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){ - update_sustain_coeffs(env_adsr, num_samples, render_pass_id); +static inline void update_decay_coeffs(radspa_t * env_adsr, uint32_t render_pass_id){ + update_sustain_coeffs(env_adsr, render_pass_id); env_adsr_data_t * data = env_adsr->plugin_data; int32_t decay = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_DECAY], 0, render_pass_id); - if((data->decay_prev_ms != decay) || (data->sustain_prev != data->sustain) || (data->num_samples_prev != num_samples)){ - data->decay_raw = env_adsr_time_ms_to_val_rise(decay, UINT32_MAX - data->sustain, num_samples); + if((data->decay_prev_ms != decay) || (data->sustain_prev != data->sustain)){ + data->decay_raw = env_adsr_time_ms_to_val_rise(decay, UINT32_MAX - data->sustain); data->decay_prev_ms = decay; if(data->sustain_prev != data->sustain){ uint8_t phase = ENV_ADSR_PHASE_DECAY; @@ -97,11 +95,11 @@ static inline void update_decay_coeffs(radspa_t * env_adsr, uint16_t num_samples } -void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){ +void env_adsr_run(radspa_t * env_adsr, uint32_t render_pass_id){ env_adsr_data_t * data = env_adsr->plugin_data; uint16_t throwaway; - int16_t vel = radspa_trigger_get_const(&env_adsr->signals[ENV_ADSR_TRIGGER], &data->trigger_prev, &throwaway, num_samples, render_pass_id); + int16_t vel = radspa_trigger_get_const(&env_adsr->signals[ENV_ADSR_TRIGGER], &data->trigger_prev, &throwaway, render_pass_id); if(vel > 0 ){ // start data->env_phase = ENV_ADSR_PHASE_ATTACK; data->velocity = vel; @@ -118,7 +116,7 @@ void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pas data->env_counter = 0;; break; case ENV_ADSR_PHASE_ATTACK: - update_attack_coeffs(env_adsr, num_samples, render_pass_id); + update_attack_coeffs(env_adsr, render_pass_id); tmp = data->env_counter + data->attack_raw; if(tmp < data->env_counter){ // overflow tmp = ~((uint32_t) 0); // max out @@ -127,7 +125,7 @@ void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pas data->env_counter = tmp; break; case ENV_ADSR_PHASE_DECAY: - update_decay_coeffs(env_adsr, num_samples, render_pass_id); + update_decay_coeffs(env_adsr, render_pass_id); tmp = data->env_counter - data->decay_raw; if(tmp > data->env_counter){ // underflow tmp = 0; //bottom out @@ -142,12 +140,12 @@ void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pas break; case ENV_ADSR_PHASE_SUSTAIN: - update_sustain_coeffs(env_adsr, num_samples, render_pass_id); + update_sustain_coeffs(env_adsr, render_pass_id); if(data->sustain == 0) data->env_phase = ENV_ADSR_PHASE_OFF; data->env_counter = data->sustain; break; case ENV_ADSR_PHASE_RELEASE: - update_release_coeffs(env_adsr, num_samples, render_pass_id); + update_release_coeffs(env_adsr, render_pass_id); tmp = data->env_counter - data->release_raw; if(tmp > data->env_counter){ // underflow tmp = 0; //bottom out @@ -156,7 +154,6 @@ void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pas data->env_counter = tmp; break; } - data->num_samples_prev = num_samples; int32_t gain = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_GAIN], 0, render_pass_id); @@ -185,8 +182,8 @@ void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pas int16_t ret = radspa_signal_get_const_value(&env_adsr->signals[ENV_ADSR_INPUT], render_pass_id); if(ret == RADSPA_SIGNAL_NONCONST){ - int32_t env_slope = ((env - data->env_prev) << 15) / num_samples; - for(uint16_t i = 0; i < num_samples; i++){ + int32_t env_slope = ((env - data->env_prev) << 15) / RADSPA_BUFFER_LEN; + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_INPUT], i, render_pass_id); int32_t env_inter = data->env_prev + ((env_slope * i)>>15); ret = (ret * env_inter) >> 12; diff --git a/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.h b/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.h index 513afa385589cc262499d26bdfe48ac8960d38ac..d096cf2868a6e24566b25125eb53a3ee5c3ff305 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/env_adsr.h @@ -8,7 +8,6 @@ typedef struct { uint32_t square_mult[5]; uint32_t square_min[5]; int16_t trigger_prev; - uint16_t num_samples_prev; int32_t env_prev; uint8_t env_phase; int16_t attack_prev_ms; @@ -25,5 +24,5 @@ typedef struct { extern radspa_descriptor_t env_adsr_desc; radspa_t * env_adsr_create(uint32_t init_var); -void env_adsr_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void env_adsr_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/filter.c b/components/bl00mbox/radspa/standard_plugin_lib/filter.c index b821b827b119e33b63148359699b47421815016e..69004dd0b7e49f1b30e8b61f30a6cdb00a140609 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/filter.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/filter.c @@ -118,7 +118,7 @@ static inline void get_coeffs(filter_data_t * data, int16_t pitch, int16_t reso, data->mode_prev = mode; } -void filter_run(radspa_t * filter, uint16_t num_samples, uint32_t render_pass_id){ +void filter_run(radspa_t * filter, uint32_t render_pass_id){ filter_data_t * data = filter->plugin_data; radspa_signal_t * output_sig = radspa_signal_get_by_index(filter, FILTER_OUTPUT); @@ -154,9 +154,9 @@ void filter_run(radspa_t * filter, uint16_t num_samples, uint32_t render_pass_id return; } - int16_t out[num_samples]; + int16_t out[RADSPA_BUFFER_LEN]; - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ if(!(i & (RADSPA_EVENT_MASK))){ if(always_update_coeffs){ if(pitch_const == RADSPA_SIGNAL_NONCONST) pitch = radspa_signal_get_value(pitch_sig, i, render_pass_id); @@ -207,11 +207,11 @@ void filter_run(radspa_t * filter, uint16_t num_samples, uint32_t render_pass_id } if(input_const == RADSPA_SIGNAL_NONCONST){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ radspa_signal_set_value(output_sig, i, out[i]); } } else if(data->const_output == RADSPA_SIGNAL_NONCONST){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ radspa_signal_set_value_check_const(output_sig, i, out[i]); } data->const_output = radspa_signal_set_value_check_const_result(output_sig); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/filter.h b/components/bl00mbox/radspa/standard_plugin_lib/filter.h index c8a2bd1943a1467b9ef33730f1317a1321e01b1c..0b6857fd850629713b8180221ef67fd55b2984ad 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/filter.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/filter.h @@ -21,4 +21,4 @@ typedef struct { extern radspa_descriptor_t filter_desc; radspa_t * filter_create(uint32_t init_var); -void filter_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void filter_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/flanger.c b/components/bl00mbox/radspa/standard_plugin_lib/flanger.c index 40dee9c70e54dbd126bde5fb6c5a4557b896e851..f735446a69cbc99408ccc4d228b1a1e057761e31 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/flanger.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/flanger.c @@ -48,7 +48,7 @@ static inline int32_t fixed_point_list_access(int32_t * buf, int32_t fp_index, u * delay_reso_int = sct_to_rel_freq(offset - (delay_time_ms * 2400)/decay_ms_per_6dB) */ -void flanger_run(radspa_t * flanger, uint16_t num_samples, uint32_t render_pass_id){ +void flanger_run(radspa_t * flanger, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(flanger, FLANGER_OUTPUT); if(output_sig->buffer == NULL) return; flanger_data_t * data = flanger->plugin_data; @@ -93,7 +93,7 @@ void flanger_run(radspa_t * flanger, uint16_t num_samples, uint32_t render_pass_ } data->manual_prev = manual; - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t dry = radspa_signal_get_value(input_sig, i, render_pass_id); data->write_head_position++; diff --git a/components/bl00mbox/radspa/standard_plugin_lib/flanger.h b/components/bl00mbox/radspa/standard_plugin_lib/flanger.h index 717037a0baa569090818a0aa460f40214c43e886..5f37c527c95b85e76f1feb99d620c43658f526d8 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/flanger.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/flanger.h @@ -13,5 +13,5 @@ typedef struct { extern radspa_descriptor_t flanger_desc; radspa_t * flanger_create(uint32_t init_var); -void flanger_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void flanger_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/lowpass.c b/components/bl00mbox/radspa/standard_plugin_lib/lowpass.c index d59421b2584cf609178e742c9f493d3c454c0b97..82b0aba453477920f9d0404445d1ee97459c4260 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/lowpass.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/lowpass.c @@ -51,7 +51,7 @@ static void set_lowpass_coeffs(lowpass_data_t * data, int32_t freq, int32_t mq){ } -void lowpass_run(radspa_t * lowpass, uint16_t num_samples, uint32_t render_pass_id){ +void lowpass_run(radspa_t * lowpass, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(lowpass, LOWPASS_OUTPUT); if(output_sig->buffer == NULL) return; lowpass_data_t * data = lowpass->plugin_data; @@ -60,7 +60,7 @@ void lowpass_run(radspa_t * lowpass, uint16_t num_samples, uint32_t render_pass_ radspa_signal_t * q_sig = radspa_signal_get_by_index(lowpass, LOWPASS_Q); radspa_signal_t * gain_sig = radspa_signal_get_by_index(lowpass, LOWPASS_GAIN); - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int16_t input = radspa_signal_get_value(input_sig, i, render_pass_id); int32_t freq = radspa_signal_get_value(freq_sig, i, render_pass_id); int16_t q = radspa_signal_get_value(q_sig, i, render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/lowpass.h b/components/bl00mbox/radspa/standard_plugin_lib/lowpass.h index 6bac0a5d127af80dc98fcc245aae21961f102f8a..a37975b19b98da72024d78fdf318aaf8add95bc4 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/lowpass.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/lowpass.h @@ -15,4 +15,4 @@ typedef struct { extern radspa_descriptor_t lowpass_desc; radspa_t * lowpass_create(uint32_t init_var); -void lowpass_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void lowpass_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/mixer.c b/components/bl00mbox/radspa/standard_plugin_lib/mixer.c index 91cb1e6910d3381ae92a43eb06002945bc92508f..d246ba5f6627f17075cfbd204d439d6ef89fc615 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/mixer.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/mixer.c @@ -8,10 +8,10 @@ radspa_descriptor_t mixer_desc = { .destroy_plugin_instance = radspa_standard_plugin_destroy }; -void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ +void mixer_run(radspa_t * mixer, uint32_t render_pass_id){ mixer_data_t * data = mixer->plugin_data; - int32_t ret[num_samples]; + int32_t ret[RADSPA_BUFFER_LEN]; bool ret_init = false; bool ret_const_init = false; @@ -30,7 +30,7 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ if(!input_const) continue; if((input_const != RADSPA_SIGNAL_NONCONST) && (input_gain_const != RADSPA_SIGNAL_NONCONST)){ if(ret_init){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] += (input_gain_const * input_const) >> 12; } } else if(ret_const_init){ @@ -41,41 +41,41 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ } } else { if(ret_const_init){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] = ret[0]; } ret_const_init = false; } if(input_gain_const == RADSPA_SIGNAL_VAL_UNITY_GAIN){ if(ret_init){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] += radspa_signal_get_value(input_sigs[j], i, render_pass_id); } } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] = radspa_signal_get_value(input_sigs[j], i, render_pass_id); } ret_init = true; } } else if(input_gain_const == -RADSPA_SIGNAL_VAL_UNITY_GAIN){ if(ret_init){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] -= radspa_signal_get_value(input_sigs[j], i, render_pass_id); } } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] = -radspa_signal_get_value(input_sigs[j], i, render_pass_id); } ret_init = true; } } else if(input_gain_const == RADSPA_SIGNAL_NONCONST){ if(ret_init){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t input_gain = radspa_signal_get_value(input_gain_sigs[j], i, render_pass_id); ret[i] += (input_gain * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12; } } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t input_gain = radspa_signal_get_value(input_gain_sigs[j], i, render_pass_id); ret[i] = (input_gain * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12; } @@ -83,11 +83,11 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ } } else { if(ret_init){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] += (input_gain_const * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12; } } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] = (input_gain_const * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12; } ret_init = true; @@ -103,7 +103,7 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ if(block_dc){ if(ret_init){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ bool invert = data->dc < 0; if(invert) data->dc = -data->dc; data->dc = ((uint64_t) data->dc * (((1UL<<12) - 1)<<20)) >> 32; @@ -113,7 +113,7 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ } } else { if(data->dc){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ bool invert = data->dc < 0; if(invert) data->dc = -data->dc; data->dc = ((uint64_t) data->dc * (((1UL<<12) - 1)<<20)) >> 32; @@ -130,17 +130,17 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ int32_t gain = gain_const; if(gain_const != RADSPA_SIGNAL_VAL_UNITY_GAIN){ if(gain_const == RADSPA_SIGNAL_NONCONST){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ gain = radspa_signal_get_value(gain_sig, i, render_pass_id); ret[i] = (ret[i] * gain) >> 12; } } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ ret[i] = (ret[i] * gain) >> 12; } } } - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ radspa_signal_set_value(output_sig, i, ret[i]); } } else if(ret_const_init){ @@ -148,7 +148,7 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ int32_t gain = gain_const; if(gain_const != RADSPA_SIGNAL_VAL_UNITY_GAIN){ if(gain_const == RADSPA_SIGNAL_NONCONST){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ gain = radspa_signal_get_value(gain_sig, i, render_pass_id); ret[i] = (ret[0] * gain) >> 12; } @@ -157,7 +157,7 @@ void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){ } } if(gain_const == RADSPA_SIGNAL_NONCONST){ - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ radspa_signal_set_value(output_sig, i, ret[i]); } } else { diff --git a/components/bl00mbox/radspa/standard_plugin_lib/mixer.h b/components/bl00mbox/radspa/standard_plugin_lib/mixer.h index 14d9f01fbf265c7e6821bb653cc27db2974b3637..99911a2d2bf57637b4771d0ecaf9c22ecce7d6ea 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/mixer.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/mixer.h @@ -9,5 +9,5 @@ typedef struct { extern radspa_descriptor_t mixer_desc; radspa_t * mixer_create(uint32_t init_var); -void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id); +void mixer_run(radspa_t * mixer, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/multipitch.c b/components/bl00mbox/radspa/standard_plugin_lib/multipitch.c index 30a772a2e022b59ace289d870958e26b042c0177..6c5ab5c1836aa90debc3d1dd9304541657ec8370 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/multipitch.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/multipitch.c @@ -41,12 +41,12 @@ static inline int32_t pitch_limit(int32_t pitch, int32_t min, int32_t max){ return pitch; } -void multipitch_run(radspa_t * multipitch, uint16_t num_samples, uint32_t render_pass_id){ +void multipitch_run(radspa_t * multipitch, uint32_t render_pass_id){ uint8_t num_outputs = (multipitch->len_signals - (NUM_SIGNALS))/2; multipitch_data_t * data = multipitch->plugin_data; uint16_t i; - int16_t trigger_in = radspa_trigger_get_const(&multipitch->signals[TRIGGER_IN], &data->trigger_in_prev, &i, num_samples, render_pass_id); + int16_t trigger_in = radspa_trigger_get_const(&multipitch->signals[TRIGGER_IN], &data->trigger_in_prev, &i, render_pass_id); if(trigger_in > 0) radspa_trigger_start(trigger_in, &(data->trigger_thru_prev)); if(trigger_in < 0) radspa_trigger_stop(&(data->trigger_thru_prev)); radspa_signal_set_const_value(&multipitch->signals[TRIGGER_THRU], data->trigger_thru_prev); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/multipitch.h b/components/bl00mbox/radspa/standard_plugin_lib/multipitch.h index 7e830c8024688eb2f3895353860a938b125e1add..7459a573a94a53f2cfa0dca777a07e4cf83fda67 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/multipitch.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/multipitch.h @@ -4,5 +4,5 @@ extern radspa_descriptor_t multipitch_desc; radspa_t * multipitch_create(uint32_t init_var); -void multipitch_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void multipitch_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/noise.c b/components/bl00mbox/radspa/standard_plugin_lib/noise.c index 3c9ecfb061ea82ca09b6b0311b853bf96227b11b..b2212ec3c1c80291958f8bd0e39ad3cfe5ac2ac0 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/noise.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/noise.c @@ -13,14 +13,14 @@ radspa_descriptor_t noise_desc = { #define NOISE_OUTPUT 0 #define NOISE_SPEED 1 -void noise_run(radspa_t * noise, uint16_t num_samples, uint32_t render_pass_id){ +void noise_run(radspa_t * noise, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(noise, NOISE_OUTPUT); radspa_signal_t * speed_sig = radspa_signal_get_by_index(noise, NOISE_SPEED); if(radspa_signal_get_value(speed_sig, 0, render_pass_id) < 0){ radspa_signal_set_const_value(output_sig, radspa_random()); } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ radspa_signal_set_value(output_sig, i, radspa_random()); } } diff --git a/components/bl00mbox/radspa/standard_plugin_lib/noise.h b/components/bl00mbox/radspa/standard_plugin_lib/noise.h index 709f71bd9866f99faf4a10fcb0d44e1585ef1a69..4d578287fcbb2741ef30e8ad8cc33ff4a9d2adee 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/noise.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/noise.h @@ -4,5 +4,5 @@ extern radspa_descriptor_t noise_desc; radspa_t * noise_create(uint32_t init_var); -void noise_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void noise_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.c b/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.c index ed73a4a2d7819370e208faf486f45f64b5f245ee..a9bf3641a638639f8935cf42beb6671d9759f53e 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.c @@ -25,7 +25,7 @@ radspa_t * noise_burst_create(uint32_t init_var){ #define SAMPLE_RATE_SORRY 48000 -void noise_burst_run(radspa_t * noise_burst, uint16_t num_samples, uint32_t render_pass_id){ +void noise_burst_run(radspa_t * noise_burst, uint32_t render_pass_id){ noise_burst_data_t * plugin_data = noise_burst->plugin_data; radspa_signal_t * output_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_OUTPUT); radspa_signal_t * trigger_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_TRIGGER); @@ -47,7 +47,7 @@ void noise_burst_run(radspa_t * noise_burst, uint16_t num_samples, uint32_t rend int16_t out = plugin_data->last_out; - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ if(!(i && trigger_const)){ if(!trigger_const){ trigger = radspa_signal_get_value(trigger_sig, i, render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.h b/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.h index 6653858f69ebf767978518fc55bd5e5d5d3c543c..3231f9d9aab75dfabc35f83b90b83d013b82e967 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/noise_burst.h @@ -12,5 +12,5 @@ typedef struct { extern radspa_descriptor_t noise_burst_desc; radspa_t * noise_burst_create(uint32_t init_var); -void noise_burst_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void noise_burst_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/osc.c b/components/bl00mbox/radspa/standard_plugin_lib/osc.c index 7212d20cb771e87abb1a28c5a8f183a8cb81199e..f852b814d7b6ae4a4bb8305af3c80c6cc8feb27f 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/osc.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/osc.c @@ -60,7 +60,7 @@ radspa_descriptor_t osc_desc = { #define OSC_MEGASWITCH \ case 0: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ RINGMOD_READ \ FM_READ \ OSCILLATE \ @@ -70,7 +70,7 @@ radspa_descriptor_t osc_desc = { } \ break; \ case 1: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ FM_READ \ OSCILLATE \ SYNC_IN_READ \ @@ -79,7 +79,7 @@ radspa_descriptor_t osc_desc = { } \ break; \ case 2: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ RINGMOD_READ \ OSCILLATE \ OUT_WRITE \ @@ -87,14 +87,14 @@ radspa_descriptor_t osc_desc = { } \ break; \ case 3: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ OSCILLATE \ OUT_WRITE \ SYNC_OUT_WRITE \ } \ break; \ case 4: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ RINGMOD_READ \ FM_READ \ OSCILLATE \ @@ -103,7 +103,7 @@ radspa_descriptor_t osc_desc = { } \ break; \ case 5: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ FM_READ \ OSCILLATE \ SYNC_IN_READ \ @@ -111,20 +111,20 @@ radspa_descriptor_t osc_desc = { } \ break; \ case 6: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ RINGMOD_READ \ OSCILLATE \ SYNC_OUT_WRITE \ } \ break; \ case 7: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ OSCILLATE \ SYNC_OUT_WRITE \ } \ break; \ case 8: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ RINGMOD_READ \ FM_READ \ OSCILLATE \ @@ -133,7 +133,7 @@ radspa_descriptor_t osc_desc = { } \ break; \ case 9: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ FM_READ \ OSCILLATE \ SYNC_IN_READ \ @@ -141,14 +141,14 @@ radspa_descriptor_t osc_desc = { } \ break; \ case 10: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ RINGMOD_READ \ OSCILLATE \ OUT_WRITE \ } \ break; \ case 11: \ - for(; i < num_samples; i++){ \ + for(; i < RADSPA_BUFFER_LEN; i++){ \ OSCILLATE \ OUT_WRITE \ } \ @@ -356,7 +356,7 @@ static inline int16_t apply_waveform(osc_data_t * data, int16_t input, int32_t i #define ANTIALIASING_INDEX 64 -void osc_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id){ +void osc_run(radspa_t * osc, uint32_t render_pass_id){ osc_data_t * data = osc->plugin_data; int8_t * table = (int8_t * ) osc->plugin_table; radspa_signal_t * speed_sig = radspa_signal_get_by_index(osc, OSC_SPEED); @@ -394,7 +394,7 @@ void osc_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id){ OSCILLATE - if(lfo) data->counter += incr * ((num_samples - 1) << 3); + if(lfo) data->counter += incr * ((RADSPA_BUFFER_LEN - 1) << 3); if(radspa_trigger_get(sync_in, &(data->sync_in)) > 0){ SYNC_IN_APPLY diff --git a/components/bl00mbox/radspa/standard_plugin_lib/osc.h b/components/bl00mbox/radspa/standard_plugin_lib/osc.h index e24e21b1a46e700becba96cdf7ef73a5cac400d7..f4b98072d374016b0313a60936c38d9a1eca874d 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/osc.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/osc.h @@ -21,4 +21,4 @@ typedef struct { extern radspa_descriptor_t osc_desc; radspa_t * osc_create(uint32_t init_var); -void osc_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void osc_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.c b/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.c index 972fa17e844c8b412dd9de3541325f9f0226c583..9e06bc7219e0a7ef3602af490815279de091e7d0 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.c @@ -77,7 +77,7 @@ static inline int16_t waveshaper(int32_t saw, int16_t shape){ return tmp; } -void osc_fm_run(radspa_t * osc_fm, uint16_t num_samples, uint32_t render_pass_id){ +void osc_fm_run(radspa_t * osc_fm, uint32_t render_pass_id){ osc_fm_data_t * data = osc_fm->plugin_data; int16_t pitch_const = radspa_signal_get_const_value(data->pitch_sig, render_pass_id); @@ -101,7 +101,7 @@ void osc_fm_run(radspa_t * osc_fm, uint16_t num_samples, uint32_t render_pass_id if(fm_thru_const) radspa_signal_set_const_value(data->fm_pitch_thru_sig, pitch_const + fm_pitch_offset_const - RADSPA_SIGNAL_VAL_SCT_A440); - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ if(pitch_const == -32768){ pitch = radspa_signal_get_value(data->pitch_sig, i, render_pass_id); if(pitch != data->prev_pitch){ diff --git a/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.h b/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.h index 720ac9a9a04430efdb0b190e56a42684b5921ce4..7cd03c60e61d1ede95571b9f1ff9c0fec4a3dec2 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/osc_fm.h @@ -16,5 +16,5 @@ typedef struct { extern radspa_descriptor_t osc_fm_desc; radspa_t * osc_fm_create(uint32_t init_var); -void osc_fm_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void osc_fm_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.c b/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.c index 2c3a79c4d731655616808f224a481752023f47ad..fdfaef75b2e80e31edaea0142c83e50021218793 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.c @@ -115,7 +115,7 @@ static void voice_stop(poly_squeeze_voice_t * voice){ voice->trigger_out = tmp; } -void poly_squeeze_run(radspa_t * poly_squeeze, uint16_t num_samples, uint32_t render_pass_id){ +void poly_squeeze_run(radspa_t * poly_squeeze, 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])); @@ -124,7 +124,7 @@ void poly_squeeze_run(radspa_t * poly_squeeze, uint16_t num_samples, uint32_t re for(uint8_t j = 0; j < data->num_inputs; j++){ uint16_t pitch_index; int16_t trigger_in = radspa_trigger_get_const(&poly_squeeze->signals[TRIGGER_INPUT + NUM_MPX*j], - &inputs[j].trigger_in_hist, &pitch_index, num_samples, render_pass_id); + &inputs[j].trigger_in_hist, &pitch_index, render_pass_id); notes[j].pitch = radspa_signal_get_value(&poly_squeeze->signals[PITCH_INPUT + NUM_MPX*j], pitch_index, render_pass_id); // should order events by pitch index some day maybe if(trigger_in > 0){ diff --git a/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.h b/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.h index 40f954d3cfc25f6b34a17a19fc716eac477eccf9..7b90871c9658053c8c7c15e4aa28312d4e9e68ad 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/poly_squeeze.h @@ -31,4 +31,4 @@ typedef struct { 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); +void poly_squeeze_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.c b/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.c index ff9c6da3c7cd34bfe36280693440a99cc06f864d..7ff83b17b44d7e438c499b4f47cc28f62d11edaa 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.c @@ -41,7 +41,7 @@ radspa_descriptor_t range_shifter_desc = { } \ } -void range_shifter_run(radspa_t * range_shifter, uint16_t num_samples, uint32_t render_pass_id){ +void range_shifter_run(radspa_t * range_shifter, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT); radspa_signal_t * output_a_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT_A); radspa_signal_t * output_b_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT_B); @@ -81,14 +81,14 @@ void range_shifter_run(radspa_t * range_shifter, uint16_t num_samples, uint32_t APPLY_GAIN radspa_signal_set_const_value(output_sig, ret); } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t ret = radspa_signal_get_value(input_sig, i, render_pass_id); APPLY_GAIN radspa_signal_set_value(output_sig, i, ret); } } } else { - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ uint16_t k = i; GET_GAIN if(!output_span){ diff --git a/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.h b/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.h index 254099f8a2a0be8e175429c1be9fc07e20e55299..e24f0bb864804cf96771038a6556c6c685a4f137 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/range_shifter.h @@ -4,4 +4,4 @@ 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); +void range_shifter_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/sampler.c b/components/bl00mbox/radspa/standard_plugin_lib/sampler.c index 7fe4d65ba65114da0fa157b6b8f9a36dd52a6b85..02706cb1873d5e507f4b314ae6c6735fef861df5 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/sampler.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/sampler.c @@ -32,7 +32,7 @@ radspa_descriptor_t sampler_desc = { #define STATUS_RECORD_NEW_EVENT 4 #define BUFFER_OFFSET 11 -void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_id){ +void sampler_run(radspa_t * sampler, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(sampler, SAMPLER_OUTPUT); radspa_signal_t * trigger_sig = radspa_signal_get_by_index(sampler, SAMPLER_TRIGGER); radspa_signal_t * rec_trigger_sig = radspa_signal_get_by_index(sampler, SAMPLER_REC_TRIGGER); @@ -64,13 +64,14 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ buf32[SAMPLE_RATE/2] = 1; } uint32_t buffer_size = sampler->plugin_table_len - BUFFER_OFFSET; - uint64_t buffer_size_long = buffer_size * 48000; + uint64_t buffer_size_long = buffer_size * RADSPA_SAMPLE_RATE; if(sample_len >= buffer_size) sample_len = buffer_size - 1; if(sample_start >= buffer_size) sample_start = buffer_size - 1; bool output_mute = !data->playback_active; bool output_const = sample_rate < 100; + uint16_t num_samples = RADSPA_BUFFER_LEN; if(output_const){ sample_rate *= num_samples; num_samples = 1; @@ -93,7 +94,7 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ } if(data->rec_active){ int16_t rec_in = radspa_signal_get_value(rec_in_sig, i, render_pass_id); - int32_t write_head_pos = (data->write_head_pos_long * 699) >> 25; // equiv to x/48000 (acc 0.008%) + int32_t write_head_pos = data->write_head_pos_long/RADSPA_SAMPLE_RATE; if(data->write_head_pos_prev == write_head_pos){ if(data->write_steps){ data->rec_acc += rec_in; @@ -156,14 +157,14 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ int32_t read_head_pos; int8_t read_head_pos_subsample; if(data->playback_active){ - read_head_pos = (data->read_head_pos_long * 699) >> (25-6); // equiv to (x<<6)/48000 (acc 0.008%) + read_head_pos = (data->read_head_pos_long << 6)/RADSPA_SAMPLE_RATE; read_head_pos_subsample = read_head_pos & 0b111111; read_head_pos = read_head_pos >> 6; if(read_head_pos >= sample_len){ if(buf[STATUS] & (1<<(STATUS_PLAYBACK_LOOP))){ while(read_head_pos > sample_len){ if(sample_len){ - data->read_head_pos_long -= (uint64_t) sample_len * 48000; + data->read_head_pos_long -= (uint64_t) sample_len * RADSPA_SAMPLE_RATE; read_head_pos -= sample_len; } else { data->read_head_pos_long = 0; @@ -228,7 +229,7 @@ void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_ } } -#define MAX_SAMPLE_LEN (48000UL*300) +#define MAX_SAMPLE_LEN (RADSPA_SAMPLE_RATE * 300UL) radspa_t * sampler_create(uint32_t init_var){ if(init_var == 0) return NULL; //doesn't make sense @@ -247,7 +248,7 @@ radspa_t * sampler_create(uint32_t init_var){ int16_t * buf = sampler->plugin_table; uint32_t * buf32 = (uint32_t *) buf; - buf32[SAMPLE_RATE/2] = 48000; + buf32[SAMPLE_RATE/2] = RADSPA_SAMPLE_RATE; buf[STATUS] = 1<<(STATUS_RECORD_OVERFLOW); return sampler; } diff --git a/components/bl00mbox/radspa/standard_plugin_lib/sampler.h b/components/bl00mbox/radspa/standard_plugin_lib/sampler.h index 61c064dcdc2cd71a1aeac7a20939ad6e6aa51c73..6505a1651e6ccf4d3a37321c6da491c59f3b4a93 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/sampler.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/sampler.h @@ -21,5 +21,5 @@ typedef struct { extern radspa_descriptor_t sampler_desc; radspa_t * sampler_create(uint32_t init_var); -void sampler_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void sampler_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/sequencer.c b/components/bl00mbox/radspa/standard_plugin_lib/sequencer.c index e5d2e9398781c464d65e7ddb5840be82d7f29bef..bb8666d63f7e9ecd7d72820ef5c0c9d9c96a8a46 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/sequencer.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/sequencer.c @@ -25,10 +25,10 @@ radspa_descriptor_t sequencer_desc = { 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); + return (RADSPA_SAMPLE_RATE * 60ULL * 4) / (bpm * beat_div); } -void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_pass_id){ +void sequencer_run(radspa_t * sequencer, uint32_t render_pass_id){ bool output_request = false; sequencer_data_t * data = sequencer->plugin_data; sequencer_track_data_t * tracks = (void *) (&data[1]); @@ -67,7 +67,7 @@ void sequencer_run(radspa_t * sequencer, uint16_t num_samples, uint32_t render_p data->beat_div_prev = beat_div; } - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int16_t sync_in = radspa_trigger_get(radspa_signal_get_value(sync_in_sig, i, render_pass_id), &(data->sync_in_hist)); if(sync_in){ diff --git a/components/bl00mbox/radspa/standard_plugin_lib/sequencer.h b/components/bl00mbox/radspa/standard_plugin_lib/sequencer.h index 4d53c4f9d5a047680802d094b24c668aa66ddcc0..9d43116e660583586d05390d424830a42f090593 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/sequencer.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/sequencer.h @@ -29,4 +29,4 @@ typedef struct { extern radspa_descriptor_t sequencer_desc; radspa_t * sequencer_create(uint32_t init_var); -void sequencer_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void sequencer_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.c b/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.c index e2c8ec7a4baa9bdfd984afb0c6c6611475a4176c..1787a0fe83e97e3e6e612cfc1535bd1cc110ad71 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.c @@ -22,7 +22,7 @@ radspa_t * slew_rate_limiter_create(uint32_t init_var){ return slew_rate_limiter; } -void slew_rate_limiter_run(radspa_t * slew_rate_limiter, uint16_t num_samples, uint32_t render_pass_id){ +void slew_rate_limiter_run(radspa_t * slew_rate_limiter, uint32_t render_pass_id){ radspa_signal_t * output_sig = radspa_signal_get_by_index(slew_rate_limiter, SLEW_RATE_LIMITER_OUTPUT); if(output_sig->buffer == NULL) return; radspa_signal_t * input_sig = radspa_signal_get_by_index(slew_rate_limiter, SLEW_RATE_LIMITER_INPUT); @@ -31,7 +31,7 @@ void slew_rate_limiter_run(radspa_t * slew_rate_limiter, uint16_t num_samples, u slew_rate_limiter_data_t * data = slew_rate_limiter->plugin_data; int32_t ret = 0; - for(uint16_t i = 0; i < num_samples; i++){ + for(uint16_t i = 0; i < RADSPA_BUFFER_LEN; i++){ int32_t input = radspa_signal_get_value(input_sig, i, render_pass_id); int32_t slew_rate = (uint16_t) radspa_signal_get_value(slew_rate_sig, i, render_pass_id); ret = data->prev; diff --git a/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.h b/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.h index 4c92240b201abab055a92d0493dfa36f3ee54988..047089a331c02e1dc34e8e0d6bc6fa5c2deb6a9d 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/slew_rate_limiter.h @@ -8,5 +8,5 @@ typedef struct { extern radspa_descriptor_t slew_rate_limiter_desc; radspa_t * slew_rate_limiter_create(uint32_t init_var); -void slew_rate_limiter_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void slew_rate_limiter_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.c b/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.c index d6e1982279c3c3a4c13cfa6eb4751e5f3633db06..f0c951111a1e91e5ee4ef9e3efae65e70f4935b2 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.c +++ b/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.c @@ -17,7 +17,7 @@ typedef struct { int16_t trigger_in_prev[]; } trigger_merge_data_t; -void trigger_merge_run(radspa_t * plugin, uint16_t num_samples, uint32_t render_pass_id){ +void trigger_merge_run(radspa_t * plugin, uint32_t render_pass_id){ int num_inputs = plugin->len_signals - 1; trigger_merge_data_t * data = plugin->plugin_data; bool block_stop_events = plugin->plugin_table[0]; @@ -26,7 +26,7 @@ void trigger_merge_run(radspa_t * plugin, uint16_t num_samples, uint32_t render_ int16_t merged_trigger = 0; int16_t last_timestamp = -1; for(uint8_t j = 0; j < num_inputs; j++){ - int16_t trigger_in = radspa_trigger_get_const(&plugin->signals[j], &data->trigger_in_prev[j], (uint16_t *) &i, num_samples, render_pass_id); + int16_t trigger_in = radspa_trigger_get_const(&plugin->signals[j], &data->trigger_in_prev[j], (uint16_t *) &i, render_pass_id); if((last_timestamp > i) || (!trigger_in)) continue; if((trigger_in > 0) && (last_timestamp == i)){ if(merged_trigger != -1){ diff --git a/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.h b/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.h index 484ec37bda4f3b5fd81dc8cc0aeebf0088b8e494..d9dad9f9ecbe42ac1f679216fb76babdaa854a77 100644 --- a/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.h +++ b/components/bl00mbox/radspa/standard_plugin_lib/trigger_merge.h @@ -4,5 +4,5 @@ extern radspa_descriptor_t trigger_merge_desc; radspa_t * trigger_merge_create(uint32_t init_var); -void trigger_merge_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); +void trigger_merge_run(radspa_t * osc, uint32_t render_pass_id); diff --git a/components/flow3r_bsp/flow3r_bsp_max98091.c b/components/flow3r_bsp/flow3r_bsp_max98091.c index 67ce09f81041b3c4ada1e5485e7d0656b3202bda..eb5b9d490878c44fbbdb86a6b6f0c29b2a72a917 100644 --- a/components/flow3r_bsp/flow3r_bsp_max98091.c +++ b/components/flow3r_bsp/flow3r_bsp_max98091.c @@ -461,7 +461,6 @@ void flow3r_bsp_max98091_init(void) { // jack detect enable POKE(JACK_DETECT, 1 << 7); - // TODO(q3k): mute this ESP_LOGI( TAG, "Codec initilialied! Don't worry about the readback errors above."); diff --git a/components/st3m/st3m_audio.c b/components/st3m/st3m_audio.c index 214bd6726e699c5081d623f83abcfe19ff06a807..40f15041e28846254e5460a73a41d4a612ff0856 100644 --- a/components/st3m/st3m_audio.c +++ b/components/st3m/st3m_audio.c @@ -14,46 +14,17 @@ #include "freertos/task.h" #include "bl00mbox.h" +#include "bl00mbox_config.h" +#if FLOW3R_BSP_AUDIO_SAMPLE_RATE != BL00MBOX_SAMPLE_RATE +#error bl00mbox sample rate mismatch +#endif +#if FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE != BL00MBOX_BUFFER_LEN +#error bl00mbox buffer size mismatch +#endif #include "st3m_pcm.h" static const char *TAG = "st3m-audio"; -// TODO: clean up -static void bl00mbox_init_wrapper(uint32_t sample_rate, uint16_t max_len) { - bl00mbox_init(); -} -static bool bl00mbox_audio_render_wrapper(int16_t *rx, int16_t *tx, - uint16_t len) { - bl00mbox_audio_render(rx, tx, len); - return true; -} - -/* You can add your own audio engine here by simply adding a valid struct to - * this list! For details about the fields check out st3m_audio.h. - */ - -static const st3m_audio_engine_t engines[] = { - { - .name = "bl00mbox", - .render_fun = bl00mbox_audio_render_wrapper, - .init_fun = bl00mbox_init_wrapper, - }, - { - .name = "PCM", - .render_fun = st3m_pcm_audio_render, - .init_fun = NULL, - } -}; - -static const uint8_t num_engines = - (sizeof(engines)) / (sizeof(st3m_audio_engine_t)); - -typedef struct { - int32_t volume; - bool mute; - bool active; // whether the engine has been filling tx in the last run -} _engine_data_t; - #define TIMEOUT_MS 1000 static void _audio_player_task(void *data); @@ -247,8 +218,6 @@ typedef struct { st3m_audio_input_source_t thru_target_source; st3m_audio_input_source_t source; - _engine_data_t *engines_data; - // Software-based audio pipe settings. int32_t input_thru_vol; int32_t input_thru_vol_int; @@ -533,24 +502,7 @@ void st3m_audio_init(void) { assert(state_mutex != NULL); flow3r_bsp_audio_init(); - { - _engine_data_t *tmp = malloc(sizeof(_engine_data_t) * num_engines); - LOCK; - state.engines_data = tmp; - UNLOCK; - } - - for (uint8_t i = 0; i < num_engines; i++) { - LOCK; - state.engines_data[i].volume = 4096; - state.engines_data[i].mute = false; - state.engines_data[i].active = false; // is ignored by engine anyways - UNLOCK; - if (engines[i].init_fun != NULL) { - (*engines[i].init_fun)(FLOW3R_BSP_AUDIO_SAMPLE_RATE, - FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE); - } - } + bl00mbox_init(); _update_routing(); _output_apply(&state.speaker); @@ -564,20 +516,21 @@ void st3m_audio_init(void) { ESP_LOGI(TAG, "Audio task started"); } +#define BUF_LEN (FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2) + static void _audio_player_task(void *data) { (void)data; - int16_t buffer_tx[FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2]; - int16_t buffer_rx[FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2]; - int16_t buffer_rx_dummy[FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2]; - int32_t output_acc[FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2]; - int16_t engines_tx[FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2]; - memset(buffer_tx, 0, sizeof(buffer_tx)); + int16_t buffer_rx[BUF_LEN]; + int16_t buffer_empty[BUF_LEN]; + int16_t buffer_acc[BUF_LEN]; memset(buffer_rx, 0, sizeof(buffer_rx)); - memset(buffer_rx_dummy, 0, sizeof(buffer_rx_dummy)); + memset(buffer_empty, 0, sizeof(buffer_empty)); size_t count; st3m_audio_input_source_t source_prev = st3m_audio_input_source_none; + int source_chan = 0; // 0: stereo, 1: left-to-stereo, 2: right-to-stereo + int16_t * source_gain = NULL; // *256: unity gain, NULL: don't render source while (true) { count = 0; @@ -593,136 +546,119 @@ static void _audio_player_task(void *data) { continue; } - int32_t engines_vol[num_engines]; - bool engines_mute[num_engines]; - bool engines_active[num_engines]; - LOCK; - for (uint8_t e = 0; e < num_engines; e++) { - engines_vol[e] = state.engines_data[e].volume; - engines_mute[e] = state.engines_data[e].mute; - } st3m_audio_input_source_t source = state.source; st3m_audio_input_source_t engines_source = state.engines_source; st3m_audio_input_source_t thru_source = state.thru_source; - bool headphones = _headphones_connected(); - int32_t software_volume = headphones ? state.headphones.volume_software - : state.speaker.volume_software; + int32_t software_volume = _headphones_connected() ? + state.headphones.volume_software : + state.speaker.volume_software; bool input_thru_mute = state.input_thru_mute; int32_t input_thru_vol_int = state.input_thru_vol_int; - UNLOCK; // <RX SIGNAL PREPROCESSING> - int32_t rx_gain = 256; // unity - uint8_t rx_chan = 3; // stereo = 0; left = 1; right = 2; off = 3; if (source != source_prev) { // state change: throw away buffer source_prev = source; memset(buffer_rx, 0, sizeof(buffer_rx)); - } else { - LOCK; + source_chan = 0; if (source == st3m_audio_input_source_headset_mic) { - rx_gain = state.headset_mic_gain_software; - rx_chan = 0; // not sure, don't have one here, need to test + source_gain = &state.headset_mic_gain_software; + //source_chan = ?; // not sure, don't have one here, need to test } else if (source == st3m_audio_input_source_line_in) { - rx_gain = state.line_in_gain_software; - rx_chan = 0; + source_gain = &state.line_in_gain_software; } else if (source == st3m_audio_input_source_onboard_mic) { - rx_gain = state.onboard_mic_gain_software; - rx_chan = 1; - } - UNLOCK; - } - - if (rx_chan == 0) { - // keep stereo image - for (uint16_t i = 0; i < FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2; - i++) { - buffer_rx[i] = (buffer_rx[i] * rx_gain) >> 8; - } - } else if (rx_chan < 3) { - // mix one of the input channels to both rx stereo chans (easier - // mono sources) - for (uint16_t i = 0; i < FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2; - i++) { - uint16_t j = (i / 2) * 2 + rx_chan - 1; - buffer_rx[i] = (buffer_rx[j] * rx_gain) >> 8; + source_gain = &state.onboard_mic_gain_software; + source_chan = 1; + } else if (source == st3m_audio_input_source_none) { + source_gain = NULL; } } + UNLOCK; int16_t *engines_rx; - if (engines_source == st3m_audio_input_source_none) { - engines_rx = buffer_rx_dummy; + if (!source_gain) { + engines_rx = buffer_empty; } else { + int32_t rx_gain = *source_gain; // 256 is unity + if (source_chan == 0) { + for (uint16_t i = 0; i < BUF_LEN; i++) { + buffer_rx[i] = (buffer_rx[i] * rx_gain) >> 8; + } + } else if (source_chan == 1) { + for (uint16_t i = 0; i < BUF_LEN; i += 2) { + buffer_rx[i] = buffer_rx[i+1] = (buffer_rx[i] * rx_gain) >> 8; + } + } else if (source_chan == 2){ + for (uint16_t i = 0; i < BUF_LEN; i += 2) { + buffer_rx[i] = buffer_rx[i+1] = (buffer_rx[i+1] * rx_gain) >> 8; + } + } engines_rx = buffer_rx; } - // </RX SIGNAL PREPROCESSING> // <ACCUMULATING ENGINES> - bool output_acc_uninit = true; - for (uint8_t e = 0; e < num_engines; e++) { - // always run function even when muted, else the engine - // might suffer from being deprived of the passage of time - engines_active[e] = (*engines[e].render_fun)( - engines_rx, engines_tx, FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2); - if ((!engines_active[e]) || (!engines_vol[e]) || engines_mute[e]) - continue; - if (output_acc_uninit) { - for (uint16_t i = 0; i < FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2; - i++) { - output_acc[i] = (engines_tx[i] * engines_vol[e]) >> 12; + // note: engines may not write to engines_rx as it might be the empty ref buffer + + bool buffer_acc_init = st3m_pcm_audio_render(engines_rx, buffer_acc, BUF_LEN); + if(buffer_acc_init){ + // bl00mbox handles clipping for us + bl00mbox_audio_render_adding(engines_rx, buffer_acc); + } else { + buffer_acc_init = bl00mbox_audio_render(engines_rx, buffer_acc); + } + + // <THRU> + + if ((thru_source != st3m_audio_input_source_none) && + ((engines_source == thru_source) || + (engines_source == st3m_audio_input_source_none)) && + (!input_thru_mute)) { + if(buffer_acc_init){ + for (int i = 0; i < BUF_LEN; i += 1) { + int32_t val = (buffer_rx[i] * input_thru_vol_int) >> 15; + val += buffer_acc[i]; + // clip here manually + buffer_acc[i] = (val > 32767) ? 32767 : ((val < -32767) ? -32767 : val); } } else { - for (uint16_t i = 0; i < FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2; - i++) { - output_acc[i] += (engines_tx[i] * engines_vol[e]) >> 12; + for (int i = 0; i < BUF_LEN; i += 1) { + int32_t val = (buffer_rx[i] * input_thru_vol_int) >> 15; + // not sure if clipping is crequired here clip here manually + buffer_acc[i] = (val > 32767) ? 32767 : ((val < -32767) ? -32767 : val); } + buffer_acc_init = true; } - output_acc_uninit = false; - } - if (output_acc_uninit) { - memset(output_acc, 0, sizeof(output_acc)); - } - - LOCK; - for (uint8_t e = 0; e < num_engines; e++) { - state.engines_data[e].active = engines_active[e]; } - UNLOCK; - // </ACCUMULATING ENGINES> + // <SCOPE> - // <VOLUME AND THRU> - - for (uint16_t i = 0; i < FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE; i++) { - st3m_scope_write((output_acc[2 * i] + output_acc[2 * i + 1]) >> 3); - } - - for (int i = 0; i < (FLOW3R_BSP_AUDIO_DMA_BUFFER_SIZE * 2); i += 1) { - if ((thru_source != st3m_audio_input_source_none) && - ((engines_source == thru_source) || - (engines_source == st3m_audio_input_source_none)) && - (!input_thru_mute)) { - output_acc[i] += (buffer_rx[i] * input_thru_vol_int) >> 15; + // there should be an off switch for this + if (buffer_acc_init) { + for (uint16_t i = 0; i < BUF_LEN; i+=2) { + st3m_scope_write((buffer_acc[i] + buffer_acc[i + 1]) >> 3); } + } + // <VOLUME> - output_acc[i] = (output_acc[i] * software_volume) >> 15; - - if (output_acc[i] > 32767) output_acc[i] = 32767; - if (output_acc[i] < -32767) output_acc[i] = -32767; + int16_t * buffer_tx = buffer_empty; - buffer_tx[i] = output_acc[i]; + if (buffer_acc_init) { + for (uint16_t i = 0; i < BUF_LEN; i++) { + buffer_acc[i] = (buffer_acc[i] * software_volume) >> 15; + } + buffer_tx = buffer_acc; } - // </VOLUME AND THRU> + // <WRITE> - flow3r_bsp_audio_write(buffer_tx, sizeof(buffer_tx), &count, 1000); - if (count != sizeof(buffer_tx)) { + flow3r_bsp_audio_write(buffer_tx, sizeof(buffer_empty), &count, 1000); + if (count != sizeof(buffer_empty)) { ESP_LOGE(TAG, "audio_write: count (%d) != length (%d)\n", count, - sizeof(buffer_tx)); + sizeof(buffer_empty)); abort(); } } diff --git a/components/st3m/st3m_audio.h b/components/st3m/st3m_audio.h index 51ea9339f27a33d33e28671f71561e15a47b114b..e06daa236d02880502a4eaf9e945715ba2cfdfd4 100644 --- a/components/st3m/st3m_audio.h +++ b/components/st3m/st3m_audio.h @@ -16,48 +16,6 @@ typedef enum { st3m_audio_input_source_auto = 4 } st3m_audio_input_source_t; -/* Initializes the audio engine and passes sample rate as well as max buffer - * length. At this point those values are always 48000/128, but this might - * become variable in the future. However, we see flow3r primarily as a real - * time instrument, and longer buffers introduce latency; the current buffer - * length corresponds to 1.3ms latency which isn't much, but given the up to - * 10ms captouch latency on top we shouldn't be super careless here. - */ -typedef void (*st3m_audio_engine_init_function_t)(uint32_t sample_rate, - uint16_t max_len); - -/* Renders the output of the audio engine and returns whether or not it has - * overwritten tx. Always called for each buffer, no exceptions. This means you - * can keep track of time within the engine easily and use the audio player task - * to handle musical events (the current 1.3ms buffer rate is well paced for - * this), but it also puts the burden on you of exiting early if there's nothing - * to do. - * - * rx (input) and tx (output) are both stereo interlaced, i.e. the even indices - * represent the left channel, the odd indices represent the right channel. The - * length is the total length of the buffer so that each channel has len/2 data - * points. len is always even. - * - * The function must never modify rx. This is so that we can pass the same - * buffer to all the engines without having to memcpy by default, so if you need - * to modify rx please do your own memcpy of it. - * - * In a similar manner, tx is not cleaned up when calling the function, it - * carries random junk data that is not supposed to be read by the user. The - * return value indicates whether tx should be used or if tx should be ignored - * andit should be treated as if you had written all zeroes into it (without you - * actually doing so). If you choose to return true please make sure you have - * overwritten the entirety of tx with valid data. - */ -typedef bool (*st3m_audio_engine_render_function_t)(int16_t* rx, int16_t* tx, - uint16_t len); - -typedef struct { - char* name; // used for UI, no longer than 14 characters - st3m_audio_engine_render_function_t render_fun; - st3m_audio_engine_init_function_t init_fun; // optional, else NULL -} st3m_audio_engine_t; - /* Initializes I2S bus, the audio task and required data structures. * Expects an initialized I2C bus, will fail ungracefully otherwise (TODO). */ diff --git a/components/st3m/st3m_media.c b/components/st3m/st3m_media.c index 5750239ecd008bbdf77eb6f698f12172db6bbcc2..e3358d40af80945a237f7856cf43729d49641893 100644 --- a/components/st3m/st3m_media.c +++ b/components/st3m/st3m_media.c @@ -1,5 +1,6 @@ #include "st3m_media.h" #include "st3m_audio.h" +#include "flow3r_bsp.h" #include <math.h> #include <stdio.h> @@ -106,7 +107,7 @@ float st3m_media_get_position(void) { float st3m_media_get_time(void) { if (!media_item) return 0; if (media_item->time <= 0) return media_item->time; - return media_item->time - st3m_pcm_queued() / 48000.0 / 2.0; + return media_item->time - st3m_pcm_queued() / ((float) FLOW3R_BSP_AUDIO_SAMPLE_RATE) / 2.0; } void st3m_media_seek(float position) { diff --git a/components/st3m/st3m_pcm.c b/components/st3m/st3m_pcm.c index 851df6b0d05579958110d554252ae7336b33f903..6c2c820c6ec9b626917c9772fae0b99a34b06567 100644 --- a/components/st3m/st3m_pcm.c +++ b/components/st3m/st3m_pcm.c @@ -1,4 +1,5 @@ #include "st3m_pcm.h" +#include "flow3r_bsp.h" #include <unistd.h> @@ -41,7 +42,7 @@ bool st3m_pcm_audio_render(int16_t *rx, int16_t *tx, uint16_t len) { static int phase = 0; void st3m_pcm_queue_s16(int hz, int ch, int count, int16_t *data) { - if (hz == 48000) { + if (hz == FLOW3R_BSP_AUDIO_SAMPLE_RATE) { if (ch == 2) { if (st3m_pcm_gain == 4096) { for (int i = 0; i < count * 2; i++) { @@ -75,7 +76,7 @@ void st3m_pcm_queue_s16(int hz, int ch, int count, int16_t *data) { } } } else { - int fraction = ((48000.0 / hz) - 1.0) * 65536; + int fraction = ((((float) FLOW3R_BSP_AUDIO_SAMPLE_RATE) / hz) - 1.0) * 65536; if (ch == 2) { for (int i = 0; i < count; i++) { st3m_pcm_buffer[st3m_pcm_w++] = @@ -112,7 +113,7 @@ void st3m_pcm_queue_s16(int hz, int ch, int count, int16_t *data) { } void st3m_pcm_queue_float(int hz, int ch, int count, float *data) { - if (hz == 48000) { + if (hz == FLOW3R_BSP_AUDIO_SAMPLE_RATE) { if (ch == 2) { if (st3m_pcm_gain == 4096) for (int i = 0; i < count * 2; i++) { @@ -144,7 +145,7 @@ void st3m_pcm_queue_float(int hz, int ch, int count, float *data) { } } } else { - int fraction = ((48000.0 / hz) - 1.0) * 65536; + int fraction = ((((float) FLOW3R_BSP_AUDIO_SAMPLE_RATE) / hz) - 1.0) * 65536; if (ch == 2) { for (int i = 0; i < count; i++) { st3m_pcm_buffer[st3m_pcm_w++] = diff --git a/python_payload/st3m/ui/mixer.py b/python_payload/st3m/ui/mixer.py index 9df06c90b7138365e4ae0ae3f1da552184903af0..59c1696868968872ee93f5f2694baed6a1b799ed 100644 --- a/python_payload/st3m/ui/mixer.py +++ b/python_payload/st3m/ui/mixer.py @@ -40,6 +40,9 @@ class Channel: def get_rms_dB(self): return -math.inf + def get_load(self): + return 0 + def get_mute(self): mute = False if self.get_name() in session_channel_vol_mute: @@ -98,6 +101,9 @@ class bl00mboxChannel(Channel): def get_rms_dB(self): return self.blm.sys_rms_dB + def get_load(self): + return self.blm.render.load + class mediaChannel(Channel): def get_name(self): @@ -126,6 +132,7 @@ class ChannelColors: name = (0, 1, 1) vol_bar = (0, 1, 0) rms_bar = (1, 0, 0) + load_bar = (0, 0.5, 1) mute_bg = ((0.2, 0.2, 0.2), (0.5, 0.0, 0.0)) mute_fg = ((0.5, 0.5, 0.5), (0.8, 0.8, 0.8)) @@ -135,6 +142,7 @@ class HighlightColors: name = (0, 1, 1) vol_bar = (0, 1, 0) rms_bar = (1, 0, 0) + load_bar = (0, 0.5, 1) mute_bg = ((0.2, 0.2, 0.2), (0.8, 0.0, 0.0)) mute_fg = ((0.5, 0.5, 0.5), (1.0, 1.0, 1.0)) @@ -184,8 +192,10 @@ class AudioMixer(Responder): self._chans = [mediaChannel()] for c in bl00mbox.Sys.collect_channels(True): chan = bl00mboxChannel(c) - chan.prev_compute_rms = chan.blm.compute_rms - chan.blm.compute_rms = True + chan.prev_compute_rms = chan.blm.render.rms_dB is None + chan.blm.render.rms_dB = True + chan.prev_compute_time = chan.blm.render.load is None + chan.blm.render.load = True self._chans += [chan] """ for i in range(5): @@ -335,10 +345,15 @@ class AudioMixer(Responder): ctx.round_rectangle(-chan_width / 2 + 3, 41, 18, 18, 2).stroke() ctx.rgb(0, 0, 0) - ctx.rectangle(chan_width / 2 - 13, bar_bottom - len_bar, 9, len_bar).fill() + + if isinstance(chan, bl00mboxChannel): + shift = 0 + else: + shift = 7 + ctx.rectangle(chan_width / 2 - 16 + shift, bar_bottom - len_bar, 12-shift, len_bar).fill() # reference notch - ctx.move_to(chan_width / 2 - 13, bar_bottom - len_bar * 5 / 7) + ctx.move_to(chan_width / 2 - 16 + shift, bar_bottom - len_bar * 5 / 7) ctx.rel_line_to(-5, 0).stroke() # vol bar @@ -347,7 +362,7 @@ class AudioMixer(Responder): vol_bar_len = min(1, max(0, vol_bar_len)) vol_bar_len *= len_bar ctx.rectangle( - chan_width / 2 - 12, bar_bottom - vol_bar_len, 3, vol_bar_len + chan_width / 2 - 15 + shift, bar_bottom - vol_bar_len, 3, vol_bar_len ).fill() if self._editing_channel == 1 and highlight: @@ -358,20 +373,31 @@ class AudioMixer(Responder): ctx.rel_line_to(5, -3) ctx.fill() - ctx.rgb(0, 0, 0) - ctx.rectangle(chan_width / 2 - 9, bar_bottom - len_bar, 5, len_bar).fill() + if isinstance(chan, bl00mboxChannel): + ctx.rgb(0, 0, 0) + ctx.rectangle(chan_width / 2 - 11, bar_bottom - len_bar, 7, len_bar).fill() + + # rms bar + rms = chan.get_rms_dB() + 15 + ctx.rgb(*colors.rms_bar) + rms_bar_len = (rms + 50) / 70 + rms_bar_len = min(1, max(0, rms_bar_len)) + rms_bar_len *= len_bar + ctx.rectangle( + chan_width / 2 - 11, bar_bottom - rms_bar_len, 3, rms_bar_len + ).fill() - # rms bar - rms = chan.get_rms_dB() + 15 - ctx.rgb(*colors.rms_bar) - rms_bar_len = (rms + 50) / 70 - rms_bar_len = min(1, max(0, rms_bar_len)) - rms_bar_len *= len_bar - ctx.rectangle( - chan_width / 2 - 8, bar_bottom - rms_bar_len, 3, rms_bar_len - ).fill() + # load bar + ctx.rgb(*colors.load_bar) + load_bar_len = chan.blm.render.load * 5 / 7 + load_bar_len = min(1, max(0, load_bar_len)) + load_bar_len *= len_bar + ctx.rectangle( + chan_width / 2 - 7, bar_bottom - load_bar_len, 2, load_bar_len + ).fill() def on_exit(self): for chan in self._chans: if isinstance(chan, bl00mboxChannel): - chan.blm.compute_rms = chan.prev_compute_rms + chan.blm.render.rms_dB = chan.prev_compute_rms + chan.blm.render.load = chan.prev_compute_time