From 3b8a4d7186afd822f1a5b237381f425d299c4efb Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Wed, 23 Nov 2022 10:54:48 +0100 Subject: [PATCH] updated svf to new API (still doc and wah/synth examples broken) --- ChangeLog | 7 +- TODO | 1 + examples/fx_svf/src/bw_example_fx_svf.c | 22 +- examples/fx_svf/vst3/Makefile.linux | 1 - examples/fx_svf/vst3/Makefile.macos | 1 - examples/fx_svf/vst3/Makefile.win32 | 1 - examples/fx_svf/web/Makefile | 1 - include/bw_common.h | 9 + include/bw_one_pole.h | 90 ++++---- include/bw_svf.h | 280 ++++++++++++++++++++---- src/bw_svf.c | 111 ---------- 11 files changed, 308 insertions(+), 216 deletions(-) delete mode 100644 src/bw_svf.c diff --git a/ChangeLog b/ChangeLog index d685a61..7e0b4da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,13 @@ 0.2.0 ----- - * Refactored API of DSP modules to avoid dynamic memory allocation. + * Refactored API of DSP modules. + * Removed bw_inline_one_pole (functionality implemented by bw_one_pole). * Added bw_wah and bw_example_fx_wah. + * Added BW_RESTRICT and removed BW_MALLOC, BW_REALLOC, and BW_FREE from + bw_common. * Renamed bw_example_fx to bw_example_fx_svf. * Removed output "Level" parameter from bw_example_fx_svf. - * Now using correct "Fx|Filter" VST3 subcategory for bw_example_fx_svf. + * Using correct "Fx|Filter" VST3 subcategory for bw_example_fx_svf. * Using official logo as VST3 plugin icon. 0.1.0 diff --git a/TODO b/TODO index 3fe6906..18dbb3f 100644 --- a/TODO +++ b/TODO @@ -9,6 +9,7 @@ code: * web examples construction/destruction * web effect multichannel in? * check const restrict etc. +* define BW_RESTRICT to __restrict or similar when the compiler supports it build system: * make makefiles handle paths with spaces etc diff --git a/examples/fx_svf/src/bw_example_fx_svf.c b/examples/fx_svf/src/bw_example_fx_svf.c index f7c1325..3576dab 100644 --- a/examples/fx_svf/src/bw_example_fx_svf.c +++ b/examples/fx_svf/src/bw_example_fx_svf.c @@ -19,8 +19,8 @@ #include "bw_example_fx_svf.h" -#include #include +#include enum { p_cutoff, @@ -30,42 +30,44 @@ enum { struct _bw_example_fx_svf { // Sub-components - bw_svf svf; + bw_svf_coeffs svf_coeffs; + bw_svf_state svf_state; // Parameters float params[p_n]; }; bw_example_fx_svf bw_example_fx_svf_new() { - bw_example_fx_svf instance = (bw_example_fx_svf)BW_MALLOC(sizeof(struct _bw_example_fx_svf)); + bw_example_fx_svf instance = (bw_example_fx_svf)malloc(sizeof(struct _bw_example_fx_svf)); if (instance != NULL) - bw_svf_init(&instance->svf); + bw_svf_init(&instance->svf_coeffs); return instance; } void bw_example_fx_svf_free(bw_example_fx_svf instance) { - BW_FREE(instance); + free(instance); } void bw_example_fx_svf_set_sample_rate(bw_example_fx_svf instance, float sample_rate) { - bw_svf_set_sample_rate(&instance->svf, sample_rate); + bw_svf_set_sample_rate(&instance->svf_coeffs, sample_rate); } void bw_example_fx_svf_reset(bw_example_fx_svf instance) { - bw_svf_reset(&instance->svf); + bw_svf_reset_coeffs(&instance->svf_coeffs); + bw_svf_reset_state(&instance->svf_coeffs, &instance->svf_state); } void bw_example_fx_svf_process(bw_example_fx_svf instance, const float** x, float** y, int n_samples) { - bw_svf_process(&instance->svf, x[0], y[0], NULL, NULL, n_samples); + bw_svf_process(&instance->svf_coeffs, &instance->svf_state, x[0], y[0], NULL, NULL, n_samples); } void bw_example_fx_svf_set_parameter(bw_example_fx_svf instance, int index, float value) { switch (index) { case p_cutoff: - bw_svf_set_cutoff(&instance->svf, (20e3f - 20.f) * value * value * value + 20.f); + bw_svf_set_cutoff(&instance->svf_coeffs, (20e3f - 20.f) * value * value * value + 20.f); break; case p_Q: - bw_svf_set_Q(&instance->svf, 0.5f + 9.5f * value); + bw_svf_set_Q(&instance->svf_coeffs, 0.5f + 9.5f * value); break; } } diff --git a/examples/fx_svf/vst3/Makefile.linux b/examples/fx_svf/vst3/Makefile.linux index 3e1f449..dd3ae2f 100644 --- a/examples/fx_svf/vst3/Makefile.linux +++ b/examples/fx_svf/vst3/Makefile.linux @@ -19,7 +19,6 @@ INSTALL_PREFIX=/usr/local ROOT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) SOURCES= \ - ${ROOT_DIR}/../../../src/bw_svf.c \ ${ROOT_DIR}/../src/bw_example_fx_svf.c \ \ ${ROOT_DIR}/../../common/vst3/entry.cpp \ diff --git a/examples/fx_svf/vst3/Makefile.macos b/examples/fx_svf/vst3/Makefile.macos index 1e26d95..6634133 100644 --- a/examples/fx_svf/vst3/Makefile.macos +++ b/examples/fx_svf/vst3/Makefile.macos @@ -17,7 +17,6 @@ LDFLAGS= \ ROOT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) SOURCES= \ - ${ROOT_DIR}/../../../src/bw_svf.c \ ${ROOT_DIR}/../src/bw_example_fx_svf.c \ \ ${ROOT_DIR}/../../common/vst3/entry.cpp \ diff --git a/examples/fx_svf/vst3/Makefile.win32 b/examples/fx_svf/vst3/Makefile.win32 index c8996df..c25e5b7 100644 --- a/examples/fx_svf/vst3/Makefile.win32 +++ b/examples/fx_svf/vst3/Makefile.win32 @@ -25,7 +25,6 @@ ARCH=x86_64 ROOT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) SOURCES= \ - ${ROOT_DIR}/../../../src/bw_svf.c \ ${ROOT_DIR}/../src/bw_example_fx_svf.c \ \ ${ROOT_DIR}/../../common/vst3/entry.cpp \ diff --git a/examples/fx_svf/web/Makefile b/examples/fx_svf/web/Makefile index df357eb..78edcbc 100644 --- a/examples/fx_svf/web/Makefile +++ b/examples/fx_svf/web/Makefile @@ -25,7 +25,6 @@ LDFLAGS= \ ROOT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) SOURCES= \ - ${ROOT_DIR}/../../../src/bw_svf.c \ ${ROOT_DIR}/../src/bw_example_fx_svf.c \ ${ROOT_DIR}/../../common/web/walloc.c \ ${ROOT_DIR}/../../common/web/wrapper.c diff --git a/include/bw_common.h b/include/bw_common.h index 69eef46..e9ca83f 100644 --- a/include/bw_common.h +++ b/include/bw_common.h @@ -30,6 +30,7 @@ *
  • Version 0.2.0: *
      *
    • Removed BW_MALLOC, BW_REALLOC, and BW_FREE.
    • + *
    • Added BW_RESTRICT.
    • *
    *
  • *
  • Version 0.1.0: @@ -82,6 +83,14 @@ # include #endif +#ifndef BW_RESTRICT +# if defined(__STDC__) && (__STDC_VERSION__ >= 199901L) +# define BW_RESTRICT restrict +# else +# define BW_RESTRICT +# endif +#endif + /*! ... }}} */ #endif diff --git a/include/bw_one_pole.h b/include/bw_one_pole.h index e674d99..edddf0e 100644 --- a/include/bw_one_pole.h +++ b/include/bw_one_pole.h @@ -48,6 +48,8 @@ extern "C" { #endif +#include + /*! api {{{ * #### bw_one_pole_coeffs * ```>>> */ @@ -75,39 +77,39 @@ typedef enum { * * #### bw_one_pole_init() * ```>>> */ -static inline void bw_one_pole_init(bw_one_pole_coeffs *restrict coeffs); +static inline void bw_one_pole_init(bw_one_pole_coeffs *BW_RESTRICT coeffs); /*! <<<``` * Initializes `coeffs`. * * #### bw_one_pole_set_sample_rate() * ```>>> */ -static inline void bw_one_pole_set_sample_rate(bw_one_pole_coeffs *restrict coeffs, float sample_rate); +static inline void bw_one_pole_set_sample_rate(bw_one_pole_coeffs *BW_RESTRICT coeffs, float sample_rate); /*! <<<``` * Sets the `sample_rate` (Hz) value for the given `coeffs`. * * #### bw_one_pole_reset_state() * ```>>> */ -static inline void bw_one_pole_reset_state(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state); +static inline void bw_one_pole_reset_state(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state); /*! <<<``` * Resets the given `state` to the initial state using the given `coeffs`. * >>> */ -static inline void bw_one_pole_reset_coeffs(bw_one_pole_coeffs *restrict coeffs); +static inline void bw_one_pole_reset_coeffs(bw_one_pole_coeffs *BW_RESTRICT coeffs); -static inline void bw_one_pole_update_coeffs_ctrl(bw_one_pole_coeffs *restrict coeffs); -static inline void bw_one_pole_update_coeffs_audio(bw_one_pole_coeffs *restrict coeffs); +static inline void bw_one_pole_update_coeffs_ctrl(bw_one_pole_coeffs *BW_RESTRICT coeffs); +static inline void bw_one_pole_update_coeffs_audio(bw_one_pole_coeffs *BW_RESTRICT coeffs); -static inline float bw_one_pole_process1(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x); -static inline float bw_one_pole_process1_sticky_abs(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x); -static inline float bw_one_pole_process1_sticky_rel(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x); -static inline float bw_one_pole_process1_asym(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x); -static inline float bw_one_pole_process1_asym_sticky_abs(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x); -static inline float bw_one_pole_process1_asym_sticky_rel(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x); +static inline float bw_one_pole_process1(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x); +static inline float bw_one_pole_process1_sticky_abs(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x); +static inline float bw_one_pole_process1_sticky_rel(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x); +static inline float bw_one_pole_process1_asym(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x); +static inline float bw_one_pole_process1_asym_sticky_abs(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x); +static inline float bw_one_pole_process1_asym_sticky_rel(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x); /*! ... * #### bw_one_pole_process() * ```>>> */ -static inline void bw_one_pole_process(bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, const float *x, float *y, int n_samples); +static inline void bw_one_pole_process(bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, const float *x, float *y, int n_samples); /*! <<<``` * Lets the given `instance` process `n_samples` samples from the input * buffer `x` and fills the corresponding `n_samples` samples in the output @@ -117,7 +119,7 @@ static inline void bw_one_pole_process(bw_one_pole_coeffs *restrict coeffs, bw_o /*! ... * #### bw_one_pole_set_init_val() * ```>>> */ -static inline void bw_one_pole_set_init_val(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_init_val(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the initial/quiescent `value` for the given `instance`. * @@ -131,7 +133,7 @@ static inline void bw_one_pole_set_init_val(bw_one_pole_coeffs *restrict coeffs, /*! ... * #### bw_one_pole_set_cutoff() * ```>>> */ -static inline void bw_one_pole_set_cutoff(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_cutoff(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets both the upgoing (attack) and downgoing (decay) cutoff frequency to * the given `value` (Hz) for the given `instance`. @@ -147,7 +149,7 @@ static inline void bw_one_pole_set_cutoff(bw_one_pole_coeffs *restrict coeffs, f /*! ... * #### bw_one_pole_set_cutoff_up() * ```>>> */ -static inline void bw_one_pole_set_cutoff_up(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_cutoff_up(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the upgoing (attack) cutoff frequency to the given `value` (Hz) for * the given `instance`. @@ -161,7 +163,7 @@ static inline void bw_one_pole_set_cutoff_up(bw_one_pole_coeffs *restrict coeffs /*! ... * #### bw_one_pole_set_cutoff_down() * ```>>> */ -static inline void bw_one_pole_set_cutoff_down(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_cutoff_down(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the downgoing (attack) cutoff frequency to the given `value` (Hz) * for the given `instance`. @@ -175,7 +177,7 @@ static inline void bw_one_pole_set_cutoff_down(bw_one_pole_coeffs *restrict coef /*! ... * #### bw_one_pole_set_tau() * ```>>> */ -static inline void bw_one_pole_set_tau(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_tau(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets both the upgoing (attack) and downgoing (decay) time constant to the * given `value` (s) for the given `instance`. @@ -191,7 +193,7 @@ static inline void bw_one_pole_set_tau(bw_one_pole_coeffs *restrict coeffs, floa /*! ... * #### bw_one_pole_set_tau_up() * ```>>> */ -static inline void bw_one_pole_set_tau_up(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_tau_up(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the upgoing (attack) time constant to the given `value` (s) for the * given `instance`. @@ -205,7 +207,7 @@ static inline void bw_one_pole_set_tau_up(bw_one_pole_coeffs *restrict coeffs, f /*! ... * #### bw_one_pole_set_tau_down() * ```>>> */ -static inline void bw_one_pole_set_tau_down(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_tau_down(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the downgoing (decay) time constant to the given `value` (s) for the * given `instance`. @@ -219,7 +221,7 @@ static inline void bw_one_pole_set_tau_down(bw_one_pole_coeffs *restrict coeffs, /*! ... * #### bw_one_pole_set_sticky_thresh() * ```>>> */ -static inline void bw_one_pole_set_sticky_thresh(bw_one_pole_coeffs *restrict coeffs, float value); +static inline void bw_one_pole_set_sticky_thresh(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the target-reach threshold specified by `value` for the given * `instance`. @@ -235,7 +237,7 @@ static inline void bw_one_pole_set_sticky_thresh(bw_one_pole_coeffs *restrict co /*! ... * #### bw_one_pole_set_sticky_mode() * ```>>> */ -static inline void bw_one_pole_set_sticky_mode(bw_one_pole_coeffs *restrict coeffs, bw_one_pole_sticky_mode value); +static inline void bw_one_pole_set_sticky_mode(bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_sticky_mode value); /*! <<<``` * Sets the current distance metric for sticky behavior. * }}} */ @@ -272,27 +274,27 @@ struct _bw_one_pole_state { #include -static inline void bw_one_pole_init(bw_one_pole_coeffs *restrict coeffs) { +static inline void bw_one_pole_init(bw_one_pole_coeffs *BW_RESTRICT coeffs) { coeffs->init_val = 0.f; coeffs->cutoff_up = INFINITY; coeffs->cutoff_down = INFINITY; coeffs->sticky_thresh = 0.f; } -static inline void bw_one_pole_set_sample_rate(bw_one_pole_coeffs *restrict coeffs, float sample_rate) { +static inline void bw_one_pole_set_sample_rate(bw_one_pole_coeffs *BW_RESTRICT coeffs, float sample_rate) { coeffs->Ttm2pi = -6.283185307179586f / sample_rate; } -static inline void bw_one_pole_reset_coeffs(bw_one_pole_coeffs *restrict coeffs) { +static inline void bw_one_pole_reset_coeffs(bw_one_pole_coeffs *BW_RESTRICT coeffs) { coeffs->param_changed = ~0; bw_one_pole_update_coeffs_ctrl(coeffs); } -static inline void bw_one_pole_reset_state(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state) { +static inline void bw_one_pole_reset_state(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state) { state->y_z1 = coeffs->init_val; } -static inline void bw_one_pole_update_coeffs_ctrl(bw_one_pole_coeffs *restrict coeffs) { +static inline void bw_one_pole_update_coeffs_ctrl(bw_one_pole_coeffs *BW_RESTRICT coeffs) { if (coeffs->param_changed) { if (coeffs->param_changed & _BW_ONE_POLE_PARAM_CUTOFF_UP) coeffs->mA1u = bw_expf_3(coeffs->Ttm2pi * coeffs->cutoff_up); @@ -304,16 +306,16 @@ static inline void bw_one_pole_update_coeffs_ctrl(bw_one_pole_coeffs *restrict c } } -static inline void bw_one_pole_update_coeffs_audio(bw_one_pole_coeffs *restrict coeffs) { +static inline void bw_one_pole_update_coeffs_audio(bw_one_pole_coeffs *BW_RESTRICT coeffs) { } -static inline float bw_one_pole_process1(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x) { +static inline float bw_one_pole_process1(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x) { const float y = x + coeffs->mA1u * (state->y_z1 - x); state->y_z1 = y; return y; } -static inline float bw_one_pole_process1_sticky_abs(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x) { +static inline float bw_one_pole_process1_sticky_abs(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x) { float y = x + coeffs->mA1u * (state->y_z1 - x); const float d = y - x; if (d * d <= coeffs->st2) @@ -322,7 +324,7 @@ static inline float bw_one_pole_process1_sticky_abs(const bw_one_pole_coeffs *re return y; } -static inline float bw_one_pole_process1_sticky_rel(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x) { +static inline float bw_one_pole_process1_sticky_rel(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x) { float y = x + coeffs->mA1u * (state->y_z1 - x); const float d = y - x; if (d * d <= coeffs->st2 * x * x) @@ -331,13 +333,13 @@ static inline float bw_one_pole_process1_sticky_rel(const bw_one_pole_coeffs *re return y; } -static inline float bw_one_pole_process1_asym(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x) { +static inline float bw_one_pole_process1_asym(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x) { const float y = x + (x >= state->y_z1 ? coeffs->mA1u : coeffs->mA1d) * (state->y_z1 - x); state->y_z1 = y; return y; } -static inline float bw_one_pole_process1_asym_sticky_abs(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x) { +static inline float bw_one_pole_process1_asym_sticky_abs(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x) { float y = x + (x >= state->y_z1 ? coeffs->mA1u : coeffs->mA1d) * (state->y_z1 - x); const float d = y - x; if (d * d <= coeffs->st2) @@ -346,7 +348,7 @@ static inline float bw_one_pole_process1_asym_sticky_abs(const bw_one_pole_coeff return y; } -static inline float bw_one_pole_process1_asym_sticky_rel(const bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, float x) { +static inline float bw_one_pole_process1_asym_sticky_rel(const bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, float x) { float y = x + (x >= state->y_z1 ? coeffs->mA1u : coeffs->mA1d) * (state->y_z1 - x); const float d = y - x; if (d * d <= coeffs->st2 * x * x) @@ -355,7 +357,7 @@ static inline float bw_one_pole_process1_asym_sticky_rel(const bw_one_pole_coeff return y; } -static inline void bw_one_pole_process(bw_one_pole_coeffs *restrict coeffs, bw_one_pole_state *restrict state, const float *x, float *y, int n_samples) { +static inline void bw_one_pole_process(bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_state *BW_RESTRICT state, const float *x, float *y, int n_samples) { bw_one_pole_update_coeffs_ctrl(coeffs); if (coeffs->mA1u != coeffs->mA1d) { @@ -388,52 +390,52 @@ static inline void bw_one_pole_process(bw_one_pole_coeffs *restrict coeffs, bw_o } } -static inline void bw_one_pole_set_init_val(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_init_val(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { coeffs->init_val = value; } -static inline void bw_one_pole_set_cutoff(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_cutoff(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { bw_one_pole_set_cutoff_up(coeffs, value); bw_one_pole_set_cutoff_down(coeffs, value); } -static inline void bw_one_pole_set_cutoff_up(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_cutoff_up(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { if (coeffs->cutoff_up != value) { coeffs->cutoff_up = value; coeffs->param_changed |= _BW_ONE_POLE_PARAM_CUTOFF_UP; } } -static inline void bw_one_pole_set_cutoff_down(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_cutoff_down(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { if (coeffs->cutoff_down != value) { coeffs->cutoff_down = value; coeffs->param_changed |= _BW_ONE_POLE_PARAM_CUTOFF_DOWN; } } -static inline void bw_one_pole_set_tau(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_tau(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { bw_one_pole_set_tau_up(coeffs, value); bw_one_pole_set_tau_down(coeffs, value); } -static inline void bw_one_pole_set_tau_up(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_tau_up(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { bw_one_pole_set_cutoff_up(coeffs, value < 1e-9f ? INFINITY : 0.1591549430918953f * bw_rcpf_2(value)); // tau < 1 ns is instantaneous for any practical purpose } -static inline void bw_one_pole_set_tau_down(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_tau_down(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { bw_one_pole_set_cutoff_down(coeffs, value < 1e-9f ? INFINITY : 0.1591549430918953f * bw_rcpf_2(value)); // as before } -static inline void bw_one_pole_set_sticky_thresh(bw_one_pole_coeffs *restrict coeffs, float value) { +static inline void bw_one_pole_set_sticky_thresh(bw_one_pole_coeffs *BW_RESTRICT coeffs, float value) { if (coeffs->sticky_thresh != value) { coeffs->sticky_thresh = value; coeffs->param_changed |= _BW_ONE_POLE_PARAM_STICKY_THRESH; } } -static inline void bw_one_pole_set_sticky_mode(bw_one_pole_coeffs *restrict coeffs, bw_one_pole_sticky_mode value) { +static inline void bw_one_pole_set_sticky_mode(bw_one_pole_coeffs *BW_RESTRICT coeffs, bw_one_pole_sticky_mode value) { coeffs->sticky_mode = value; } diff --git a/include/bw_svf.h b/include/bw_svf.h index e194a75..3b72d7c 100644 --- a/include/bw_svf.h +++ b/include/bw_svf.h @@ -48,42 +48,57 @@ extern "C" { #endif -/*! api {{{ - * #### bw_svf - * ```>>> */ -typedef struct _bw_svf bw_svf; -/*! <<<``` - * Instance object. - * >>> */ +#include -/*! ... +/*! api {{{ + * #### bw_svf_coeffs + * ```>>> */ +typedef struct _bw_svf_coeffs bw_svf_coeffs; +/*! <<<``` + * Coefficients. + * + * ### bw_svf_state + * ```>>> */ +typedef struct _bw_svf_state bw_svf_state; +/*! <<<``` + * State. + * * #### bw_svf_init() * ```>>> */ -void bw_svf_init(bw_svf *instance); +static inline void bw_svf_init(bw_svf_coeffs *BW_RESTRICT coeffs); /*! <<<``` - * Initializes the `instance` object. - * >>> */ - -/*! ... + * Initializes `coeffs`. + * * #### bw_svf_set_sample_rate() * ```>>> */ -void bw_svf_set_sample_rate(bw_svf *instance, float sample_rate); +static inline void bw_svf_set_sample_rate(bw_svf_coeffs *BW_RESTRICT coeffs, float sample_rate); /*! <<<``` - * Sets the `sample_rate` (Hz) value for the given `instance`. + * Sets the `sample_rate` (Hz) value for the given `coeffs`. + * + * #### bw_svf_reset_state() + * ```>>> */ +static inline void bw_svf_reset_state(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state); +/*! <<<``` + * Resets the given `state` to the initial state using the given `coeffs`. * >>> */ -/*! ... - * #### bw_svf_reset() - * ```>>> */ -void bw_svf_reset(bw_svf *instance); -/*! <<<``` - * Resets the given `instance` to its initial state. - * >>> */ +static inline void bw_svf_reset_coeffs(bw_svf_coeffs *BW_RESTRICT coeffs); + +static inline void bw_svf_update_coeffs_ctrl(bw_svf_coeffs *BW_RESTRICT coeffs); +static inline void bw_svf_update_coeffs_audio(bw_svf_coeffs *BW_RESTRICT coeffs); + +static inline float bw_svf_process1_lp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x); +static inline float bw_svf_process1_bp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x); +static inline float bw_svf_process1_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x); +static inline void bw_svf_process1_lp_bp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_lp, float *y_bp); +static inline void bw_svf_process1_lp_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_lp, float *y_hp); +static inline void bw_svf_process1_bp_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_bp, float *y_hp); +static inline void bw_svf_process1_lp_bp_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_lp, float *y_bp, float *y_hp); /*! ... * #### bw_svf_process() * ```>>> */ -void bw_svf_process(bw_svf *instance, const float *x, float* y_lp, float *y_bp, float *y_hp, int n_samples); +static inline void bw_svf_process(bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, const float *x, float *y_lp, float *y_bp, float *y_hp, int n_samples); /*! <<<``` * Lets the given `instance` process `n_samples` samples from the input * buffer `x` and fills the corresponding `n_samples` samples in the output @@ -94,7 +109,7 @@ void bw_svf_process(bw_svf *instance, const float *x, float* y_lp, float *y_bp, /*! ... * #### bw_svf_set_cutoff() * ```>>> */ -void bw_svf_set_cutoff(bw_svf *instance, float value); +static inline void bw_svf_set_cutoff(bw_svf_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the cutoff frequency to the given `value` (Hz) for the given * `instance`. @@ -105,7 +120,7 @@ void bw_svf_set_cutoff(bw_svf *instance, float value); /*! ... * #### bw_svf_set_Q() * ```>>> */ -void bw_svf_set_Q(bw_svf *instance, float value); +static inline void bw_svf_set_Q(bw_svf_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the quality factor to the given `value` (Hz) for the given * `instance`. @@ -113,12 +128,14 @@ void bw_svf_set_Q(bw_svf *instance, float value); * Default value: `0.5f`. * }}} */ +/*** Implementation ***/ + +/* WARNING: This part of the file is not part of the public API. Its content may + * change at any time in future versions. Please, do not use it directly. */ + #include -/* WARNING: the internal definition of this struct is not part of the public - * API. Its content may change at any time in future versions. Please, do not - * access its members directly. */ -struct _bw_svf { +struct _bw_svf_coeffs { // Sub-components bw_one_pole_coeffs smooth_cutoff_coeffs; bw_one_pole_state smooth_cutoff_state; @@ -126,28 +143,201 @@ struct _bw_svf { bw_one_pole_state smooth_Q_state; // Coefficients - float t_k; + float t_k; - float t; - float k; - float hp_hp_z1; - float hp_bp_z1; - float hp_x; + float t; + float k; + float hp_hp_z1; + float hp_bp_z1; + float hp_x; // Parameters - float cutoff; - float Q; + float cutoff; + float Q; - float cutoff_cur; - float Q_cur; - - // State - char first_run; - float hp_z1; - float lp_z1; - float bp_z1; + float cutoff_cur; + float Q_cur; }; +struct _bw_svf_state { + // State + float hp_z1; + float lp_z1; + float bp_z1; +}; + +static inline void bw_svf_init(bw_svf_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_init(&coeffs->smooth_cutoff_coeffs); + bw_one_pole_set_tau(&coeffs->smooth_cutoff_coeffs, 0.05f); + bw_one_pole_set_sticky_thresh(&coeffs->smooth_cutoff_coeffs, 1e-3f); + bw_one_pole_init(&coeffs->smooth_Q_coeffs); + bw_one_pole_set_tau(&coeffs->smooth_Q_coeffs, 0.05f); + bw_one_pole_set_sticky_thresh(&coeffs->smooth_Q_coeffs, 1e-3f); + coeffs->cutoff = 1e3f; + coeffs->Q = 0.5f; +} + +static inline void bw_svf_set_sample_rate(bw_svf_coeffs *BW_RESTRICT coeffs, float sample_rate) { + bw_one_pole_set_sample_rate(&coeffs->smooth_cutoff_coeffs, sample_rate); + bw_one_pole_set_sample_rate(&coeffs->smooth_Q_coeffs, sample_rate); + coeffs->t_k = 3.141592653589793f / sample_rate; +} + +static inline void _bw_svf_do_update_coeffs(bw_svf_coeffs *BW_RESTRICT coeffs, char force) { + const char cutoff_changed = force || coeffs->cutoff != coeffs->cutoff_cur; + const char Q_changed = force || coeffs->Q != coeffs->Q_cur; + if (cutoff_changed || Q_changed) { + if (cutoff_changed) { + coeffs->cutoff_cur = bw_one_pole_process1_sticky_rel(&coeffs->smooth_cutoff_coeffs, &coeffs->smooth_cutoff_state, coeffs->cutoff); + coeffs->t = bw_tanf_3(coeffs->t_k * coeffs->cutoff_cur); + } + if (Q_changed) { + coeffs->Q_cur = bw_one_pole_process1_sticky_abs(&coeffs->smooth_Q_coeffs, &coeffs->smooth_Q_state, coeffs->Q); + coeffs->k = bw_rcpf_2(coeffs->Q_cur); + } + const float kpt = coeffs->k + coeffs->t; + coeffs->hp_hp_z1 = coeffs->t * kpt; + coeffs->hp_bp_z1 = coeffs->t + kpt; + coeffs->hp_x = bw_rcpf_2(1.f + coeffs->hp_hp_z1); + } +} + +static inline void bw_svf_reset_coeffs(bw_svf_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_set_init_val(&coeffs->smooth_cutoff_coeffs, coeffs->cutoff); + bw_one_pole_reset_coeffs(&coeffs->smooth_cutoff_coeffs); + bw_one_pole_reset_state(&coeffs->smooth_cutoff_coeffs, &coeffs->smooth_cutoff_state); + bw_one_pole_set_init_val(&coeffs->smooth_Q_coeffs, coeffs->Q); + bw_one_pole_reset_coeffs(&coeffs->smooth_Q_coeffs); + bw_one_pole_reset_state(&coeffs->smooth_Q_coeffs, &coeffs->smooth_Q_state); + _bw_svf_do_update_coeffs(coeffs, 1); +} + +static inline void bw_svf_reset_state(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state) { + state->hp_z1 = 0.f; + state->lp_z1 = 0.f; + state->bp_z1 = 0.f; +} + +static inline void bw_svf_update_coeffs_ctrl(bw_svf_coeffs *BW_RESTRICT coeffs) { +} + +static inline void bw_svf_update_coeffs_audio(bw_svf_coeffs *BW_RESTRICT coeffs) { + _bw_svf_do_update_coeffs(coeffs, 0); +} + +static inline float bw_svf_process1_lp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x) { + float lp, bp, hp; + bw_svf_process1_lp_bp_hp(coeffs, state, x, &lp, &bp, &hp); + return lp; +} + +static inline float bw_svf_process1_bp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x) { + float lp, bp, hp; + bw_svf_process1_lp_bp_hp(coeffs, state, x, &lp, &bp, &hp); + return bp; +} + +static inline float bw_svf_process1_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x) { + float lp, bp, hp; + bw_svf_process1_lp_bp_hp(coeffs, state, x, &lp, &bp, &hp); + return hp; +} + +static inline void bw_svf_process1_lp_bp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_lp, float *y_bp) { + float lp, bp, hp; + bw_svf_process1_lp_bp_hp(coeffs, state, x, &lp, &bp, &hp); + *y_lp = lp; + *y_bp = bp; +} + +static inline void bw_svf_process1_lp_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_lp, float *y_hp) { + float lp, bp, hp; + bw_svf_process1_lp_bp_hp(coeffs, state, x, &lp, &bp, &hp); + *y_lp = lp; + *y_hp = hp; +} + +static inline void bw_svf_process1_bp_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_bp, float *y_hp) { + float lp, bp, hp; + bw_svf_process1_lp_bp_hp(coeffs, state, x, &lp, &bp, &hp); + *y_bp = bp; + *y_hp = hp; +} + +static inline void bw_svf_process1_lp_bp_hp(const bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, float x, float *y_lp, float *y_bp, float *y_hp) { + *y_hp = coeffs->hp_x * (x - state->lp_z1 + coeffs->hp_bp_z1 * state->bp_z1 - coeffs->hp_hp_z1 * state->hp_z1); + *y_bp = state->bp_z1 - coeffs->t * (*y_hp + state->hp_z1); + *y_lp = state->lp_z1 - coeffs->t * (*y_bp + state->bp_z1); + + state->hp_z1 = *y_hp; + state->lp_z1 = *y_lp; + state->bp_z1 = *y_bp; +} + +static inline void bw_svf_process(bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_state *BW_RESTRICT state, const float *x, float *y_lp, float *y_bp, float *y_hp, int n_samples) { + if (y_lp != NULL) { + if (y_bp != NULL) { + if (y_hp != NULL) { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + bw_svf_process1_lp_bp_hp(coeffs, state, x[i], y_lp + i, y_bp + i, y_hp + i); + } + } else { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + bw_svf_process1_lp_bp(coeffs, state, x[i], y_lp + i, y_bp + i); + } + } + } else { + if (y_hp != NULL) { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + bw_svf_process1_lp_hp(coeffs, state, x[i], y_lp + i, y_hp + i); + } + } else { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + y_lp[i] = bw_svf_process1_lp(coeffs, state, x[i]); + } + } + } + } else { + if (y_bp != NULL) { + if (y_hp != NULL) { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + bw_svf_process1_bp_hp(coeffs, state, x[i], y_bp + i, y_hp + i); + } + } else { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + y_bp[i] = bw_svf_process1_bp(coeffs, state, x[i]); + } + } + } else { + if (y_hp != NULL) { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + y_hp[i] = bw_svf_process1_hp(coeffs, state, x[i]); + } + } else { + for (int i = 0; i < n_samples; i++) { + bw_svf_update_coeffs_audio(coeffs); + const float v = bw_svf_process1_lp(coeffs, state, x[i]); + } + } + } + } +} + +static inline void bw_svf_set_cutoff(bw_svf_coeffs *BW_RESTRICT coeffs, float value) { + coeffs->cutoff = value; +} + +static inline void bw_svf_set_Q(bw_svf_coeffs *BW_RESTRICT coeffs, float value) { + coeffs->Q = value; +} + #ifdef __cplusplus } #endif diff --git a/src/bw_svf.c b/src/bw_svf.c deleted file mode 100644 index ebe8ad1..0000000 --- a/src/bw_svf.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Brickworks - * - * Copyright (C) 2022 Orastron Srl unipersonale - * - * Brickworks is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * Brickworks is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * - * File author: Stefano D'Angelo - */ - -#include - -#include - -void bw_svf_init(bw_svf *instance) { - bw_one_pole_init(&instance->smooth_cutoff_coeffs); - bw_one_pole_set_tau(&instance->smooth_cutoff_coeffs, 0.05f); - bw_one_pole_set_sticky_thresh(&instance->smooth_cutoff_coeffs, 1e-3f); - bw_one_pole_init(&instance->smooth_Q_coeffs); - bw_one_pole_set_tau(&instance->smooth_Q_coeffs, 0.05f); - bw_one_pole_set_sticky_thresh(&instance->smooth_Q_coeffs, 1e-3f); - instance->cutoff = 1e3f; - instance->Q = 0.5f; -} - -void bw_svf_set_sample_rate(bw_svf *instance, float sample_rate) { - bw_one_pole_set_sample_rate(&instance->smooth_cutoff_coeffs, sample_rate); - bw_one_pole_set_sample_rate(&instance->smooth_Q_coeffs, sample_rate); - instance->t_k = 3.141592653589793f / sample_rate; -} - -void bw_svf_reset(bw_svf *instance) { - instance->first_run = 1; -} - -#define PARAM_CUTOFF 1 -#define PARAM_Q (1<<1) - -static inline void update_coefficients(bw_svf *instance) { - bw_one_pole_update_coeffs_audio(&instance->smooth_cutoff_coeffs); - bw_one_pole_update_coeffs_audio(&instance->smooth_Q_coeffs); - const char cutoff_changed = instance->cutoff != instance->cutoff_cur || instance->first_run; - const char Q_changed = instance->Q != instance->Q_cur || instance->first_run; - if (cutoff_changed || Q_changed) { - if (cutoff_changed) { - instance->cutoff_cur = bw_one_pole_process1_sticky_rel(&instance->smooth_cutoff_coeffs, &instance->smooth_cutoff_state, instance->cutoff); - instance->t = bw_tanf_3(instance->t_k * instance->cutoff_cur); - } - if (Q_changed) { - instance->Q_cur = bw_one_pole_process1_sticky_abs(&instance->smooth_Q_coeffs, &instance->smooth_Q_state, instance->Q); - instance->k = bw_rcpf_2(instance->Q_cur); - } - const float kpt = instance->k + instance->t; - instance->hp_hp_z1 = instance->t * kpt; - instance->hp_bp_z1 = instance->t + kpt; - instance->hp_x = bw_rcpf_2(1.f + instance->hp_hp_z1); - } -} - -void bw_svf_process(bw_svf *instance, const float *x, float *y_lp, float *y_bp, float *y_hp, int n_samples) { - if (instance->first_run) { - bw_one_pole_set_init_val(&instance->smooth_cutoff_coeffs, instance->cutoff); - bw_one_pole_reset_coeffs(&instance->smooth_cutoff_coeffs); - bw_one_pole_reset_state(&instance->smooth_cutoff_coeffs, &instance->smooth_cutoff_state); - bw_one_pole_set_init_val(&instance->smooth_Q_coeffs, instance->Q); - bw_one_pole_reset_coeffs(&instance->smooth_Q_coeffs); - bw_one_pole_reset_state(&instance->smooth_Q_coeffs, &instance->smooth_Q_state); - update_coefficients(instance); - instance->hp_z1 = 0.f; - instance->lp_z1 = 0.f; - instance->bp_z1 = 0.f; - instance->first_run = 0; - } - - bw_one_pole_update_coeffs_ctrl(&instance->smooth_cutoff_coeffs); - bw_one_pole_update_coeffs_ctrl(&instance->smooth_Q_coeffs); - - for (int i = 0; i < n_samples; i++) { - update_coefficients(instance); - - const float hp = instance->hp_x * (x[i] - instance->lp_z1 + instance->hp_bp_z1 * instance->bp_z1 - instance->hp_hp_z1 * instance->hp_z1); - const float bp = instance->bp_z1 - instance->t * (hp + instance->hp_z1); - const float lp = instance->lp_z1 - instance->t * (bp + instance->bp_z1); - instance->hp_z1 = hp; - instance->lp_z1 = lp; - instance->bp_z1 = bp; - if (y_lp) - y_lp[i] = lp; - if (y_bp) - y_bp[i] = bp; - if (y_hp) - y_hp[i] = hp; - } -} - -void bw_svf_set_cutoff(bw_svf *instance, float value) { - instance->cutoff = value; -} - -void bw_svf_set_Q(bw_svf *instance, float value) { - instance->Q = value; -}