From 695dca576966dc18c59e41345e18b78efba85344 Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Thu, 1 Jun 2023 12:20:37 +0200 Subject: [PATCH] new bw_gain_get_gain() + fixed bw_ringmod inv polarity and doc + tentative bw_drywet --- include/bw_drywet.h | 185 +++++++++++++++++++++++++++++++++++++++++++ include/bw_gain.h | 17 +++- include/bw_ringmod.h | 15 +++- 3 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 include/bw_drywet.h diff --git a/include/bw_drywet.h b/include/bw_drywet.h new file mode 100644 index 0000000..987f13f --- /dev/null +++ b/include/bw_drywet.h @@ -0,0 +1,185 @@ +/* + * Brickworks + * + * Copyright (C) 2023 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 + * along with Brickworks. If not, see . + * + * File author: Stefano D'Angelo + */ + +/*! + * module_type {{{ dsp }}} + * version {{{ 0.5.0 }}} + * requires {{{ bw_common bw_config bw_gain bw_math bw_one_pole }}} + * description {{{ + * Dry/wet mixer. + * }}} + * changelog {{{ + * + * }}} + */ + +#ifndef _BW_DRYWET_H +#define _BW_DRYWET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/*! api {{{ + * #### bw_drywet_coeffs + * ```>>> */ +typedef struct _bw_drywet_coeffs bw_drywet_coeffs; +/*! <<<``` + * Coefficients and related. + * + * #### bw_drywet_init() + * ```>>> */ +static inline void bw_drywet_init(bw_drywet_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Initializes input parameter values in `coeffs`. + * + * #### bw_drywet_set_sample_rate() + * ```>>> */ +static inline void bw_drywet_set_sample_rate(bw_drywet_coeffs *BW_RESTRICT coeffs, float sample_rate); +/*! <<<``` + * Sets the `sample_rate` (Hz) value in `coeffs`. + * + * #### bw_drywet_reset_coeffs() + * ```>>> */ +static inline void bw_drywet_reset_coeffs(bw_drywet_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Resets coefficients in `coeffs` to assume their target values. + * + * #### bw_drywet_update_coeffs_ctrl() + * ```>>> */ +static inline void bw_drywet_update_coeffs_ctrl(bw_drywet_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Triggers control-rate update of coefficients in `coeffs`. + * + * #### bw_drywet_update_coeffs_audio() + * ```>>> */ +static inline void bw_drywet_update_coeffs_audio(bw_drywet_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Triggers audio-rate update of coefficients in `coeffs`. + * + * #### bw_drywet_process1() + * ```>>> */ +static inline float bw_drywet_process1(const bw_drywet_coeffs *BW_RESTRICT coeffs, float x_dry, float x_wet); +/*! <<<``` + * Processes one dry input sample `x_dry` and one wet input sample `x_wet` + * using `coeffs` and returns the corresponding output sample. + * + * #### bw_drywet_process() + * ```>>> */ +static inline void bw_drywet_process(bw_drywet_coeffs *BW_RESTRICT coeffs, const float *x_dry, const float *x_wet, float *y, int n_samples); +/*! <<<``` + * Processes the first `n_samples` of the dry input buffer `x_dry` and of the + * wet input buffer `x_wet` and fills the first `n_samples` of the output + * buffer `y`, while using and updating `coeffs` (control and audio rate). + * + * #### bw_drywet_set_wet_lin() + * ```>>> */ +static inline void bw_drywet_set_wet_lin(bw_drywet_coeffs *BW_RESTRICT coeffs, float value); +/*! <<<``` + * Sets the wet gain parameter to the given `value` (linear gain) in `coeffs`. + * + * Default value: `1.f`. + * + * #### bw_drywet_set_wet_dB() + * ```>>> */ +static inline void bw_drywet_set_wet_dB(bw_drywet_coeffs *BW_RESTRICT coeffs, float value); +/*! <<<``` + * Sets the wet gain parameter to the given `value` (dB) in `coeffs`. + * + * Default value: `0.f`. + * + * #### bw_drywet_set_smooth_tau() + * ```>>> */ +static inline void bw_drywet_set_smooth_tau(bw_drywet_coeffs *BW_RESTRICT coeffs, float value); +/*! <<<``` + * Sets the smoothing time constant `value` (s) in `coeffs`. + * + * Default value: `0.05f`. + * }}} */ + +/*** 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 + +struct _bw_drywet_coeffs { + // Sub-components + bw_gain gain_coeffs; +}; + +static inline void bw_drywet_init(bw_drywet_coeffs *BW_RESTRICT coeffs) { + bw_gain_init(&coeffs->gain_coeffs); +} + +static inline void bw_drywet_set_sample_rate(bw_drywet_coeffs *BW_RESTRICT coeffs, float sample_rate) { + bw_gain_sample_rate(&coeffs->smooth_coeffs, sample_rate); +} + +static inline void bw_drywet_reset_coeffs(bw_drywet_coeffs *BW_RESTRICT coeffs) { + bw_gain_reset_coeffs(&coeffs->gain_coeffs); +} + +static inline void bw_drywet_update_coeffs_ctrl(bw_drywet_coeffs *BW_RESTRICT coeffs) { + bw_gain_update_coeffs_ctrl(&coeffs->gain_coeffs); +} + +static inline void bw_drywet_update_coeffs_audio(bw_drywet_coeffs *BW_RESTRICT coeffs) { + bw_gain_update_coeffs_audio(&coeffs->gain_coeffs); +} + +static inline float bw_drywet_process1(const bw_drywet_coeffs *BW_RESTRICT coeffs, float x_dry, float x_wet) { + return bw_gain_get_gain(coeffs->gain_coeffs) * (x_wet - x_dry) + x_dry; +} + +static inline void bw_drywet_process(bw_drywet_coeffs *BW_RESTRICT coeffs, const float *x_dry, const float *x_wet, float *y, int n_samples) { + bw_drywet_update_coeffs_ctrl(coeffs); + for (int i = 0; i < n_samples; i++) { + bw_drywet_update_coeffs_audio(coeffs); + y[i] = bw_drywet_process1(coeffs, x_dry[i], x_wet[i]); + } +} + +static inline void bw_drywet_set_drywet_lin(bw_drywet_coeffs *BW_RESTRICT coeffs, float value) { + bw_gain_set_gain_lin(&coeffs->gain_coeffs, value); +} + +static inline void bw_drywet_set_drywet_dB(bw_drywet_coeffs *BW_RESTRICT coeffs, float value) { + bw_gain_set_gain_dB(&coeffs->gain_coeffs, value); +} + +static inline void bw_drywet_set_smooth_tau(bw_drywet_coeffs *BW_RESTRICT coeffs, float value) { + bw_gain_set_smooth_tau(&coeffs->gain_coeffs, value); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/bw_gain.h b/include/bw_gain.h index 1788734..4021815 100644 --- a/include/bw_gain.h +++ b/include/bw_gain.h @@ -20,13 +20,18 @@ /*! * module_type {{{ dsp }}} - * version {{{ 0.3.0 }}} + * version {{{ 0.5.0 }}} * requires {{{ bw_common bw_config bw_math bw_one_pole }}} * description {{{ * Gain. * }}} * changelog {{{ *
    + *
  • Version 0.5.0: + *
      + *
    • Added bw_gain_get_gain().
    • + *
    + *
  • *
  • Version 0.3.0: *
      *
    • Renamed as bw_gain.
    • @@ -133,6 +138,12 @@ static inline void bw_gain_set_smooth_tau(bw_gain_coeffs *BW_RESTRICT coeffs, fl * Sets the smoothing time constant `value` (s) in `coeffs`. * * Default value: `0.05f`. + * + * #### bw_gain_get_gain() + * ```>>> */ +static inline float bw_gain_get_gain(const bw_gain_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Returns the actual current gain coefficient (linear gain) in `coeffs`. * }}} */ /*** Implementation ***/ @@ -211,6 +222,10 @@ static inline void bw_gain_set_smooth_tau(bw_gain_coeffs *BW_RESTRICT coeffs, fl coeffs->smooth_tau = value; } +static inline float bw_gain_get_gain(const bw_gain_coeffs *BW_RESTRICT coeffs) { + return bw_one_pole_get_y_z1(&coeffs->smooth_state); +} + #ifdef __cplusplus } #endif diff --git a/include/bw_ringmod.h b/include/bw_ringmod.h index fbead2f..e6993b0 100644 --- a/include/bw_ringmod.h +++ b/include/bw_ringmod.h @@ -20,13 +20,19 @@ /*! * module_type {{{ dsp }}} - * version {{{ 0.4.0 }}} + * version {{{ 0.5.0 }}} * requires {{{ bw_common bw_config bw_math bw_one_pole }}} * description {{{ * Ring modulator with variable modulation amount. * }}} * changelog {{{ *
        + *
      • Version 0.5.0: + *
          + *
        • Fixed inverted-polarity modulation.
        • + *
        • "modulator signal" -> "modulation signal" in documentation.
        • + *
        + *
      • *
      • Version 0.4.0: *
          *
        • First release.
        • @@ -86,14 +92,14 @@ static inline void bw_ringmod_update_coeffs_audio(bw_ringmod_coeffs *BW_RESTRICT * ```>>> */ static inline float bw_ringmod_process1(const bw_ringmod_coeffs *BW_RESTRICT coeffs, float x_mod, float x_car); /*! <<<``` - * Processes one modulator input sample `x_mod` and one carrier input sample + * Processes one modulation input sample `x_mod` and one carrier input sample * `x_car` using `coeffs` and returns the corresponding output sample. * * #### bw_ringmod_process() * ```>>> */ static inline void bw_ringmod_process(bw_ringmod_coeffs *BW_RESTRICT coeffs, const float *x_mod, const float *x_car, float *y, int n_samples); /*! <<<``` - * Processes the first `n_samples` of the modulator input buffer `x_mod` and + * Processes the first `n_samples` of the modulation input buffer `x_mod` and * of the carrier input buffer `x_car` and fills the first `n_samples` of the * output buffer `y`, while using and updating `coeffs` (control and audio * rate). @@ -150,7 +156,8 @@ static inline void bw_ringmod_update_coeffs_audio(bw_ringmod_coeffs *BW_RESTRICT } static inline float bw_ringmod_process1(const bw_ringmod_coeffs *BW_RESTRICT coeffs, float x_mod, float x_car) { - return bw_one_pole_get_y_z1(&coeffs->smooth_state) * (x_car * x_mod - x_mod) + x_mod; + const float k = bw_one_pole_get_y_z1(&coeffs->smooth_state); + return k * x_car * x_mod + bw_absf(1.f - k) * x_mod; } static inline void bw_ringmod_process(bw_ringmod_coeffs *BW_RESTRICT coeffs, const float *x_mod, const float *x_car, float *y, int n_samples) {