diff --git a/TODO b/TODO index 521df1f..3fd1d00 100644 --- a/TODO +++ b/TODO @@ -15,8 +15,8 @@ code: * fix vst3 mapped values (visible in Ableton Live) and short names * polish examples (ranges, etc.) * change name of vst3 template folders to something that doesn't look like a vst3 folder itself -* compute bit depth reduction only when input changes? (state) -* common smoothing policy (as control rate as possible?) +* compute bit depth reduction only when input changes? (state, option?) +* common smoothing policy (as control rate as possible?) - smoothing control? * avoid "force" in coeffs update by using inline functions? build system: diff --git a/examples/synth_mono/src/bw_example_synth_mono.c b/examples/synth_mono/src/bw_example_synth_mono.c index 098cd81..d49b13f 100644 --- a/examples/synth_mono/src/bw_example_synth_mono.c +++ b/examples/synth_mono/src/bw_example_synth_mono.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include enum { @@ -50,21 +50,21 @@ enum { p_vco1_fine, p_vco1_waveform, p_vco1_pw_slope, - p_vco1_volume, + p_vco1_level, p_vco2_mod, p_vco2_coarse, p_vco2_fine, p_vco2_waveform, p_vco2_pw_slope, - p_vco2_volume, + p_vco2_level, p_vco3_kbd, p_vco3_coarse, p_vco3_fine, p_vco3_waveform, p_vco3_pw_slope, - p_vco3_volume, + p_vco3_level, p_noise_color, - p_noise_volume, + p_noise_level, p_vcf_mod, p_vcf_kbd_ctrl, p_vcf_cutoff, @@ -91,22 +91,22 @@ struct _bw_example_synth_mono { bw_phase_gen_state vco1_phase_gen_state; bw_osc_pulse_coeffs vco1_pulse_coeffs; bw_osc_tri_coeffs vco1_tri_coeffs; - bw_vol_coeffs vco1_vol_coeffs; + bw_gain_coeffs vco1_gain_coeffs; bw_phase_gen_coeffs vco2_phase_gen_coeffs; bw_phase_gen_state vco2_phase_gen_state; bw_osc_pulse_coeffs vco2_pulse_coeffs; bw_osc_tri_coeffs vco2_tri_coeffs; - bw_vol_coeffs vco2_vol_coeffs; + bw_gain_coeffs vco2_gain_coeffs; bw_phase_gen_coeffs vco3_phase_gen_coeffs; bw_phase_gen_state vco3_phase_gen_state; bw_osc_pulse_coeffs vco3_pulse_coeffs; bw_osc_tri_coeffs vco3_tri_coeffs; - bw_vol_coeffs vco3_vol_coeffs; + bw_gain_coeffs vco3_gain_coeffs; bw_osc_filt_state osc_filt_state; bw_noise_gen_coeffs noise_gen_coeffs; bw_pink_filt_coeffs pink_filt_coeffs; bw_pink_filt_state pink_filt_state; - bw_vol_coeffs noise_vol_coeffs; + bw_gain_coeffs noise_gain_coeffs; bw_env_gen_coeffs vcf_env_gen_coeffs; bw_env_gen_state vcf_env_gen_state; bw_svf_coeffs vcf_coeffs; @@ -115,7 +115,7 @@ struct _bw_example_synth_mono { bw_env_gen_state vca_env_gen_state; bw_phase_gen_coeffs a440_phase_gen_coeffs; bw_phase_gen_state a440_phase_gen_state; - bw_vol_coeffs vol_coeffs; + bw_gain_coeffs gain_coeffs; bw_env_follow_coeffs env_follow_coeffs; bw_env_follow_state env_follow_state; @@ -143,23 +143,23 @@ bw_example_synth_mono bw_example_synth_mono_new() { bw_phase_gen_init(&instance->vco1_phase_gen_coeffs); bw_osc_pulse_init(&instance->vco1_pulse_coeffs); bw_osc_tri_init(&instance->vco1_tri_coeffs); - bw_vol_init(&instance->vco1_vol_coeffs); + bw_gain_init(&instance->vco1_gain_coeffs); bw_phase_gen_init(&instance->vco2_phase_gen_coeffs); bw_osc_pulse_init(&instance->vco2_pulse_coeffs); bw_osc_tri_init(&instance->vco2_tri_coeffs); - bw_vol_init(&instance->vco2_vol_coeffs); + bw_gain_init(&instance->vco2_gain_coeffs); bw_phase_gen_init(&instance->vco3_phase_gen_coeffs); bw_osc_pulse_init(&instance->vco3_pulse_coeffs); bw_osc_tri_init(&instance->vco3_tri_coeffs); - bw_vol_init(&instance->vco3_vol_coeffs); + bw_gain_init(&instance->vco3_gain_coeffs); bw_noise_gen_init(&instance->noise_gen_coeffs, &instance->rand_state); bw_pink_filt_init(&instance->pink_filt_coeffs); - bw_vol_init(&instance->noise_vol_coeffs); + bw_gain_init(&instance->noise_gain_coeffs); bw_env_gen_init(&instance->vcf_env_gen_coeffs); bw_svf_init(&instance->vcf_coeffs); bw_env_gen_init(&instance->vca_env_gen_coeffs); bw_phase_gen_init(&instance->a440_phase_gen_coeffs); - bw_vol_init(&instance->vol_coeffs); + bw_gain_init(&instance->gain_coeffs); bw_env_follow_init(&instance->env_follow_coeffs); bw_osc_saw_set_antialiasing(&instance->vco_saw_coeffs, 1); @@ -167,11 +167,11 @@ bw_example_synth_mono bw_example_synth_mono_new() { bw_osc_tri_set_antialiasing(&instance->vco1_tri_coeffs, 1); bw_osc_pulse_set_antialiasing(&instance->vco2_pulse_coeffs, 1); bw_osc_tri_set_antialiasing(&instance->vco2_tri_coeffs, 1); - bw_vol_set_volume_lin(&instance->vco2_vol_coeffs, 0.f); + bw_gain_set_gain_lin(&instance->vco2_gain_coeffs, 0.f); bw_osc_pulse_set_antialiasing(&instance->vco3_pulse_coeffs, 1); bw_osc_tri_set_antialiasing(&instance->vco3_tri_coeffs, 1); - bw_vol_set_volume_lin(&instance->vco3_vol_coeffs, 0.f); - bw_vol_set_volume_lin(&instance->noise_vol_coeffs, 0.f); + bw_gain_set_gain_lin(&instance->vco3_gain_coeffs, 0.f); + bw_gain_set_gain_lin(&instance->noise_gain_coeffs, 0.f); bw_phase_gen_set_frequency(&instance->a440_phase_gen_coeffs, 440.f); bw_env_follow_set_release_tau(&instance->env_follow_coeffs, 1.f); @@ -188,23 +188,23 @@ void bw_example_synth_mono_set_sample_rate(bw_example_synth_mono instance, float bw_phase_gen_set_sample_rate(&instance->vco1_phase_gen_coeffs, sample_rate); bw_osc_pulse_set_sample_rate(&instance->vco1_pulse_coeffs, sample_rate); bw_osc_tri_set_sample_rate(&instance->vco1_tri_coeffs, sample_rate); - bw_vol_set_sample_rate(&instance->vco1_vol_coeffs, sample_rate); + bw_gain_set_sample_rate(&instance->vco1_gain_coeffs, sample_rate); bw_phase_gen_set_sample_rate(&instance->vco2_phase_gen_coeffs, sample_rate); bw_osc_pulse_set_sample_rate(&instance->vco2_pulse_coeffs, sample_rate); bw_osc_tri_set_sample_rate(&instance->vco2_tri_coeffs, sample_rate); - bw_vol_set_sample_rate(&instance->vco2_vol_coeffs, sample_rate); + bw_gain_set_sample_rate(&instance->vco2_gain_coeffs, sample_rate); bw_phase_gen_set_sample_rate(&instance->vco3_phase_gen_coeffs, sample_rate); bw_osc_pulse_set_sample_rate(&instance->vco3_pulse_coeffs, sample_rate); bw_osc_tri_set_sample_rate(&instance->vco3_tri_coeffs, sample_rate); - bw_vol_set_sample_rate(&instance->vco3_vol_coeffs, sample_rate); + bw_gain_set_sample_rate(&instance->vco3_gain_coeffs, sample_rate); bw_noise_gen_set_sample_rate(&instance->noise_gen_coeffs, sample_rate); bw_pink_filt_set_sample_rate(&instance->pink_filt_coeffs, sample_rate); - bw_vol_set_sample_rate(&instance->noise_vol_coeffs, sample_rate); + bw_gain_set_sample_rate(&instance->noise_gain_coeffs, sample_rate); bw_env_gen_set_sample_rate(&instance->vcf_env_gen_coeffs, sample_rate); bw_svf_set_sample_rate(&instance->vcf_coeffs, sample_rate); bw_env_gen_set_sample_rate(&instance->vca_env_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_gain_set_sample_rate(&instance->gain_coeffs, sample_rate); bw_env_follow_set_sample_rate(&instance->env_follow_coeffs, sample_rate); } @@ -217,20 +217,20 @@ void bw_example_synth_mono_reset(bw_example_synth_mono instance) { bw_phase_gen_reset_state(&instance->vco1_phase_gen_coeffs, &instance->vco1_phase_gen_state, 0.f); bw_osc_pulse_reset_coeffs(&instance->vco1_pulse_coeffs); bw_osc_tri_reset_coeffs(&instance->vco1_tri_coeffs); - bw_vol_reset_coeffs(&instance->vco1_vol_coeffs); + bw_gain_reset_coeffs(&instance->vco1_gain_coeffs); bw_phase_gen_reset_coeffs(&instance->vco2_phase_gen_coeffs); bw_phase_gen_reset_state(&instance->vco2_phase_gen_coeffs, &instance->vco2_phase_gen_state, 0.f); bw_osc_pulse_reset_coeffs(&instance->vco2_pulse_coeffs); bw_osc_tri_reset_coeffs(&instance->vco2_tri_coeffs); - bw_vol_reset_coeffs(&instance->vco2_vol_coeffs); + bw_gain_reset_coeffs(&instance->vco2_gain_coeffs); bw_phase_gen_reset_coeffs(&instance->vco3_phase_gen_coeffs); bw_phase_gen_reset_state(&instance->vco3_phase_gen_coeffs, &instance->vco3_phase_gen_state, 0.f); bw_osc_pulse_reset_coeffs(&instance->vco3_pulse_coeffs); bw_osc_tri_reset_coeffs(&instance->vco3_tri_coeffs); - bw_vol_reset_coeffs(&instance->vco3_vol_coeffs); + bw_gain_reset_coeffs(&instance->vco3_gain_coeffs); bw_osc_filt_reset_state(&instance->osc_filt_state); bw_pink_filt_reset_state(&instance->pink_filt_coeffs, &instance->pink_filt_state); - bw_vol_reset_coeffs(&instance->noise_vol_coeffs); + bw_gain_reset_coeffs(&instance->noise_gain_coeffs); bw_env_gen_reset_coeffs(&instance->vcf_env_gen_coeffs); bw_env_gen_reset_state(&instance->vcf_env_gen_coeffs, &instance->vcf_env_gen_state); bw_svf_reset_coeffs(&instance->vcf_coeffs); @@ -239,7 +239,7 @@ void bw_example_synth_mono_reset(bw_example_synth_mono instance) { bw_env_gen_reset_state(&instance->vca_env_gen_coeffs, &instance->vca_env_gen_state); 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, 0.f); - bw_vol_reset_coeffs(&instance->vol_coeffs); + bw_gain_reset_coeffs(&instance->gain_coeffs); bw_env_follow_reset_coeffs(&instance->env_follow_coeffs); bw_env_follow_reset_state(&instance->env_follow_coeffs, &instance->env_follow_state); instance->note = 60; @@ -329,10 +329,10 @@ void bw_example_synth_mono_process(bw_example_synth_mono instance, const float** bw_osc_tri_reset_coeffs(&instance->vco2_tri_coeffs); } - bw_vol_process(&instance->vco1_vol_coeffs, instance->buf[2], instance->buf[2], n); - bw_vol_process(&instance->vco2_vol_coeffs, instance->buf[1], instance->buf[1], n); - bw_vol_process(&instance->vco3_vol_coeffs, out, out, n); - bw_vol_process(&instance->noise_vol_coeffs, instance->buf[0], instance->buf[0], n); + bw_gain_process(&instance->vco1_gain_coeffs, instance->buf[2], instance->buf[2], n); + bw_gain_process(&instance->vco2_gain_coeffs, instance->buf[1], instance->buf[1], n); + bw_gain_process(&instance->vco3_gain_coeffs, out, out, n); + bw_gain_process(&instance->noise_gain_coeffs, instance->buf[0], instance->buf[0], n); for (int j = 0; j < n; j++) out[j] = out[j] + instance->buf[1][j] + instance->buf[2][j]; @@ -367,7 +367,7 @@ void bw_example_synth_mono_process(bw_example_synth_mono instance, const float** for (int j = 0; j < n; j++) out[j] += instance->buf[0][j]; - bw_vol_process(&instance->vol_coeffs, out, out, n); + bw_gain_process(&instance->gain_coeffs, out, out, n); bw_env_follow_process(&instance->env_follow_coeffs, &instance->env_follow_state, out, NULL, n); } } @@ -378,7 +378,7 @@ void bw_example_synth_mono_set_parameter(bw_example_synth_mono instance, int ind instance->params[index] = value; switch (index) { case p_volume: - bw_vol_set_volume_lin(&instance->vol_coeffs, value * value * value); + bw_gain_set_gain_lin(&instance->gain_coeffs, value * value * value); break; case p_portamento: bw_phase_gen_set_portamento_tau(&instance->vco1_phase_gen_coeffs, value); @@ -389,25 +389,25 @@ void bw_example_synth_mono_set_parameter(bw_example_synth_mono instance, int ind bw_osc_pulse_set_pulse_width(&instance->vco1_pulse_coeffs, value); bw_osc_tri_set_slope(&instance->vco1_tri_coeffs, bw_clipf(value, 0.001f, 0.999f)); break; - case p_vco1_volume: - bw_vol_set_volume_lin(&instance->vco1_vol_coeffs, value * value * value); + case p_vco1_level: + bw_gain_set_gain_lin(&instance->vco1_gain_coeffs, value * value * value); break; case p_vco2_pw_slope: bw_osc_pulse_set_pulse_width(&instance->vco2_pulse_coeffs, value); bw_osc_tri_set_slope(&instance->vco2_tri_coeffs, bw_clipf(value, 0.001f, 0.999f)); break; - case p_vco2_volume: - bw_vol_set_volume_lin(&instance->vco2_vol_coeffs, value * value * value); + case p_vco2_level: + bw_gain_set_gain_lin(&instance->vco2_gain_coeffs, value * value * value); break; case p_vco3_pw_slope: bw_osc_pulse_set_pulse_width(&instance->vco3_pulse_coeffs, value); bw_osc_tri_set_slope(&instance->vco3_tri_coeffs, bw_clipf(value, 0.001f, 0.999f)); break; - case p_vco3_volume: - bw_vol_set_volume_lin(&instance->vco3_vol_coeffs, value * value * value); + case p_vco3_level: + bw_gain_set_gain_lin(&instance->vco3_gain_coeffs, value * value * value); break; - case p_noise_volume: - bw_vol_set_volume_lin(&instance->noise_vol_coeffs, value * value * value); + case p_noise_level: + bw_gain_set_gain_lin(&instance->noise_gain_coeffs, value * value * value); break; case p_vcf_Q: bw_svf_set_Q(&instance->vcf_coeffs, 0.5f + 9.5f * value); diff --git a/examples/synth_mono/src/config.h b/examples/synth_mono/src/config.h index a1da2e8..ed5ca43 100644 --- a/examples/synth_mono/src/config.h +++ b/examples/synth_mono/src/config.h @@ -74,21 +74,21 @@ static struct config_parameter config_parameters[NUM_PARAMETERS] = { { "VCO1 fine", "VCO1 fine", "st", 0, 0, 0, 0.5f }, { "VCO1 waveform", "VCO1 wave", "", 0, 0, 2, 0.f }, { "VCO1 pulse width/slope", "VCO1 pw/slope", "%", 0, 0, 0, 0.5f }, - { "VCO1 volume", "VCO1 volume", "%", 0, 0, 0, 1.f }, + { "VCO1 level", "VCO1 level", "%", 0, 0, 0, 1.f }, { "VCO2 modulation", "VCO2 mod", "%", 0, 0, 0, 0.f }, { "VCO2 coarse", "VCO2 coarse", "", 0, 0, 6, 0.5f }, { "VCO2 fine", "VCO2 fine", "st", 0, 0, 0, 0.5f }, { "VCO2 waveform", "VCO2 wave", "", 0, 0, 2, 0.f }, { "VCO2 pulse width/slope", "VCO2 pw/slope", "%", 0, 0, 0, 0.5f }, - { "VCO2 volume", "VCO2 volume", "%", 0, 0, 0, 0.f }, + { "VCO2 level", "VCO2 level", "%", 0, 0, 0, 0.f }, { "VCO3 kyboard control", "VCO3 kbd ctrl", "", 0, 0, 1, 1.f }, { "VCO3 coarse", "VCO3 coarse", "", 0, 0, 6, 0.5f }, { "VCO3 fine", "VCO3 fine", "st", 0, 0, 0, 0.5f }, { "VCO3 waveform", "VCO3 wave", "", 0, 0, 2, 0.f }, { "VCO3 pulse width/slope", "VCO3 pw/slope", "%", 0, 0, 0, 0.5f }, - { "VCO3 volume", "VCO3 volume", "%", 0, 0, 0, 0.f }, + { "VCO3 level", "VCO3 level", "%", 0, 0, 0, 0.f }, { "Noise color", "Noise color", "", 0, 0, 1, 0.f }, - { "Noise volume", "Noise volume", "%", 0, 0, 0, 0.f }, + { "Noise level", "Noise level", "%", 0, 0, 0, 0.f }, { "VCF modulation", "VCF mod", "%", 0, 0, 0, 0.f }, { "VCF keyboard control", "VCF kbd ctrl", "", 0, 0, 3, 0.f }, { "VCF cutoff", "VCF cutoff", "Hz", 0, 0, 0, 1.f }, diff --git a/examples/synth_mono/web/config.js b/examples/synth_mono/web/config.js index 0cdf143..cf29faa 100644 --- a/examples/synth_mono/web/config.js +++ b/examples/synth_mono/web/config.js @@ -74,7 +74,7 @@ var parameters = [ defaultValue: 0.5 }, { - name: "VCO1 volume", + name: "VCO1 level", output: false, defaultValue: 1.0 }, @@ -106,7 +106,7 @@ var parameters = [ defaultValue: 0.5 }, { - name: "VCO2 volume", + name: "VCO2 level", output: false, defaultValue: 0.0 }, @@ -139,7 +139,7 @@ var parameters = [ defaultValue: 0.5 }, { - name: "VCO3 volume", + name: "VCO3 level", output: false, defaultValue: 0.0 }, @@ -150,7 +150,7 @@ var parameters = [ step: 1 }, { - name: "Noise volume", + name: "Noise level", output: false, defaultValue: 0.0 }, diff --git a/examples/synth_simple/src/bw_example_synth_simple.c b/examples/synth_simple/src/bw_example_synth_simple.c index 8162b1c..5f1637a 100644 --- a/examples/synth_simple/src/bw_example_synth_simple.c +++ b/examples/synth_simple/src/bw_example_synth_simple.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include enum { @@ -61,7 +61,7 @@ struct _bw_example_synth_simple { bw_svf_state svf_state; bw_env_gen_coeffs env_gen_coeffs; bw_env_gen_state env_gen_state; - bw_vol_coeffs vol_coeffs; + bw_gain_coeffs gain_coeffs; bw_env_follow_coeffs env_follow_coeffs; bw_env_follow_state env_follow_state; @@ -85,7 +85,7 @@ bw_example_synth_simple bw_example_synth_simple_new() { bw_osc_pulse_init(&instance->osc_pulse_coeffs); bw_svf_init(&instance->svf_coeffs); bw_env_gen_init(&instance->env_gen_coeffs); - bw_vol_init(&instance->vol_coeffs); + bw_gain_init(&instance->gain_coeffs); bw_env_follow_init(&instance->env_follow_coeffs); bw_osc_pulse_set_antialiasing(&instance->osc_pulse_coeffs, 1); @@ -105,7 +105,7 @@ void bw_example_synth_simple_set_sample_rate(bw_example_synth_simple instance, f bw_osc_pulse_set_sample_rate(&instance->osc_pulse_coeffs, sample_rate); bw_svf_set_sample_rate(&instance->svf_coeffs, sample_rate); bw_env_gen_set_sample_rate(&instance->env_gen_coeffs, sample_rate); - bw_vol_set_sample_rate(&instance->vol_coeffs, sample_rate); + bw_gain_set_sample_rate(&instance->gain_coeffs, sample_rate); bw_env_follow_set_sample_rate(&instance->env_follow_coeffs, sample_rate); } @@ -118,7 +118,7 @@ void bw_example_synth_simple_reset(bw_example_synth_simple instance) { bw_svf_reset_state(&instance->svf_coeffs, &instance->svf_state); bw_env_gen_reset_coeffs(&instance->env_gen_coeffs); bw_env_gen_reset_state(&instance->env_gen_coeffs, &instance->env_gen_state); - bw_vol_reset_coeffs(&instance->vol_coeffs); + bw_gain_reset_coeffs(&instance->gain_coeffs); bw_env_follow_reset_coeffs(&instance->env_follow_coeffs); bw_env_follow_reset_state(&instance->env_follow_coeffs, &instance->env_follow_state); instance->note = -1; @@ -142,7 +142,7 @@ void bw_example_synth_simple_process(bw_example_synth_simple instance, const flo bw_env_gen_process(&instance->env_gen_coeffs, &instance->env_gen_state, instance->buf, n); for (int j = 0; j < n; j++) out[j] *= instance->buf[j]; - bw_vol_process(&instance->vol_coeffs, out, out, n); + bw_gain_process(&instance->gain_coeffs, out, out, n); bw_env_follow_process(&instance->env_follow_coeffs, &instance->env_follow_state, out, NULL, n); } } @@ -153,7 +153,7 @@ void bw_example_synth_simple_set_parameter(bw_example_synth_simple instance, int instance->params[index] = value; switch (index) { case p_volume: - bw_vol_set_volume_lin(&instance->vol_coeffs, value * value * value); + bw_gain_set_gain_lin(&instance->gain_coeffs, value * value * value); break; case p_portamento: bw_phase_gen_set_portamento_tau(&instance->phase_gen_coeffs, value); diff --git a/include/bw_allpass1.h b/include/bw_allpass1.h deleted file mode 100644 index b52a642..0000000 --- a/include/bw_allpass1.h +++ /dev/null @@ -1,201 +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 - * along with Brickworks. If not, see . - * - * File author: Stefano D'Angelo - */ - -/*! - * module_type {{{ dsp }}} - * version {{{ 0.3.0 }}} - * requires {{{ bw_config bw_common bw_math }}} - * description {{{ - * First-order allpass filter. - * }}} - * changelog {{{ - *
    - *
  • Version 0.3.0: - *
      - *
    • First release.
    • - *
    - *
  • - *
- * }}} - */ - -#ifndef _BW_ALLPASS1_H -#define _BW_ALLPASS1_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/*! api {{{ - * #### bw_allpass1_coeffs - * ```>>> */ -typedef struct _bw_allpass1_coeffs bw_allpass1_coeffs; -/*! <<<``` - * Coefficients and related. - * - * #### bw_allpass1_state - * ```>>> */ -typedef struct _bw_allpass1_state bw_allpass1_state; -/*! <<<``` - * Internal state and related. - * - * #### bw_allpass1_init() - * ```>>> */ -static inline void bw_allpass1_init(bw_allpass1_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Initializes input parameter values in `coeffs`. - * - * #### bw_allpass1_set_sample_rate() - * ```>>> */ -static inline void bw_allpass1_set_sample_rate(bw_allpass1_coeffs *BW_RESTRICT coeffs, float sample_rate); -/*! <<<``` - * Sets the `sample_rate` (Hz) value in `coeffs`. - * - * #### bw_allpass1_reset_coeffs() - * ```>>> */ -static inline void bw_allpass1_reset_coeffs(bw_allpass1_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Resets coefficients in `coeffs` to assume their target values. - * - * #### bw_allpass1_reset_state() - * ```>>> */ -static inline void bw_allpass1_reset_state(const bw_allpass1_coeffs *BW_RESTRICT coeffs, bw_allpass1_state *BW_RESTRICT state); -/*! <<<``` - * Resets the given `state` to its initial values using the given `coeffs`. - * - * #### bw_allpass1_update_coeffs_ctrl() - * ```>>> */ -static inline void bw_allpass1_update_coeffs_ctrl(bw_allpass1_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Triggers control-rate update of coefficients in `coeffs`. - * - * #### bw_allpass1_update_coeffs_audio() - * ```>>> */ -static inline void bw_allpass1_update_coeffs_audio(bw_allpass1_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Triggers audio-rate update of coefficients in `coeffs`. - * - * #### bw_allpass1_process1() - * ```>>> */ -static inline float bw_allpass1_process1(const bw_allpass1_coeffs *BW_RESTRICT coeffs, bw_allpass1_state *BW_RESTRICT state, float x); -/*! <<<``` - * Processes one input sample `x` using `coeffs`, while using and updating - * `state`. Returns the corresponding output sample. - * - * #### bw_allpass1_process() - * ```>>> */ -static inline void bw_allpass1_process(bw_allpass1_coeffs *BW_RESTRICT coeffs, bw_allpass1_state *BW_RESTRICT state, const float *x, float *y, int n_samples); -/*! <<<``` - * Processes the first `n_samples` of the input buffer `x` and fills the - * first `n_samples` of the output buffer `y`, while using and updating both - * `coeffs` and `state` (control and audio rate). - * - * #### bw_allpass1_set_cutoff() - * ```>>> */ -static inline void bw_allpass1_set_cutoff(bw_allpass1_coeffs *BW_RESTRICT coeffs, float value); -/*! <<<``` - * Sets the cutoff frequency `value` (Hz) in `coeffs`. - * - * Default value: `1e3f`. - * }}} */ - -/*** 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_allpass1_coeffs { - // Coefficients - float t_k; - - float t; - float X_x; - float X_X_z1; - float lp_X; - - // Parameters - float cutoff; - float cutoff_prev; -}; - -struct _bw_allpass1_state { - float lp_z1; - float X_z1; -}; - -static inline void bw_allpass1_init(bw_allpass1_coeffs *BW_RESTRICT coeffs) { - coeffs->cutoff = 1e3f; -} - -static inline void bw_allpass1_set_sample_rate(bw_allpass1_coeffs *BW_RESTRICT coeffs, float sample_rate) { - coeffs->t_k = 3.141592653589793f / sample_rate; -} - -static inline void bw_allpass1_reset_coeffs(bw_allpass1_coeffs *BW_RESTRICT coeffs) { - coeffs->cutoff_prev = -1.f; - bw_allpass1_update_coeffs_ctrl(coeffs); -} - -static inline void bw_allpass1_reset_state(const bw_allpass1_coeffs *BW_RESTRICT coeffs, bw_allpass1_state *BW_RESTRICT state) { - state->lp_z1 = 0.f; - state->X_z1 = 0.f; -} - -static inline void bw_allpass1_update_coeffs_ctrl(bw_allpass1_coeffs *BW_RESTRICT coeffs) { - if (coeffs->cutoff != coeffs->cutoff_prev) { - coeffs->t = bw_tanf_3(coeffs->t_k * coeffs->cutoff); - const float k = bw_rcpf_2(1.f + coeffs->T); - coeffs->X_x = k * coeffs->cutoff; - coeffs->X_X_z1 = k * coeffs->t; - coeffs->lp_X = bw_rcpf_2(coeffs->cutoff); - coeffs->cutoff_prev = coeffs->cutoff; - } -} - -static inline void bw_allpass1_update_coeffs_audio(bw_allpass1_coeffs *BW_RESTRICT coeffs) { -} - -static inline float bw_allpass1_process1(const bw_allpass1_coeffs *BW_RESTRICT coeffs, bw_allpass1_state *BW_RESTRICT state, float x) { - const float X = coeffs->X_x * (x - state->lp_z1) - coeffs->X_X_z1 * state->X_z1; - const float lp = x - coeffs->lp_X * X; - state->X_z1 = X; - state->lp_z1 = lp; - return lp + lp - x; -} - -static inline void bw_allpass1_process(bw_allpass1_coeffs *BW_RESTRICT coeffs, bw_allpass1_state *BW_RESTRICT state, const float *x, float *y, int n_samples) { - bw_allpass1_update_coeffs_ctrl(coeffs); - for (int i = 0; i < n_samples; i++) - y[i] = bw_allpass1_process1(coeffs, state, x[i]); -} - -static inline void bw_allpass1_set_cutoff(bw_allpass1_coeffs *BW_RESTRICT coeffs, float value) { - coeffs->cutoff = value; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/bw_allpass2.h b/include/bw_allpass2.h deleted file mode 100644 index a9a8f09..0000000 --- a/include/bw_allpass2.h +++ /dev/null @@ -1,258 +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 - * along with Brickworks. If not, see . - * - * File author: Stefano D'Angelo - */ - -/*! - * module_type {{{ dsp }}} - * version {{{ 0.3.0 }}} - * requires {{{ bw_config bw_common bw_math }}} - * description {{{ - * Second-order allpass filter. - * }}} - * changelog {{{ - *
    - *
  • Version 0.3.0: - *
      - *
    • First release.
    • - *
    - *
  • - *
- * }}} - */ - -#ifndef _BW_ALLPASS2_H -#define _BW_ALLPASS2_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/*! api {{{ - * #### bw_allpass2_coeffs - * ```>>> */ -typedef struct _bw_allpass2_coeffs bw_allpass2_coeffs; -/*! <<<``` - * Coefficients and related. - * - * #### bw_allpass2_state - * ```>>> */ -typedef struct _bw_allpass2_state bw_allpass2_state; -/*! <<<``` - * Internal state and related. - * - * #### bw_allpass2_init() - * ```>>> */ -static inline void bw_allpass2_init(bw_allpass2_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Initializes input parameter values in `coeffs`. - * - * #### bw_allpass2_set_sample_rate() - * ```>>> */ -static inline void bw_allpass2_set_sample_rate(bw_allpass2_coeffs *BW_RESTRICT coeffs, float sample_rate); -/*! <<<``` - * Sets the `sample_rate` (Hz) value in `coeffs`. - * - * #### bw_allpass2_reset_coeffs() - * ```>>> */ -static inline void bw_allpass2_reset_coeffs(bw_allpass2_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Resets coefficients in `coeffs` to assume their target values. - * - * #### bw_allpass2_reset_state() - * ```>>> */ -static inline void bw_allpass2_reset_state(const bw_allpass2_coeffs *BW_RESTRICT coeffs, bw_allpass2_state *BW_RESTRICT state); -/*! <<<``` - * Resets the given `state` to its initial values using the given `coeffs`. - * - * #### bw_allpass2_update_coeffs_ctrl() - * ```>>> */ -static inline void bw_allpass2_update_coeffs_ctrl(bw_allpass2_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Triggers control-rate update of coefficients in `coeffs`. - * - * #### bw_allpass2_update_coeffs_audio() - * ```>>> */ -static inline void bw_allpass2_update_coeffs_audio(bw_allpass2_coeffs *BW_RESTRICT coeffs); -/*! <<<``` - * Triggers audio-rate update of coefficients in `coeffs`. - * - * #### bw_allpass2_process1() - * ```>>> */ -static inline float bw_allpass2_process1(const bw_allpass2_coeffs *BW_RESTRICT coeffs, bw_allpass2_state *BW_RESTRICT state, float x); -/*! <<<``` - * Processes one input sample `x` using `coeffs`, while using and updating - * `state`. Returns the corresponding output sample. - * - * #### bw_allpass2_process() - * ```>>> */ -static inline void bw_allpass2_process(bw_allpass2_coeffs *BW_RESTRICT coeffs, bw_allpass2_state *BW_RESTRICT state, const float *x, float *y, int n_samples); -/*! <<<``` - * Processes the first `n_samples` of the input buffer `x` and fills the - * first `n_samples` of the output buffer `y`, while using and updating both - * `coeffs` and `state` (control and audio rate). - * - * #### bw_allpass2_set_cutoff() - * ```>>> */ -static inline void bw_allpass2_set_cutoff(bw_allpass2_coeffs *BW_RESTRICT coeffs, float value); -/*! <<<``` - * Sets the cutoff frequency `value` (Hz) in `coeffs`. - * - * Default value: `1e3f`. - * - * #### bw_allpass2_set_Q() - * ```>>> */ -static inline void bw_allpass2_set_Q(bw_allpass2_coeffs *BW_RESTRICT coeffs, float value); -/*! <<<``` - * Sets the quality factor `value` in `coeffs`. - * - * 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 - -struct _bw_allpass2_coeffs { - // Coefficients - float t_k; - - float t; - float kf; - float k; - float ks; - float X1_x; - float X2_X2_xz1_x1; - float X2_X1; - float X1_X2_xz1_x1; - float X1_VC1_xz1; - - // Parameters - float cutoff; - float Q; - int param_changed; -}; - -struct _bw_allpass2_state { - float VC1_z1; - float VC2_z1; - float X1_z1; - float X2_z1; -}; - -#define _BW_ALLPASS2_PARAM_CUTOFF 1 -#define _BW_ALLPASS2_PARAM_Q (1<<1) - -static inline void bw_allpass2_init(bw_allpass2_coeffs *BW_RESTRICT coeffs) { - coeffs->cutoff = 1e3f; - coeffs->Q = 0.5f; -} - -static inline void bw_allpass2_set_sample_rate(bw_allpass2_coeffs *BW_RESTRICT coeffs, float sample_rate) { - coeffs->t_k = 3.141592653589793f / sample_rate; -} - -static inline void bw_allpass2_reset_coeffs(bw_allpass2_coeffs *BW_RESTRICT coeffs) { - coeffs->param_changed = ~0; - bw_allpass2_update_coeffs_ctrl(coeffs); -} - -static inline void bw_allpass2_reset_state(const bw_allpass2_coeffs *BW_RESTRICT coeffs, bw_allpass2_state *BW_RESTRICT state) { - state->VC1_z1 = 0.f; - state->VC2_z1 = 0.f; - state->X1_z1 = 0.f; - state->X2_z1 = 0.f; -} - -static inline void bw_allpass2_update_coeffs_ctrl(bw_allpass2_coeffs *BW_RESTRICT coeffs) { - if (coeffs->param_changed) { - if (coeffs->param_changed & _BW_ALLPASS2_PARAM_CUTOFF) { - coeffs->t = bw_tanf_3(coeffs->t_k * coeffs->cutoff); - coeffs->kf = coeffs->t * bw_rcpf_2(coeffs->cutoff); - } - if (coeffs->param_changed & _BW_ALLPASS2_PARAM_Q) { - const float Q2 = coeffs->Q + coeffs->Q; - const float Q2s = Q2 + Q2; - coeffs->k = Q2 * bw_rcpf_2(1.f + bw_sqrtf_2(1.f + Q2s + Q2s)); - coeffs->ks = coeffs->k * coeffs->k; - coeffs->X1_x = 1.f - coeffs->ks - coeffs->ks; - } - const float kt = coeffs->k * coeffs->t; - const float kt1 = 1.f + kt; - const float X1_k = coeffs->cutoff * bw_rcpf_2(coeffs->t * kt1 + coeffs->k * (1.f - kt - kt)); - coeffs->X2_X2_xz1_x1 = -coeffs->cutoff * coeffs->k * bw_rcpf_2(kt1); - coeffs->X2_X1 = coeffs->kf * coeffs->X2_X2_xz1_x1; - coeffs->X1_X2_xz1_x1 = 3.f * X1_k * coeffs->ks; - coeffs->X1_VC1_xz1 = X1_k * kt1; - coeffs->param_changed = 0; - } -} - -static inline void bw_allpass2_update_coeffs_audio(bw_allpass2_coeffs *BW_RESTRICT coeffs) { -} - -static inline float bw_allpass2_process1(const bw_allpass2_coeffs *BW_RESTRICT coeffs, bw_allpass2_state *BW_RESTRICT state, float x) { - const float VC2_xz1 = coeffs->kf * state->X2_z1 + state->VC2_z1; - const float VC1_xz1 = coeffs->kf * state->X1_z1 + state->VC1_z1; - const float X2_xz1_x1 = state->VC2_xz1 + state->VC1_xz1; - const float X2_xz1 = coeffs->X2_X2_xz1_x1 * X2_xz1_x1; - const float X1 = coeffs->X1_VC1_xz1 * (coeffs->X1_x * x - state->VC1_xz1) + coeffs->X1_X2_xz1_x1 * X2_xz1_x1; - const float X2 = X2_xz1 + coeffs->X2_X1 * X1; - const float VC1 = coeffs->kf * X1 + VC1_xz1; - const float VC2 = coeffs->kf * X2 + VC2_xz1; - const float y_x1 = VC1 + VC2; - state->VC1_z1 = VC1; - state->VC2_z1 = VC2; - state->X1_z1 = X1; - state->X2_z1 = X2; - return x - (y_x1 + y_x1); -} - -static inline void bw_allpass2_process(bw_allpass2_coeffs *BW_RESTRICT coeffs, bw_allpass2_state *BW_RESTRICT state, const float *x, float *y, int n_samples) { - bw_allpass2_update_coeffs_ctrl(coeffs); - for (int i = 0; i < n_samples; i++) - y[i] = bw_allpass2_process1(coeffs, state, x[i]); -} - -static inline void bw_allpass2_set_cutoff(bw_allpass2_coeffs *BW_RESTRICT coeffs, float value) { - if (value != coeffs->cutoff) { - coeffs->cutoff = value; - coeffs->param_changed |= _BW_ALLPASS2_PARAM_CUTOFF; - } -} - -static inline void bw_allpass2_set_Q(bw_allpass2_coeffs *BW_RESTRICT coeffs, float value) { - if (value != coeffs->Q) { - coeffs->Q = value; - coeffs->param_changed |= _BW_ALLPASS2_PARAM_Q; - } -} - -#undef _BW_ALLPASS2_PARAM_CUTOFF -#undef _BW_ALLPASS2_PARAM_Q - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/bw_comp.h b/include/bw_comp.h index e8d0206..352b069 100644 --- a/include/bw_comp.h +++ b/include/bw_comp.h @@ -21,7 +21,9 @@ /*! * module_type {{{ dsp }}} * version {{{ 0.3.0 }}} - * requires {{{ bw_config bw_common bw_env_follow bw_one_pole bw_math bw_vol }}} + * requires {{{ + * bw_config bw_common bw_env_follow bw_one_pole bw_math bw_gain + * }}} * description {{{ * Feedforward compressor/limiter with independent sidechain input. * }}} @@ -180,13 +182,13 @@ static inline void bw_comp_set_gain_dB(bw_comp_coeffs *BW_RESTRICT coeffs, float #include #include -#include +#include #include struct _bw_comp_coeffs { // Sub-components bw_env_follow_coeffs env_follow_coeffs; - bw_vol_coeffs vol_coeffs; + bw_gain_coeffs gain_coeffs; bw_one_pole_coeffs smooth_coeffs; bw_one_pole_state smooth_thresh_state; bw_one_pole_state smooth_ratio_state; @@ -205,7 +207,7 @@ struct _bw_comp_state { static inline void bw_comp_init(bw_comp_coeffs *BW_RESTRICT coeffs) { bw_env_follow_init(&coeffs->env_follow_coeffs); - bw_vol_init(&coeffs->vol_coeffs); + bw_gain_init(&coeffs->gain_coeffs); bw_one_pole_set_tau(&coeffs->smooth_coeffs, 0.05f); coeffs->thresh = 1.f; coeffs->ratio = 1.f; @@ -213,14 +215,14 @@ static inline void bw_comp_init(bw_comp_coeffs *BW_RESTRICT coeffs) { static inline void bw_comp_set_sample_rate(bw_comp_coeffs *BW_RESTRICT coeffs, float sample_rate) { bw_env_follow_set_sample_rate(&coeffs->env_follow_coeffs, sample_rate); - bw_vol_set_sample_rate(&coeffs->vol_coeffs, sample_rate); + bw_gain_set_sample_rate(&coeffs->gain_coeffs, sample_rate); bw_one_pole_set_sample_rate(&coeffs->smooth_coeffs, sample_rate); bw_one_pole_reset_coeffs(&coeffs->smooth_coeffs); } static inline void bw_comp_reset_coeffs(bw_comp_coeffs *BW_RESTRICT coeffs) { bw_env_follow_reset_coeffs(&coeffs->env_follow_coeffs); - bw_vol_reset_coeffs(&coeffs->vol_coeffs); + bw_gain_reset_coeffs(&coeffs->gain_coeffs); bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_thresh_state, coeffs->thresh); bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_ratio_state, coeffs->ratio); } @@ -231,12 +233,12 @@ static inline void bw_comp_reset_state(const bw_comp_coeffs *BW_RESTRICT coeffs, static inline void bw_comp_update_coeffs_ctrl(bw_comp_coeffs *BW_RESTRICT coeffs) { bw_env_follow_update_coeffs_ctrl(&coeffs->env_follow_coeffs); - bw_vol_update_coeffs_ctrl(&coeffs->vol_coeffs); + bw_gain_update_coeffs_ctrl(&coeffs->gain_coeffs); } static inline void bw_comp_update_coeffs_audio(bw_comp_coeffs *BW_RESTRICT coeffs) { bw_env_follow_update_coeffs_audio(&coeffs->env_follow_coeffs); - bw_vol_update_coeffs_audio(&coeffs->vol_coeffs); + bw_gain_update_coeffs_audio(&coeffs->gain_coeffs); bw_one_pole_process1(&coeffs->smooth_coeffs, &coeffs->smooth_thresh_state, coeffs->thresh); coeffs->kc = 1.f - bw_one_pole_process1(&coeffs->smooth_coeffs, &coeffs->smooth_ratio_state, coeffs->ratio); } @@ -245,7 +247,7 @@ static inline float bw_comp_process1(const bw_comp_coeffs *BW_RESTRICT coeffs, b const float env = bw_env_follow_process1(&coeffs->env_follow_coeffs, &state->env_follow_state, x_sc); const float thresh = bw_one_pole_get_y_z1(&coeffs->smooth_thresh_state); const float y = env > thresh ? bw_pow2f_3(coeffs->kc * bw_log2f_3(thresh * bw_rcpf_2(env))) * x : x; - return bw_vol_process1(&coeffs->vol_coeffs, y); + return bw_gain_process1(&coeffs->gain_coeffs, y); } static inline void bw_comp_process(bw_comp_coeffs *BW_RESTRICT coeffs, bw_comp_state *BW_RESTRICT state, const float *x, const float *x_sc, float *y, int n_samples) { @@ -277,11 +279,11 @@ static inline void bw_comp_set_release_tau(bw_comp_coeffs *BW_RESTRICT coeffs, f } static inline void bw_comp_set_gain_lin(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { - bw_vol_set_volume_lin(&coeffs->vol_coeffs, value); + bw_gain_set_gain_lin(&coeffs->gain_coeffs, value); } static inline void bw_comp_set_gain_dB(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { - bw_vol_set_volume_dB(&coeffs->vol_coeffs, value); + bw_gain_set_gain_dB(&coeffs->gain_coeffs, value); } #ifdef __cplusplus diff --git a/include/bw_vol.h b/include/bw_gain.h similarity index 57% rename from include/bw_vol.h rename to include/bw_gain.h index 8970d26..cb48410 100644 --- a/include/bw_vol.h +++ b/include/bw_gain.h @@ -23,13 +23,14 @@ * version {{{ 0.3.0 }}} * requires {{{ bw_config bw_common bw_math bw_one_pole }}} * description {{{ - * Volume control. + * Gain. * }}} * changelog {{{ *
    *
  • Version 0.3.0: *
      - *
    • Changed volume parameter API to express values in linear gain + *
    • Renamed as bw_gain.
    • + *
    • Changed gain parameter API to express values in linear gain * and dB.
    • *
    *
  • @@ -47,8 +48,8 @@ * }}} */ -#ifndef _BW_VOL_H -#define _BW_VOL_H +#ifndef _BW_GAIN_H +#define _BW_GAIN_H #ifdef __cplusplus extern "C" { @@ -57,71 +58,70 @@ extern "C" { #include /*! api {{{ - * #### bw_vol_coeffs + * #### bw_gain_coeffs * ```>>> */ -typedef struct _bw_vol_coeffs bw_vol_coeffs; +typedef struct _bw_gain_coeffs bw_gain_coeffs; /*! <<<``` * Coefficients and related. * - * #### bw_vol_init() + * #### bw_gain_init() * ```>>> */ -static inline void bw_vol_init(bw_vol_coeffs *BW_RESTRICT coeffs); +static inline void bw_gain_init(bw_gain_coeffs *BW_RESTRICT coeffs); /*! <<<``` * Initializes input parameter values in `coeffs`. * - * #### bw_vol_set_sample_rate() + * #### bw_gain_set_sample_rate() * ```>>> */ -static inline void bw_vol_set_sample_rate(bw_vol_coeffs *BW_RESTRICT coeffs, float sample_rate); +static inline void bw_gain_set_sample_rate(bw_gain_coeffs *BW_RESTRICT coeffs, float sample_rate); /*! <<<``` * Sets the `sample_rate` (Hz) value in `coeffs`. * - * #### bw_vol_reset_coeffs() + * #### bw_gain_reset_coeffs() * ```>>> */ -static inline void bw_vol_reset_coeffs(bw_vol_coeffs *BW_RESTRICT coeffs); +static inline void bw_gain_reset_coeffs(bw_gain_coeffs *BW_RESTRICT coeffs); /*! <<<``` * Resets coefficients in `coeffs` to assume their target values. * - * #### bw_vol_update_coeffs_ctrl() + * #### bw_gain_update_coeffs_ctrl() * ```>>> */ -static inline void bw_vol_update_coeffs_ctrl(bw_vol_coeffs *BW_RESTRICT coeffs); +static inline void bw_gain_update_coeffs_ctrl(bw_gain_coeffs *BW_RESTRICT coeffs); /*! <<<``` * Triggers control-rate update of coefficients in `coeffs`. * - * #### bw_vol_update_coeffs_audio() + * #### bw_gain_update_coeffs_audio() * ```>>> */ -static inline void bw_vol_update_coeffs_audio(bw_vol_coeffs *BW_RESTRICT coeffs); +static inline void bw_gain_update_coeffs_audio(bw_gain_coeffs *BW_RESTRICT coeffs); /*! <<<``` * Triggers audio-rate update of coefficients in `coeffs`. * - * #### bw_vol_process1() + * #### bw_gain_process1() * ```>>> */ -static inline float bw_vol_process1(const bw_vol_coeffs *BW_RESTRICT coeffs, float x); +static inline float bw_gain_process1(const bw_gain_coeffs *BW_RESTRICT coeffs, float x); /*! <<<``` * Processes one input sample `x` using `coeffs` and returns the * corresponding output sample. * - * #### bw_vol_process() + * #### bw_gain_process() * ```>>> */ -static inline void bw_vol_process(bw_vol_coeffs *BW_RESTRICT coeffs, const float *x, float *y, int n_samples); +static inline void bw_gain_process(bw_gain_coeffs *BW_RESTRICT coeffs, const float *x, float *y, int n_samples); /*! <<<``` * Processes the first `n_samples` of the input buffer `x` and fills the * first `n_samples` of the output buffer `y`, while using and updating * `coeffs` (control and audio rate). * - * #### bw_vol_set_volume_lin() + * #### bw_gain_set_gain_lin() * ```>>> */ -static inline void bw_vol_set_volume_lin(bw_vol_coeffs *BW_RESTRICT coeffs, float value); +static inline void bw_gain_set_gain_lin(bw_gain_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` - * Sets the volume parameter to the given `value` (linear gain) in - * `coeffs`. + * Sets the gain parameter to the given `value` (linear gain) in `coeffs`. * * Default value: `1.f`. * - * #### bw_vol_set_volume_dB() + * #### bw_gain_set_gain_dB() * ```>>> */ -static inline void bw_vol_set_volume_dB(bw_vol_coeffs *BW_RESTRICT coeffs, float value); +static inline void bw_gain_set_gain_dB(bw_gain_coeffs *BW_RESTRICT coeffs, float value); /*! <<<``` - * Sets the volume parameter to the given `value` (dB) in `coeffs`. + * Sets the gain parameter to the given `value` (dB) in `coeffs`. * * Default value: `0.f`. * }}} */ @@ -134,54 +134,54 @@ static inline void bw_vol_set_volume_dB(bw_vol_coeffs *BW_RESTRICT coeffs, float #include #include -struct _bw_vol_coeffs { +struct _bw_gain_coeffs { // Sub-components bw_one_pole_coeffs smooth_coeffs; bw_one_pole_state smooth_state; // Parameters - float volume; + float gain; }; -static inline void bw_vol_init(bw_vol_coeffs *BW_RESTRICT coeffs) { +static inline void bw_gain_init(bw_gain_coeffs *BW_RESTRICT coeffs) { bw_one_pole_init(&coeffs->smooth_coeffs); bw_one_pole_set_tau(&coeffs->smooth_coeffs, 0.05f); - coeffs->volume = 1.f; + coeffs->gain = 1.f; } -static inline void bw_vol_set_sample_rate(bw_vol_coeffs *BW_RESTRICT coeffs, float sample_rate) { +static inline void bw_gain_set_sample_rate(bw_gain_coeffs *BW_RESTRICT coeffs, float sample_rate) { bw_one_pole_set_sample_rate(&coeffs->smooth_coeffs, sample_rate); bw_one_pole_reset_coeffs(&coeffs->smooth_coeffs); } -static inline void bw_vol_reset_coeffs(bw_vol_coeffs *BW_RESTRICT coeffs) { - bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->volume); +static inline void bw_gain_reset_coeffs(bw_gain_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->gain); } -static inline void bw_vol_update_coeffs_ctrl(bw_vol_coeffs *BW_RESTRICT coeffs) { +static inline void bw_gain_update_coeffs_ctrl(bw_gain_coeffs *BW_RESTRICT coeffs) { } -static inline void bw_vol_update_coeffs_audio(bw_vol_coeffs *BW_RESTRICT coeffs) { - bw_one_pole_process1(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->volume); +static inline void bw_gain_update_coeffs_audio(bw_gain_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_process1(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->gain); } -static inline float bw_vol_process1(const bw_vol_coeffs *BW_RESTRICT coeffs, float x) { +static inline float bw_gain_process1(const bw_gain_coeffs *BW_RESTRICT coeffs, float x) { return bw_one_pole_get_y_z1(&coeffs->smooth_state) * x; } -static inline void bw_vol_process(bw_vol_coeffs *BW_RESTRICT coeffs, const float *x, float *y, int n_samples) { +static inline void bw_gain_process(bw_gain_coeffs *BW_RESTRICT coeffs, const float *x, float *y, int n_samples) { for (int i = 0; i < n_samples; i++) { - bw_vol_update_coeffs_audio(coeffs); - y[i] = bw_vol_process1(coeffs, x[i]); + bw_gain_update_coeffs_audio(coeffs); + y[i] = bw_gain_process1(coeffs, x[i]); } } -static inline void bw_vol_set_volume_lin(bw_vol_coeffs *BW_RESTRICT coeffs, float value) { - coeffs->volume = value; +static inline void bw_gain_set_gain_lin(bw_gain_coeffs *BW_RESTRICT coeffs, float value) { + coeffs->gain = value; } -static inline void bw_vol_set_volume_dB(bw_vol_coeffs *BW_RESTRICT coeffs, float value) { - coeffs->volume = bw_dB2linf_3(value); +static inline void bw_gain_set_gain_dB(bw_gain_coeffs *BW_RESTRICT coeffs, float value) { + coeffs->gain = bw_dB2linf_3(value); } #ifdef __cplusplus diff --git a/include/bw_lowpass1.h b/include/bw_lowpass1.h new file mode 100644 index 0000000..2f8c87d --- /dev/null +++ b/include/bw_lowpass1.h @@ -0,0 +1,215 @@ +/* + * 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 + * along with Brickworks. If not, see . + * + * File author: Stefano D'Angelo + */ + +/*! + * module_type {{{ dsp }}} + * version {{{ 0.3.0 }}} + * requires {{{ bw_config bw_common bw_math bw_one_pole }}} + * description {{{ + * First-order lowpass filter (6 dB/oct) with unitary DC gain. + * + * This is better suited to filtering actual audio than + * [bw_one_pole](bw_one_pole). + * }}} + * changelog {{{ + *
      + *
    • Version 0.3.0: + *
        + *
      • First release.
      • + *
      + *
    • + *
    + * }}} + */ + +#ifndef _BW_LOWPASS1_H +#define _BW_LOWPASS1_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/*! api {{{ + * #### bw_lowpass1_coeffs + * ```>>> */ +typedef struct _bw_lowpass1_coeffs bw_lowpass1_coeffs; +/*! <<<``` + * Coefficients and related. + * + * #### bw_lowpass1_state + * ```>>> */ +typedef struct _bw_lowpass1_state bw_lowpass1_state; +/*! <<<``` + * Internal state and related. + * + * #### bw_lowpass1_init() + * ```>>> */ +static inline void bw_lowpass1_init(bw_lowpass1_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Initializes input parameter values in `coeffs`. + * + * #### bw_lowpass1_set_sample_rate() + * ```>>> */ +static inline void bw_lowpass1_set_sample_rate(bw_lowpass1_coeffs *BW_RESTRICT coeffs, float sample_rate); +/*! <<<``` + * Sets the `sample_rate` (Hz) value in `coeffs`. + * + * #### bw_lowpass1_reset_coeffs() + * ```>>> */ +static inline void bw_lowpass1_reset_coeffs(bw_lowpass1_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Resets coefficients in `coeffs` to assume their target values. + * + * #### bw_lowpass1_reset_state() + * ```>>> */ +static inline void bw_lowpass1_reset_state(const bw_lowpass1_coeffs *BW_RESTRICT coeffs, bw_lowpass1_state *BW_RESTRICT state); +/*! <<<``` + * Resets the given `state` to its initial values using the given `coeffs`. + * + * #### bw_lowpass1_update_coeffs_ctrl() + * ```>>> */ +static inline void bw_lowpass1_update_coeffs_ctrl(bw_lowpass1_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Triggers control-rate update of coefficients in `coeffs`. + * + * #### bw_lowpass1_update_coeffs_audio() + * ```>>> */ +static inline void bw_lowpass1_update_coeffs_audio(bw_lowpass1_coeffs *BW_RESTRICT coeffs); +/*! <<<``` + * Triggers audio-rate update of coefficients in `coeffs`. + * + * #### bw_lowpass1_process1() + * ```>>> */ +static inline float bw_lowpass1_process1(const bw_lowpass1_coeffs *BW_RESTRICT coeffs, bw_lowpass1_state *BW_RESTRICT state, float x); +/*! <<<``` + * Processes one input sample `x` using `coeffs`, while using and updating + * `state`. Returns the corresponding output sample. + * + * #### bw_lowpass1_process() + * ```>>> */ +static inline void bw_lowpass1_process(bw_lowpass1_coeffs *BW_RESTRICT coeffs, bw_lowpass1_state *BW_RESTRICT state, const float *x, float *y, int n_samples); +/*! <<<``` + * Processes the first `n_samples` of the input buffer `x` and fills the + * first `n_samples` of the output buffer `y`, while using and updating both + * `coeffs` and `state` (control and audio rate). + * + * #### bw_lowpass1_set_cutoff() + * ```>>> */ +static inline void bw_lowpass1_set_cutoff(bw_lowpass1_coeffs *BW_RESTRICT coeffs, float value); +/*! <<<``` + * Sets the cutoff frequency `value` (Hz) in `coeffs`. + * + * Default value: `1e3f`. + * }}} */ + +/*** 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 +#include + +struct _bw_lowpass1_coeffs { + // Sub-components + bw_one_pole_coeffs smooth_coeffs; + bw_one_pole_state smooth_state; + + // Coefficients + float t_k; + + // Parameters + float cutoff; +}; + +struct _bw_lowpass1_state { + float y_z1; + float X_z1; +}; + +static inline void bw_lowpass1_init(bw_lowpass1_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_init(&coeffs->smooth_coeffs); + bw_one_pole_set_tau(&coeffs->smooth_coeffs, 0.005f); + bw_one_pole_set_sticky_thresh(&coeffs->smooth_coeffs, 1e-3f); + coeffs->cutoff = 1e3f; +} + +static inline void bw_lowpass1_set_sample_rate(bw_lowpass1_coeffs *BW_RESTRICT coeffs, float sample_rate) { + bw_one_pole_set_sample_rate(&coeffs->smooth_coeffs, sample_rate); + bw_one_pole_reset_coeffs(&coeffs->smooth_coeffs); + coeffs->t_k = 3.141592653589793f / sample_rate; +} + +static inline void _bw_lowpass1_do_update_coeffs(bw_svf_coeffs *BW_RESTRICT coeffs, char force) { + float cutoff_cur = bw_one_pole_get_y_z1(&coeffs->smooth_state); + const char cutoff_changed = force || coeffs->cutoff != cutoff_cur; + if (cutoff_changed) { + cutoff_cur = bw_one_pole_process1_sticky_rel(&coeffs->smooth_coeffs, &coeffs->smooth_cutoff_state, coeffs->cutoff); + coeffs->t = bw_tanf_3(coeffs->t_k * cutoff_cur); + const float k = bw_rcpf_2(1.f + coeffs->t); + coeffs->X_x = k * cutoff_cur; + coeffs->X_X_z1 = k * coeffs->t; + coeffs->y_X = bw_rcpf_2(cutoff_cur); + } +} + +static inline void bw_lowpass1_reset_coeffs(bw_lowpass1_coeffs *BW_RESTRICT coeffs) { + bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->cutoff); + _bw_lowpass1_do_update_coeffs(coeffs, 1); +} + +static inline void bw_lowpass1_reset_state(const bw_lowpass1_coeffs *BW_RESTRICT coeffs, bw_lowpass1_state *BW_RESTRICT state) { + state->y_z1 = 0.f; + state->X_z1 = 0.f; +} + +static inline void bw_lowpass1_update_coeffs_ctrl(bw_lowpass1_coeffs *BW_RESTRICT coeffs) { +} + +static inline void bw_lowpass1_update_coeffs_audio(bw_lowpass1_coeffs *BW_RESTRICT coeffs) { + _bw_lowpass1_do_update_coeffs(coeffs, 0); +} + +static inline float bw_lowpass1_process1(const bw_lowpass1_coeffs *BW_RESTRICT coeffs, bw_lowpass1_state *BW_RESTRICT state, float x) { + const float X = coeffs->X_x * (x - state->y_z1) - coeffs->X_X_z1 * state->X_z1; + const float y = x - coeffs->y_f * X; + state->y_z1 = y; + state->X_z1 = X; + return y; +} + +static inline void bw_lowpass1_process(bw_lowpass1_coeffs *BW_RESTRICT coeffs, bw_lowpass1_state *BW_RESTRICT state, const float *x, float *y, int n_samples) { + for (int i = 0; i < n_samples; i++) { + bw_lowpass1_update_coeffs_audio(coeffs); + y[i] = bw_lowpass1_process1(coeffs, state, x[i]); + } +} + +static inline void bw_lowpass1_set_cutoff(bw_lowpass1_coeffs *BW_RESTRICT coeffs, float value) { + coeffs->cutoff = value; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/bw_one_pole.h b/include/bw_one_pole.h index a2578f4..f464a58 100644 --- a/include/bw_one_pole.h +++ b/include/bw_one_pole.h @@ -25,6 +25,9 @@ * description {{{ * One-pole (6 dB/oct) lowpass filter with unitary DC gain, separate attack * and decay time constants, and sticky target-reach threshold. + * + * This is better suited to implement smoothing than + * [bw_lowpass1](bw_lowpass1). * }}} * changelog {{{ *