From c4fdc7d2e598b2d48d96bfa93326f26eda9e906c Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Mon, 28 Nov 2022 12:36:57 +0100 Subject: [PATCH] ported bw_env_follow to new API --- examples/synth/src/bw_example_synth.c | 17 ++- include/bw_env_follow.h | 149 +++++++++++++++++--------- include/bw_inline_slew_lim.h | 89 --------------- src/bw_env_follow.c | 44 -------- 4 files changed, 111 insertions(+), 188 deletions(-) delete mode 100644 include/bw_inline_slew_lim.h delete mode 100644 src/bw_env_follow.c diff --git a/examples/synth/src/bw_example_synth.c b/examples/synth/src/bw_example_synth.c index ceb7987..3d0b88f 100644 --- a/examples/synth/src/bw_example_synth.c +++ b/examples/synth/src/bw_example_synth.c @@ -30,6 +30,7 @@ #include #include #include +#include /* #include @@ -65,6 +66,8 @@ struct _bw_example_synth { bw_phase_gen_coeffs a440_phase_gen_coeffs; bw_phase_gen_state a440_phase_gen_state; bw_vol_coeffs vol_coeffs; + bw_env_follow_coeffs env_follow_coeffs; + bw_env_follow_state env_follow_state; /* bw_osc_pulse osc_pulse; bw_osc_filt osc_filt; @@ -95,9 +98,11 @@ bw_example_synth bw_example_synth_new() { bw_noise_gen_init(&instance->noise_gen_coeffs, &instance->rand_state); bw_phase_gen_init(&instance->a440_phase_gen_coeffs); bw_vol_init(&instance->vol_coeffs); + bw_env_follow_init(&instance->env_follow_coeffs); bw_phase_gen_set_frequency(&instance->a440_phase_gen_coeffs, 440.f); bw_noise_gen_set_sample_rate_scaling(&instance->noise_gen_coeffs, 1); + bw_env_follow_set_release_tau(&instance->env_follow_coeffs, 1.f); instance->rand_state = 0xbaddecaf600dfeed; /* @@ -105,11 +110,8 @@ bw_example_synth bw_example_synth_new() { bw_osc_filt_init(&instance->osc_filt); bw_svf_init(&instance->svf); bw_env_gen_init(&instance->env_gen); - bw_vol_init(&instance->vol); - bw_env_follow_init(&instance->env_follow); 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; @@ -124,12 +126,11 @@ void bw_example_synth_set_sample_rate(bw_example_synth instance, float sample_ra bw_noise_gen_set_sample_rate(&instance->noise_gen_coeffs, sample_rate); bw_phase_gen_set_sample_rate(&instance->a440_phase_gen_coeffs, sample_rate); bw_vol_set_sample_rate(&instance->vol_coeffs, sample_rate); + bw_env_follow_set_sample_rate(&instance->env_follow_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); */ } @@ -139,6 +140,8 @@ void bw_example_synth_reset(bw_example_synth instance) { bw_phase_gen_reset_coeffs(&instance->a440_phase_gen_coeffs); bw_phase_gen_reset_state(&instance->a440_phase_gen_coeffs, &instance->a440_phase_gen_state); bw_vol_reset_coeffs(&instance->vol_coeffs); + bw_env_follow_reset_coeffs(&instance->env_follow_coeffs); + bw_env_follow_reset_state(&instance->env_follow_coeffs, &instance->env_follow_state); /* bw_osc_pulse_reset(&instance->osc_pulse); bw_osc_filt_reset(&instance->osc_filt); @@ -193,6 +196,10 @@ void bw_example_synth_process(bw_example_synth instance, const float** x, float* y[0][i] += a440_y; } bw_vol_process(&instance->vol_coeffs, y[0], y[0], n_samples); + + for (int i = 0; i < n_samples; i++) + bw_env_follow_process1(&instance->env_follow_coeffs, &instance->env_follow_state, y[0][i]); + instance->level = bw_env_follow_get_y_z1(&instance->env_follow_state); } void bw_example_synth_set_parameter(bw_example_synth instance, int index, float value) { diff --git a/include/bw_env_follow.h b/include/bw_env_follow.h index 29d217c..6b8c406 100644 --- a/include/bw_env_follow.h +++ b/include/bw_env_follow.h @@ -32,7 +32,7 @@ *
    *
  • Version 0.2.0: *
      - *
    • Refactored API to avoid dynamic memory allocation.
    • + *
    • Refactored API.
    • *
    *
  • *
  • Version 0.1.0: @@ -47,83 +47,132 @@ #ifndef _BW_ENV_FOLLOW_H #define _BW_ENV_FOLLOW_H -#include - #ifdef __cplusplus extern "C" { #endif -/*! api {{{ - * #### bw_env_follow - * ```>>> */ -typedef struct _bw_env_follow bw_env_follow; -/*! <<<``` - * Instance object. - * >>> */ +#include -/*! ... +/*! api {{{ + * #### bw_env_follow_coeffs + * ```>>> */ +typedef struct _bw_env_follow_coeffs bw_env_follow_coeffs; +/*! <<<``` + * Coefficients. + * + * ### bw_env_follow_state + * >>> */ +typedef struct _bw_env_follow_state bw_env_follow_state; +/*! <<<``` + * State. + * * #### bw_env_follow_init() * ```>>> */ -void bw_env_follow_init(bw_env_follow *instance); +static inline void bw_env_follow_init(bw_env_follow_coeffs *BW_RESTRICT coeffs); /*! <<<``` - * Initializes the `instance` object. - * >>> */ - -/*! ... + * Initializes `coeffs`. + * * #### bw_env_follow_set_sample_rate() * ```>>> */ -void bw_env_follow_set_sample_rate(bw_env_follow *instance, float sample_rate); +static inline void bw_env_follow_set_sample_rate(bw_env_follow_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_one_pole_reset_state() + * ```>>> */ +static inline void bw_env_follow_reset_state(const bw_env_follow_coeffs *BW_RESTRICT coeffs, bw_env_follow_state *BW_RESTRICT state); +/*! <<<``` + * Resets the given `state` to the initial state using the given `coeffs`. * >>> */ -/*! ... - * #### bw_env_follow_reset() - * ```>>> */ -void bw_env_follow_reset(bw_env_follow *instance); -/*! <<<``` - * Resets the given `instance` to its initial state. - * >>> */ +static inline void bw_env_follow_reset_coeffs(bw_env_follow_coeffs *BW_RESTRICT coeffs); + +static inline void bw_env_follow_update_coeffs_ctrl(bw_env_follow_coeffs *BW_RESTRICT coeffs); +static inline void bw_env_follow_update_coeffs_audio(bw_env_follow_coeffs *BW_RESTRICT coeffs); + +static inline float bw_env_follow_process1(const bw_env_follow_coeffs *BW_RESTRICT coeffs, bw_env_follow_state *BW_RESTRICT state, float x); /*! ... * #### bw_env_follow_process() * ```>>> */ -void bw_env_follow_process(bw_env_follow *instance, const float *x, float *y, int n_samples); +static inline void bw_env_follow_process(bw_env_follow_coeffs *BW_RESTRICT coeffs, bw_env_follow_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 * buffer `y`. - * >>> */ - -/*! ... - * #### bw_env_follow_get_one_pole() - * ```>>> */ -bw_one_pole *bw_env_follow_get_one_pole(bw_env_follow *instance); -/*! <<<``` - * Returns a pointer to the internal one-pole filter of the given - * `instance`. - * - * The returned pointer must not be used for any other purpose than setting - * parameters. - * - * This is **NOT** a function that gets an output parameter as described in - * the [documentation for DSP modules](api#dsp). - * - * This function is [reentrant](api#reentrant-function), - * [RT-safe](api#rt-safe-function), - * [**NOT** thread-safe](api#thread-safe-function), and has - * [no side effects](api#no-side-effects). * }}} */ -/* 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_env_follow { +static inline void bw_env_follow_set_attack_tau(bw_env_follow_coeffs *BW_RESTRICT coeffs, float value); +static inline void bw_env_follow_set_release_tau(bw_env_follow_coeffs *BW_RESTRICT coeffs, float value); + +static inline float bw_env_follow_get_y_z1(const bw_env_follow_state *BW_RESTRICT state); + +/*** Implementation ***/ + +#include +#include + +/* 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. */ + +struct _bw_env_follow_coeffs { // Sub-components bw_one_pole_coeffs one_pole_coeffs; +}; + +struct _bw_env_follow_state { bw_one_pole_state one_pole_state; }; +static inline void bw_env_follow_init(bw_env_follow_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_init(&coeffs->one_pole_coeffs); +} + +static inline void bw_env_follow_set_sample_rate(bw_env_follow_coeffs *BW_RESTRICT coeffs, float sample_rate) { + bw_one_pole_set_sample_rate(&coeffs->one_pole_coeffs, sample_rate); +} + +static inline void bw_env_follow_reset_coeffs(bw_env_follow_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_reset_coeffs(&coeffs->one_pole_coeffs); +} + +static inline void bw_env_follow_reset_state(const bw_env_follow_coeffs *BW_RESTRICT coeffs, bw_env_follow_state *BW_RESTRICT state) { + bw_one_pole_reset_state(&coeffs->one_pole_coeffs, &state->one_pole_state, 0.f); +} + +static inline void bw_env_follow_update_coeffs_ctrl(bw_env_follow_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_update_coeffs_ctrl(&coeffs->one_pole_coeffs); +} + +static inline void bw_env_follow_update_coeffs_audio(bw_env_follow_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_update_coeffs_audio(&coeffs->one_pole_coeffs); +} + +static inline float bw_env_follow_process1(const bw_env_follow_coeffs *BW_RESTRICT coeffs, bw_env_follow_state *BW_RESTRICT state, float x) { + x = bw_absf(x); + return bw_one_pole_process1_asym(&coeffs->one_pole_coeffs, &state->one_pole_state, x); +} + +static inline void bw_env_follow_process(bw_env_follow_coeffs *BW_RESTRICT coeffs, bw_env_follow_state *BW_RESTRICT state, const float *x, float *y, int n_samples) { + bw_env_follow_update_coeffs_ctrl(coeffs); + for (int i = 0; i < n_samples; i++) { + bw_env_follow_update_coeffs_audio(coeffs); + y[i] = bw_env_follow_process1(coeffs, state, x[i]); + } +} + +static inline void bw_env_follow_set_attack_tau(bw_env_follow_coeffs *BW_RESTRICT coeffs, float value) { + bw_one_pole_set_tau_up(&coeffs->one_pole_coeffs, value); +} + +static inline void bw_env_follow_set_release_tau(bw_env_follow_coeffs *BW_RESTRICT coeffs, float value) { + bw_one_pole_set_tau_down(&coeffs->one_pole_coeffs, value); +} + +static inline float bw_env_follow_get_y_z1(const bw_env_follow_state *BW_RESTRICT state) { + return bw_one_pole_get_y_z1(&state->one_pole_state); +} + #ifdef __cplusplus } #endif diff --git a/include/bw_inline_slew_lim.h b/include/bw_inline_slew_lim.h deleted file mode 100644 index df591a9..0000000 --- a/include/bw_inline_slew_lim.h +++ /dev/null @@ -1,89 +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 - */ - -/*! - * module_type {{{ utility }}} - * version {{{ 0.1.0 }}} - * requires {{{ bw_config bw_common bw_math }}} - * description {{{ - * Inline slew-rate limiter. - * - * This is similar to [bw_slew_lim](bw_slew_lim) but can be used to process - * on a sample-by-sample basis without buffers. - * }}} - * changelog {{{ - *
      - *
    • Version 0.1.0: - *
        - *
      • First release.
      • - *
      - *
    • - *
    - * }}} - */ - -#ifndef _BW_INLINE_SLEW_LIM_H -#define _BW_INLINE_SLEW_LIM_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/*! api {{{ - * #### bw_inline_slew_lim_get_max_var() - * ```>>> */ -static inline float bw_inline_slew_lim_get_max_var(float sample_rate, float rate); -/*! <<<``` - * Computes a maximum variation coefficient to be used with - * `bw_inline_slew_lim()` corresponding to the given `sample_rate` (Hz) and - * `rate` (1/s) values. - * - * `rate` represents the maximum variation per second and must be finite and - * non-negative. - * >>> */ - -/*! ... - * #### bw_inline_slew_lim() - * ```>>> */ -static inline float bw_inline_slew_lim(float x, float y_z1, float max_inc, float max_dec); -/*! <<<``` - * Processes one input sample `x`, using the previous output value `y_z1` and - * the maximum variation coefficients `max_inc` and `max_dec`, and returns - * the corresponding output sample. - * - * Both `max_inc` and `max_dec` must be finite and non-negative. - * }}} */ - -/* Implementation */ - -static inline float bw_inline_slew_lim_get_max_var(float sample_rate, float rate) { - return rate * bw_rcpf_2(sample_rate); -} - -static inline float bw_inline_slew_lim(float x, float y_z1, float max_inc, float max_dec) { - return bw_clipf(x, y_z1 - max_dec, y_z1 + max_inc); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/bw_env_follow.c b/src/bw_env_follow.c deleted file mode 100644 index 0b22797..0000000 --- a/src/bw_env_follow.c +++ /dev/null @@ -1,44 +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_env_follow_init(bw_env_follow *instance) { - bw_one_pole_init(&instance->one_pole); -} - -void bw_env_follow_set_sample_rate(bw_env_follow *instance, float sample_rate) { - bw_one_pole_set_sample_rate(&instance->one_pole, sample_rate); -} - -void bw_env_follow_reset(bw_env_follow *instance) { - bw_one_pole_reset(&instance->one_pole); -} - -void bw_env_follow_process(bw_env_follow *instance, const float *x, float *y, int n_samples) { - for (int i = 0; i < n_samples; i++) - y[i] = bw_absf(x[i]); - bw_one_pole_process(&instance->one_pole, y, y, n_samples); -} - -bw_one_pole *bw_env_follow_get_one_pole(bw_env_follow *instance) { - return &instance->one_pole; -}