diff --git a/examples/fx_svf/src/bw_example_fx_svf.c b/examples/fx_svf/src/bw_example_fx_svf.c index 538f5ad..65809af 100644 --- a/examples/fx_svf/src/bw_example_fx_svf.c +++ b/examples/fx_svf/src/bw_example_fx_svf.c @@ -66,6 +66,7 @@ void bw_example_fx_svf_process(bw_example_fx_svf instance, const float** x, floa } void bw_example_fx_svf_set_parameter(bw_example_fx_svf instance, int index, float value) { + instance->params[index] = value; switch (index) { case p_cutoff: bw_svf_set_cutoff(&instance->svf_coeffs, (20e3f - 20.f) * value * value * value + 20.f); diff --git a/examples/fx_wah/src/bw_example_fx_wah.c b/examples/fx_wah/src/bw_example_fx_wah.c index edfed7f..19fe16a 100644 --- a/examples/fx_wah/src/bw_example_fx_wah.c +++ b/examples/fx_wah/src/bw_example_fx_wah.c @@ -66,6 +66,7 @@ void bw_example_fx_wah_process(bw_example_fx_wah instance, const float** x, floa } void bw_example_fx_wah_set_parameter(bw_example_fx_wah instance, int index, float value) { + instance->params[index] = value; bw_wah_set_wah(&instance->wah_coeffs, value); } diff --git a/examples/synth/src/bw_example_synth.c b/examples/synth/src/bw_example_synth.c index beef66e..2c0a4dd 100644 --- a/examples/synth/src/bw_example_synth.c +++ b/examples/synth/src/bw_example_synth.c @@ -21,12 +21,20 @@ #include #include +#ifdef __WASM__ +# include "walloc.h" +#else +# include +#endif + +/* #include #include #include #include #include #include +*/ enum { p_volume, @@ -46,13 +54,16 @@ enum { struct _bw_example_synth { // Sub-components - bw_phase_gen phase_gen; + bw_phase_gen_coeffs phase_gen_coeffs; + bw_phase_gen_state phase_gen_state; + /* bw_osc_pulse osc_pulse; bw_osc_filt osc_filt; bw_svf svf; bw_env_gen env_gen; bw_vol vol; bw_env_follow env_follow; + */ // Parameters float params[p_n]; @@ -66,11 +77,12 @@ struct _bw_example_synth { }; bw_example_synth bw_example_synth_new() { - bw_example_synth instance = (bw_example_synth)BW_MALLOC(sizeof(struct _bw_example_synth)); + bw_example_synth instance = (bw_example_synth)malloc(sizeof(struct _bw_example_synth)); if (instance == NULL) return NULL; - bw_phase_gen_init(&instance->phase_gen); + bw_phase_gen_init(&instance->phase_gen_coeffs); + /* bw_osc_pulse_init(&instance->osc_pulse); bw_osc_filt_init(&instance->osc_filt); bw_svf_init(&instance->svf); @@ -80,43 +92,52 @@ bw_example_synth bw_example_synth_new() { bw_osc_pulse_set_antialiasing(&instance->osc_pulse, 1); bw_one_pole_set_cutoff_down(bw_env_follow_get_one_pole(&instance->env_follow), 1.f); + */ return instance; } void bw_example_synth_free(bw_example_synth instance) { - BW_FREE(instance); + free(instance); } void bw_example_synth_set_sample_rate(bw_example_synth instance, float sample_rate) { - bw_phase_gen_set_sample_rate(&instance->phase_gen, sample_rate); + bw_phase_gen_set_sample_rate(&instance->phase_gen_coeffs, sample_rate); + /* bw_osc_pulse_set_sample_rate(&instance->osc_pulse, sample_rate); bw_svf_set_sample_rate(&instance->svf, sample_rate); bw_env_gen_set_sample_rate(&instance->env_gen, sample_rate); bw_vol_set_sample_rate(&instance->vol, sample_rate); bw_env_follow_set_sample_rate(&instance->env_follow, sample_rate); + */ } void bw_example_synth_reset(bw_example_synth instance) { - bw_phase_gen_reset(&instance->phase_gen); + bw_phase_gen_reset_coeffs(&instance->phase_gen_coeffs); + bw_phase_gen_reset_state(&instance->phase_gen_coeffs, &instance->phase_gen_state); + /* bw_osc_pulse_reset(&instance->osc_pulse); bw_osc_filt_reset(&instance->osc_filt); bw_svf_reset(&instance->svf); bw_env_gen_reset(&instance->env_gen); bw_vol_reset(&instance->vol); bw_env_follow_reset(&instance->env_follow); + */ instance->note = -1; } void bw_example_synth_process(bw_example_synth instance, const float** x, float** y, int n_samples) { // TODO: I was too lazy to keep track of master tune and note and only update when needed, could be improved if (instance->note != -1) { - bw_phase_gen_set_frequency(&instance->phase_gen, + bw_phase_gen_set_frequency(&instance->phase_gen_coeffs, 440.f * bw_pow2f_3(8.333333333333333e-2f * ((instance->note - 69) + 2.f * instance->params[p_master_tune] - 1.f))); - bw_env_gen_set_gate(&instance->env_gen, 1); + //bw_env_gen_set_gate(&instance->env_gen, 1); } else - bw_env_gen_set_gate(&instance->env_gen, 0); + ; + //bw_env_gen_set_gate(&instance->env_gen, 0); + bw_phase_gen_process(&instance->phase_gen_coeffs, &instance->phase_gen_state, NULL, y[0], instance->buf, n_samples); + /* for (int i = 0; i < n_samples; i += BUFFER_SIZE) { float *out = y[0] + i; const uint32_t n = bw_minu32(n_samples - i, BUFFER_SIZE); @@ -131,19 +152,22 @@ void bw_example_synth_process(bw_example_synth instance, const float** x, float* bw_env_follow_process(&instance->env_follow, out, instance->buf, n); instance->level = instance->buf[i + n - 1]; } + */ + instance->level = 0.f; } void bw_example_synth_set_parameter(bw_example_synth instance, int index, float value) { + instance->params[index] = value; switch (index) { + /* case p_volume: bw_vol_set_volume(&instance->vol, value); break; - case p_master_tune: - instance->params[p_master_tune] = value; - break; + */ case p_portamento: - bw_phase_gen_set_portamento_tau(&instance->phase_gen, value); + bw_phase_gen_set_portamento_tau(&instance->phase_gen_coeffs, value); break; + /* case p_pulse_width: bw_osc_pulse_set_pulse_width(&instance->osc_pulse, value); break; @@ -165,6 +189,7 @@ void bw_example_synth_set_parameter(bw_example_synth instance, int index, float case p_release: bw_env_gen_set_release(&instance->env_gen, value); break; + */ } } diff --git a/examples/synth/web/Makefile b/examples/synth/web/Makefile index 7a5c926..79e9ec9 100644 --- a/examples/synth/web/Makefile +++ b/examples/synth/web/Makefile @@ -1,5 +1,6 @@ CC=clang CFLAGS= \ + -D__WASM__ \ -I${ROOT_DIR}/../src \ -I${ROOT_DIR}/../../common/web \ -I${ROOT_DIR}/../../../include \ @@ -27,14 +28,6 @@ LDFLAGS= \ ROOT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) SOURCES= \ - ${ROOT_DIR}/../../../src/bw_phase_gen.c \ - ${ROOT_DIR}/../../../src/bw_osc_pulse.c \ - ${ROOT_DIR}/../../../src/bw_osc_filt.c \ - ${ROOT_DIR}/../../../src/bw_svf.c \ - ${ROOT_DIR}/../../../src/bw_env_gen.c \ - ${ROOT_DIR}/../../../src/bw_vol.c \ - ${ROOT_DIR}/../../../src/bw_env_follow.c \ - ${ROOT_DIR}/../../../src/bw_one_pole.c \ ${ROOT_DIR}/../src/bw_example_synth.c \ ${ROOT_DIR}/../../common/web/walloc.c \ ${ROOT_DIR}/../../common/web/wrapper.c diff --git a/include/bw_one_pole.h b/include/bw_one_pole.h index edddf0e..45337c7 100644 --- a/include/bw_one_pole.h +++ b/include/bw_one_pole.h @@ -242,6 +242,8 @@ static inline void bw_one_pole_set_sticky_mode(bw_one_pole_coeffs *BW_RESTRICT c * Sets the current distance metric for sticky behavior. * }}} */ +static inline float bw_one_pole_get_y_z1(const bw_one_pole_state *BW_RESTRICT state); + /*** Implementation ***/ /* WARNING: This part of the file is not part of the public API. Its content may @@ -439,6 +441,10 @@ static inline void bw_one_pole_set_sticky_mode(bw_one_pole_coeffs *BW_RESTRICT c coeffs->sticky_mode = value; } +static inline float bw_one_pole_get_y_z1(const bw_one_pole_state *BW_RESTRICT state) { + return state->y_z1; +} + #ifdef __cplusplus } #endif diff --git a/include/bw_phase_gen.h b/include/bw_phase_gen.h index 35bc45e..077186a 100644 --- a/include/bw_phase_gen.h +++ b/include/bw_phase_gen.h @@ -20,7 +20,7 @@ /*! * module_type {{{ dsp }}} * version {{{ 0.2.0 }}} - * requires {{{ bw_config bw_common bw_math }}} + * requires {{{ bw_config bw_common bw_math bw_one_pole }}} * description {{{ * Phase generator with portamento and exponential frequency modulation. * @@ -30,7 +30,7 @@ *
    *
  • Version 0.2.0: *
      - *
    • Refactored API to avoid dynamic memory allocation.
    • + *
    • Refactored API.
    • *
    *
  • *
  • Version 0.1.0: @@ -49,42 +49,52 @@ extern "C" { #endif -/*! api {{{ - * #### bw_phase_gen - * ```>>> */ -typedef struct _bw_phase_gen bw_phase_gen; -/*! <<<``` - * Instance object. - * >>> */ +#include -/*! ... +/*! api {{{ + * #### bw_phase_gen_coeffs + * ```>>> */ +typedef struct _bw_phase_gen_coeffs bw_phase_gen_coeffs; +/*! <<<``` + * Coefficients. + * + * ### bw_phase_gen_state + * ```>>> */ +typedef struct _bw_phase_gen_state bw_phase_gen_state; +/*! <<<``` + * State. + * * #### bw_phase_gen_init() * ```>>> */ -void bw_phase_gen_init(bw_phase_gen *instance); +static inline void bw_phase_gen_init(bw_phase_gen_coeffs *BW_RESTRICT coeffs); /*! <<<``` - * Initializes the `instance` object. - * >>> */ - -/*! ... + * Initializes `coeffs`. + * * #### bw_phase_gen_set_sample_rate() * ```>>> */ -void bw_phase_gen_set_sample_rate(bw_phase_gen *instance, float sample_rate); +static inline void bw_phase_gen_set_sample_rate(bw_phase_gen_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_phase_gen_reset() * ```>>> */ -void bw_phase_gen_reset(bw_phase_gen *instance); +static inline void bw_phase_gen_reset_state(const bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state); /*! <<<``` - * Resets the given `instance` to its initial state. + * Resets the given `state` to the initial state using the given `coeffs`. * >>> */ +static inline void bw_phase_gen_reset_coeffs(bw_phase_gen_coeffs *BW_RESTRICT coeffs); + +static inline void bw_phase_gen_update_coeffs_ctrl(bw_phase_gen_coeffs *BW_RESTRICT coeffs); +static inline void bw_phase_gen_update_coeffs_audio(bw_phase_gen_coeffs *BW_RESTRICT coeffs); + +static inline void bw_phase_gen_process1(const bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state, float *y, float *y_phase_inc); +static inline void bw_phase_gen_process1_mod(const bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state, float x_mod, float *y, float *y_phase_inc); + /*! ... * #### bw_phase_gen_process() * ```>>> */ -void bw_phase_gen_process(bw_phase_gen *instance, const float *x_mod, float* y, float *y_phase_inc, int n_samples); +static inline void bw_phase_gen_process(bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state, const float *x_mod, float* y, float *y_phase_inc, int n_samples); /*! <<<``` * Lets the given `instance` generate `n_samples` samples and puts them in * the output buffer `y`. @@ -98,7 +108,7 @@ void bw_phase_gen_process(bw_phase_gen *instance, const float *x_mod, float* y, /*! ... * #### bw_phase_gen_set_frequency() * ```>>> */ -void bw_phase_gen_set_frequency(bw_phase_gen *instance, float value); +static inline void bw_phase_gen_set_frequency(bw_phase_gen_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the base frequency to `value` (Hz) for the given `instance`. * @@ -108,34 +118,131 @@ void bw_phase_gen_set_frequency(bw_phase_gen *instance, float value); /*! ... * #### bw_phase_gen_set_portamento_tau() * ```>>> */ -void bw_phase_gen_set_portamento_tau(bw_phase_gen *instance, float value); +static inline void bw_phase_gen_set_portamento_tau(bw_phase_gen_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` * Sets the portamento time constant `value` (s) for the given `instance`. * * Default value: `0.f`. * }}} */ -/* 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_phase_gen { - // Coefficients - float T; +/*** Implementation ***/ - float portamento_target; - float portamento_mA1; +/* 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 +#include + +struct _bw_phase_gen_coeffs { + // Sub-components + bw_one_pole_coeffs portamento_coeffs; + bw_one_pole_state portamento_state; + + // Coefficients + float T; + + float portamento_target; // Parameters - float frequency; - float portamento_tau; - int param_changed; - - // State - char first_run; - float phase; - float portamento_z1; + float frequency; + float frequency_prev; }; +struct _bw_phase_gen_state { + // State + float phase; +}; + +static inline void bw_phase_gen_init(bw_phase_gen_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_init(&coeffs->portamento_coeffs); + coeffs->frequency = 1.f; +} + +static inline void bw_phase_gen_set_sample_rate(bw_phase_gen_coeffs *BW_RESTRICT coeffs, float sample_rate) { + bw_one_pole_set_sample_rate(&coeffs->portamento_coeffs, sample_rate); + coeffs->T = 1.f / sample_rate; +} + +static inline void _bw_phase_gen_do_update_coeffs_ctrl(bw_phase_gen_coeffs *BW_RESTRICT coeffs, char force) { + bw_one_pole_update_coeffs_ctrl(&coeffs->portamento_coeffs); + if (force || coeffs->frequency != coeffs->frequency_prev) { + coeffs->portamento_target = coeffs->T * coeffs->frequency; + coeffs->frequency_prev = coeffs->frequency; + } +} + +static inline void bw_phase_gen_reset_coeffs(bw_phase_gen_coeffs *BW_RESTRICT coeffs) { + _bw_phase_gen_do_update_coeffs_ctrl(coeffs, 1); + bw_one_pole_set_init_val(&coeffs->portamento_coeffs, coeffs->portamento_target); + bw_one_pole_reset_coeffs(&coeffs->portamento_coeffs); + bw_one_pole_reset_state(&coeffs->portamento_coeffs, &coeffs->portamento_state); +} + +static inline void bw_phase_gen_reset_state(const bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state) { + state->phase = 0.f; +} + +static inline void bw_phase_gen_update_coeffs_ctrl(bw_phase_gen_coeffs *BW_RESTRICT coeffs) { + _bw_phase_gen_do_update_coeffs_ctrl(coeffs, 0); +} + +static inline void bw_phase_gen_update_coeffs_audio(bw_phase_gen_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_process1(&coeffs->portamento_coeffs, &coeffs->portamento_state, coeffs->portamento_target); +} + +static inline float _bw_phase_gen_update_phase(bw_phase_gen_state *BW_RESTRICT state, float phase_inc) { + state->phase += phase_inc; + state->phase -= bw_floorf(state->phase); + return state->phase; +} + +static inline void bw_phase_gen_process1(const bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state, float *y, float *y_phase_inc) { + *y_phase_inc = bw_one_pole_get_y_z1(&coeffs->portamento_state); + *y = _bw_phase_gen_update_phase(state, *y_phase_inc); +} + +static inline void bw_phase_gen_process1_mod(const bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state, float x_mod, float *y, float *y_phase_inc) { + *y_phase_inc = bw_one_pole_get_y_z1(&coeffs->portamento_state) * bw_pow2f_3(x_mod); + *y = _bw_phase_gen_update_phase(state, *y_phase_inc); +} + +static inline void bw_phase_gen_process(bw_phase_gen_coeffs *BW_RESTRICT coeffs, bw_phase_gen_state *BW_RESTRICT state, const float *x_mod, float* y, float *y_phase_inc, int n_samples) { + bw_phase_gen_update_coeffs_ctrl(coeffs); + if (x_mod != NULL) { + if (y_phase_inc != NULL) + for (int i = 0; i < n_samples; i++) { + bw_phase_gen_update_coeffs_audio(coeffs); + bw_phase_gen_process1_mod(coeffs, state, x_mod[i], y + i, y_phase_inc + i); + } + else + for (int i = 0; i < n_samples; i++) { + bw_phase_gen_update_coeffs_audio(coeffs); + float v_phase_inc; + bw_phase_gen_process1_mod(coeffs, state, x_mod[i], y + i, &v_phase_inc); + } + } else { + if (y_phase_inc != NULL) + for (int i = 0; i < n_samples; i++) { + bw_phase_gen_update_coeffs_audio(coeffs); + bw_phase_gen_process1(coeffs, state, y + i, y_phase_inc + i); + } + else + for (int i = 0; i < n_samples; i++) { + bw_phase_gen_update_coeffs_audio(coeffs); + float v_phase_inc; + bw_phase_gen_process1(coeffs, state, y + i, &v_phase_inc); + } + } +} + +static inline void bw_phase_gen_set_frequency(bw_phase_gen_coeffs *BW_RESTRICT coeffs, float value) { + coeffs->frequency = value; +} + +static inline void bw_phase_gen_set_portamento_tau(bw_phase_gen_coeffs *BW_RESTRICT coeffs, float value) { + bw_one_pole_set_tau(&coeffs->portamento_coeffs, value); +} + #ifdef __cplusplus } #endif diff --git a/include/bw_svf.h b/include/bw_svf.h index 3b72d7c..1be8c2d 100644 --- a/include/bw_svf.h +++ b/include/bw_svf.h @@ -87,13 +87,7 @@ 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); +static inline void bw_svf_process1(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() @@ -154,9 +148,6 @@ struct _bw_svf_coeffs { // Parameters float cutoff; float Q; - - float cutoff_cur; - float Q_cur; }; struct _bw_svf_state { @@ -184,16 +175,18 @@ static inline void bw_svf_set_sample_rate(bw_svf_coeffs *BW_RESTRICT coeffs, flo } 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; + float cutoff_cur = bw_one_pole_get_y_z1(&coeffs->smooth_cutoff_state); + float Q_cur = bw_one_pole_get_y_z1(&coeffs->smooth_Q_state); + const char cutoff_changed = force || coeffs->cutoff != cutoff_cur; + const char Q_changed = force || coeffs->Q != 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); + 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 * 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); + Q_cur = bw_one_pole_process1_sticky_abs(&coeffs->smooth_Q_coeffs, &coeffs->smooth_Q_state, coeffs->Q); + coeffs->k = bw_rcpf_2(Q_cur); } const float kpt = coeffs->k + coeffs->t; coeffs->hp_hp_z1 = coeffs->t * kpt; @@ -225,46 +218,7 @@ 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) { +static inline void bw_svf_process1(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); @@ -280,24 +234,27 @@ static inline void bw_svf_process(bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_stat 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); + bw_svf_process1(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); + float v_lp; + bw_svf_process1(coeffs, state, x[i], &v_lp, y_bp + i, y_hp + 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); + float v_bp; + bw_svf_process1(coeffs, state, x[i], y_lp + i, &v_bp, 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]); + float v_bp, v_hp; + bw_svf_process1(coeffs, state, x[i], y_lp + i, &v_bp, &v_hp); } } } @@ -306,24 +263,28 @@ static inline void bw_svf_process(bw_svf_coeffs *BW_RESTRICT coeffs, bw_svf_stat 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); + float v_lp; + bw_svf_process1(coeffs, state, x[i], &v_lp, 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]); + float v_lp, v_hp; + bw_svf_process1(coeffs, state, x[i], &v_lp, y_bp + i, &v_hp); } } } 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]); + float v_lp, v_bp; + bw_svf_process1(coeffs, state, x[i], &v_lp, &v_bp, y_hp + 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]); + float v_lp, v_bp, v_hp; + bw_svf_process1(coeffs, state, x[i], &v_lp, &v_bp, &v_hp); } } } diff --git a/include/bw_wah.h b/include/bw_wah.h index 2bb63a7..95de5e7 100644 --- a/include/bw_wah.h +++ b/include/bw_wah.h @@ -150,7 +150,9 @@ static inline void bw_wah_update_coeffs_audio(bw_wah_coeffs *BW_RESTRICT coeffs) } static inline float bw_wah_process1(const bw_wah_coeffs *BW_RESTRICT coeffs, bw_wah_state *BW_RESTRICT state, float x) { - return bw_svf_process1_bp(&coeffs->svf_coeffs, &state->svf_state, x); + float v_lp, v_hp, v_bp; + bw_svf_process1(&coeffs->svf_coeffs, &state->svf_state, x, &v_lp, &v_bp, &v_hp); + return v_lp; } static inline void bw_wah_process(bw_wah_coeffs *BW_RESTRICT coeffs, bw_wah_state *BW_RESTRICT state, const float *x, float *y, int n_samples) { diff --git a/src/bw_phase_gen.c b/src/bw_phase_gen.c deleted file mode 100644 index 2c6a808..0000000 --- a/src/bw_phase_gen.c +++ /dev/null @@ -1,95 +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_phase_gen_init(bw_phase_gen *instance) { - instance->frequency = 1.f; - instance->portamento_tau = 0.f; -} - -void bw_phase_gen_set_sample_rate(bw_phase_gen *instance, float sample_rate) { - instance->T = 1.f / sample_rate; -} - -void bw_phase_gen_reset(bw_phase_gen *instance) { - instance->first_run = 1; - instance->param_changed = ~0; -} - -#define PARAM_FREQUENCY 1 -#define PARAM_PORTAMENTO_TAU (1<<1) - -void bw_phase_gen_process(bw_phase_gen *instance, const float *x_mod, float* y, float *y_phase_inc, int n_samples) { - if (instance->param_changed) { - if (instance->param_changed & PARAM_FREQUENCY) - instance->portamento_target = instance->T * instance->frequency; - if (instance->param_changed & PARAM_PORTAMENTO_TAU) - instance->portamento_mA1 = bw_expf_3(-instance->T * bw_rcpf_2(instance->portamento_tau)); - } - - if (instance->first_run) { - instance->phase = 0.f; - instance->portamento_z1 = instance->portamento_target; - instance->first_run = 0; - } - - if (y_phase_inc == NULL) - y_phase_inc = y; - - if (x_mod != NULL) - for (int i = 0; i < n_samples; i++) { - const float portamento = instance->portamento_target + instance->portamento_mA1 * (instance->portamento_z1 - instance->portamento_target); - instance->portamento_z1 = portamento; - - const float phase_inc = portamento * bw_pow2f_3(x_mod[i]); - instance->phase += phase_inc; - instance->phase -= bw_floorf(instance->phase); - - y_phase_inc[i] = phase_inc; - y[i] = instance->phase; - } - else - for (int i = 0; i < n_samples; i++) { - const float portamento = instance->portamento_target + instance->portamento_mA1 * (instance->portamento_z1 - instance->portamento_target); - instance->portamento_z1 = portamento; - - instance->phase += portamento; - instance->phase -= bw_floorf(instance->phase); - - y_phase_inc[i] = portamento; - y[i] = instance->phase; - } -} - -void bw_phase_gen_set_frequency(bw_phase_gen *instance, float value) { - if (instance->frequency != value) { - instance->frequency = value; - instance->param_changed |= PARAM_FREQUENCY; - } -} - -void bw_phase_gen_set_portamento_tau(bw_phase_gen *instance, float value) { - if (instance->portamento_tau != value) { - instance->portamento_tau = value; - instance->param_changed |= PARAM_PORTAMENTO_TAU; - } -}