removed bw_allpass* + renamed bw_vol to bw_gain + new bw_lowpass1

This commit is contained in:
Stefano D'Angelo 2022-12-20 08:35:28 +01:00
parent a23ee901a2
commit 2096a877aa
11 changed files with 335 additions and 574 deletions

4
TODO
View File

@ -15,8 +15,8 @@ code:
* fix vst3 mapped values (visible in Ableton Live) and short names * fix vst3 mapped values (visible in Ableton Live) and short names
* polish examples (ranges, etc.) * polish examples (ranges, etc.)
* change name of vst3 template folders to something that doesn't look like a vst3 folder itself * 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) * compute bit depth reduction only when input changes? (state, option?)
* common smoothing policy (as control rate as possible?) * common smoothing policy (as control rate as possible?) - smoothing control?
* avoid "force" in coeffs update by using inline functions? * avoid "force" in coeffs update by using inline functions?
build system: build system:

View File

@ -37,7 +37,7 @@
#include <bw_pink_filt.h> #include <bw_pink_filt.h>
#include <bw_svf.h> #include <bw_svf.h>
#include <bw_env_gen.h> #include <bw_env_gen.h>
#include <bw_vol.h> #include <bw_gain.h>
#include <bw_env_follow.h> #include <bw_env_follow.h>
enum { enum {
@ -50,21 +50,21 @@ enum {
p_vco1_fine, p_vco1_fine,
p_vco1_waveform, p_vco1_waveform,
p_vco1_pw_slope, p_vco1_pw_slope,
p_vco1_volume, p_vco1_level,
p_vco2_mod, p_vco2_mod,
p_vco2_coarse, p_vco2_coarse,
p_vco2_fine, p_vco2_fine,
p_vco2_waveform, p_vco2_waveform,
p_vco2_pw_slope, p_vco2_pw_slope,
p_vco2_volume, p_vco2_level,
p_vco3_kbd, p_vco3_kbd,
p_vco3_coarse, p_vco3_coarse,
p_vco3_fine, p_vco3_fine,
p_vco3_waveform, p_vco3_waveform,
p_vco3_pw_slope, p_vco3_pw_slope,
p_vco3_volume, p_vco3_level,
p_noise_color, p_noise_color,
p_noise_volume, p_noise_level,
p_vcf_mod, p_vcf_mod,
p_vcf_kbd_ctrl, p_vcf_kbd_ctrl,
p_vcf_cutoff, p_vcf_cutoff,
@ -91,22 +91,22 @@ struct _bw_example_synth_mono {
bw_phase_gen_state vco1_phase_gen_state; bw_phase_gen_state vco1_phase_gen_state;
bw_osc_pulse_coeffs vco1_pulse_coeffs; bw_osc_pulse_coeffs vco1_pulse_coeffs;
bw_osc_tri_coeffs vco1_tri_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_coeffs vco2_phase_gen_coeffs;
bw_phase_gen_state vco2_phase_gen_state; bw_phase_gen_state vco2_phase_gen_state;
bw_osc_pulse_coeffs vco2_pulse_coeffs; bw_osc_pulse_coeffs vco2_pulse_coeffs;
bw_osc_tri_coeffs vco2_tri_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_coeffs vco3_phase_gen_coeffs;
bw_phase_gen_state vco3_phase_gen_state; bw_phase_gen_state vco3_phase_gen_state;
bw_osc_pulse_coeffs vco3_pulse_coeffs; bw_osc_pulse_coeffs vco3_pulse_coeffs;
bw_osc_tri_coeffs vco3_tri_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_osc_filt_state osc_filt_state;
bw_noise_gen_coeffs noise_gen_coeffs; bw_noise_gen_coeffs noise_gen_coeffs;
bw_pink_filt_coeffs pink_filt_coeffs; bw_pink_filt_coeffs pink_filt_coeffs;
bw_pink_filt_state pink_filt_state; 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_coeffs vcf_env_gen_coeffs;
bw_env_gen_state vcf_env_gen_state; bw_env_gen_state vcf_env_gen_state;
bw_svf_coeffs vcf_coeffs; bw_svf_coeffs vcf_coeffs;
@ -115,7 +115,7 @@ struct _bw_example_synth_mono {
bw_env_gen_state vca_env_gen_state; bw_env_gen_state vca_env_gen_state;
bw_phase_gen_coeffs a440_phase_gen_coeffs; bw_phase_gen_coeffs a440_phase_gen_coeffs;
bw_phase_gen_state a440_phase_gen_state; 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_coeffs env_follow_coeffs;
bw_env_follow_state env_follow_state; 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_phase_gen_init(&instance->vco1_phase_gen_coeffs);
bw_osc_pulse_init(&instance->vco1_pulse_coeffs); bw_osc_pulse_init(&instance->vco1_pulse_coeffs);
bw_osc_tri_init(&instance->vco1_tri_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_phase_gen_init(&instance->vco2_phase_gen_coeffs);
bw_osc_pulse_init(&instance->vco2_pulse_coeffs); bw_osc_pulse_init(&instance->vco2_pulse_coeffs);
bw_osc_tri_init(&instance->vco2_tri_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_phase_gen_init(&instance->vco3_phase_gen_coeffs);
bw_osc_pulse_init(&instance->vco3_pulse_coeffs); bw_osc_pulse_init(&instance->vco3_pulse_coeffs);
bw_osc_tri_init(&instance->vco3_tri_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_noise_gen_init(&instance->noise_gen_coeffs, &instance->rand_state);
bw_pink_filt_init(&instance->pink_filt_coeffs); 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_env_gen_init(&instance->vcf_env_gen_coeffs);
bw_svf_init(&instance->vcf_coeffs); bw_svf_init(&instance->vcf_coeffs);
bw_env_gen_init(&instance->vca_env_gen_coeffs); bw_env_gen_init(&instance->vca_env_gen_coeffs);
bw_phase_gen_init(&instance->a440_phase_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_env_follow_init(&instance->env_follow_coeffs);
bw_osc_saw_set_antialiasing(&instance->vco_saw_coeffs, 1); 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_tri_set_antialiasing(&instance->vco1_tri_coeffs, 1);
bw_osc_pulse_set_antialiasing(&instance->vco2_pulse_coeffs, 1); bw_osc_pulse_set_antialiasing(&instance->vco2_pulse_coeffs, 1);
bw_osc_tri_set_antialiasing(&instance->vco2_tri_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_pulse_set_antialiasing(&instance->vco3_pulse_coeffs, 1);
bw_osc_tri_set_antialiasing(&instance->vco3_tri_coeffs, 1); bw_osc_tri_set_antialiasing(&instance->vco3_tri_coeffs, 1);
bw_vol_set_volume_lin(&instance->vco3_vol_coeffs, 0.f); bw_gain_set_gain_lin(&instance->vco3_gain_coeffs, 0.f);
bw_vol_set_volume_lin(&instance->noise_vol_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_phase_gen_set_frequency(&instance->a440_phase_gen_coeffs, 440.f);
bw_env_follow_set_release_tau(&instance->env_follow_coeffs, 1.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_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_pulse_set_sample_rate(&instance->vco1_pulse_coeffs, sample_rate);
bw_osc_tri_set_sample_rate(&instance->vco1_tri_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_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_pulse_set_sample_rate(&instance->vco2_pulse_coeffs, sample_rate);
bw_osc_tri_set_sample_rate(&instance->vco2_tri_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_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_pulse_set_sample_rate(&instance->vco3_pulse_coeffs, sample_rate);
bw_osc_tri_set_sample_rate(&instance->vco3_tri_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_noise_gen_set_sample_rate(&instance->noise_gen_coeffs, sample_rate);
bw_pink_filt_set_sample_rate(&instance->pink_filt_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_env_gen_set_sample_rate(&instance->vcf_env_gen_coeffs, sample_rate);
bw_svf_set_sample_rate(&instance->vcf_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_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_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); 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_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_pulse_reset_coeffs(&instance->vco1_pulse_coeffs);
bw_osc_tri_reset_coeffs(&instance->vco1_tri_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_coeffs(&instance->vco2_phase_gen_coeffs);
bw_phase_gen_reset_state(&instance->vco2_phase_gen_coeffs, &instance->vco2_phase_gen_state, 0.f); 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_pulse_reset_coeffs(&instance->vco2_pulse_coeffs);
bw_osc_tri_reset_coeffs(&instance->vco2_tri_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_coeffs(&instance->vco3_phase_gen_coeffs);
bw_phase_gen_reset_state(&instance->vco3_phase_gen_coeffs, &instance->vco3_phase_gen_state, 0.f); 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_pulse_reset_coeffs(&instance->vco3_pulse_coeffs);
bw_osc_tri_reset_coeffs(&instance->vco3_tri_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_osc_filt_reset_state(&instance->osc_filt_state);
bw_pink_filt_reset_state(&instance->pink_filt_coeffs, &instance->pink_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_coeffs(&instance->vcf_env_gen_coeffs);
bw_env_gen_reset_state(&instance->vcf_env_gen_coeffs, &instance->vcf_env_gen_state); bw_env_gen_reset_state(&instance->vcf_env_gen_coeffs, &instance->vcf_env_gen_state);
bw_svf_reset_coeffs(&instance->vcf_coeffs); 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_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_coeffs(&instance->a440_phase_gen_coeffs);
bw_phase_gen_reset_state(&instance->a440_phase_gen_coeffs, &instance->a440_phase_gen_state, 0.f); 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_coeffs(&instance->env_follow_coeffs);
bw_env_follow_reset_state(&instance->env_follow_coeffs, &instance->env_follow_state); bw_env_follow_reset_state(&instance->env_follow_coeffs, &instance->env_follow_state);
instance->note = 60; 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_osc_tri_reset_coeffs(&instance->vco2_tri_coeffs);
} }
bw_vol_process(&instance->vco1_vol_coeffs, instance->buf[2], instance->buf[2], n); bw_gain_process(&instance->vco1_gain_coeffs, instance->buf[2], instance->buf[2], n);
bw_vol_process(&instance->vco2_vol_coeffs, instance->buf[1], instance->buf[1], n); bw_gain_process(&instance->vco2_gain_coeffs, instance->buf[1], instance->buf[1], n);
bw_vol_process(&instance->vco3_vol_coeffs, out, out, n); bw_gain_process(&instance->vco3_gain_coeffs, out, out, n);
bw_vol_process(&instance->noise_vol_coeffs, instance->buf[0], instance->buf[0], n); bw_gain_process(&instance->noise_gain_coeffs, instance->buf[0], instance->buf[0], n);
for (int j = 0; j < n; j++) for (int j = 0; j < n; j++)
out[j] = out[j] + instance->buf[1][j] + instance->buf[2][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++) for (int j = 0; j < n; j++)
out[j] += instance->buf[0][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); 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; instance->params[index] = value;
switch (index) { switch (index) {
case p_volume: 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; break;
case p_portamento: case p_portamento:
bw_phase_gen_set_portamento_tau(&instance->vco1_phase_gen_coeffs, value); 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_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)); bw_osc_tri_set_slope(&instance->vco1_tri_coeffs, bw_clipf(value, 0.001f, 0.999f));
break; break;
case p_vco1_volume: case p_vco1_level:
bw_vol_set_volume_lin(&instance->vco1_vol_coeffs, value * value * value); bw_gain_set_gain_lin(&instance->vco1_gain_coeffs, value * value * value);
break; break;
case p_vco2_pw_slope: case p_vco2_pw_slope:
bw_osc_pulse_set_pulse_width(&instance->vco2_pulse_coeffs, value); 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)); bw_osc_tri_set_slope(&instance->vco2_tri_coeffs, bw_clipf(value, 0.001f, 0.999f));
break; break;
case p_vco2_volume: case p_vco2_level:
bw_vol_set_volume_lin(&instance->vco2_vol_coeffs, value * value * value); bw_gain_set_gain_lin(&instance->vco2_gain_coeffs, value * value * value);
break; break;
case p_vco3_pw_slope: case p_vco3_pw_slope:
bw_osc_pulse_set_pulse_width(&instance->vco3_pulse_coeffs, value); 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)); bw_osc_tri_set_slope(&instance->vco3_tri_coeffs, bw_clipf(value, 0.001f, 0.999f));
break; break;
case p_vco3_volume: case p_vco3_level:
bw_vol_set_volume_lin(&instance->vco3_vol_coeffs, value * value * value); bw_gain_set_gain_lin(&instance->vco3_gain_coeffs, value * value * value);
break; break;
case p_noise_volume: case p_noise_level:
bw_vol_set_volume_lin(&instance->noise_vol_coeffs, value * value * value); bw_gain_set_gain_lin(&instance->noise_gain_coeffs, value * value * value);
break; break;
case p_vcf_Q: case p_vcf_Q:
bw_svf_set_Q(&instance->vcf_coeffs, 0.5f + 9.5f * value); bw_svf_set_Q(&instance->vcf_coeffs, 0.5f + 9.5f * value);

View File

@ -74,21 +74,21 @@ static struct config_parameter config_parameters[NUM_PARAMETERS] = {
{ "VCO1 fine", "VCO1 fine", "st", 0, 0, 0, 0.5f }, { "VCO1 fine", "VCO1 fine", "st", 0, 0, 0, 0.5f },
{ "VCO1 waveform", "VCO1 wave", "", 0, 0, 2, 0.f }, { "VCO1 waveform", "VCO1 wave", "", 0, 0, 2, 0.f },
{ "VCO1 pulse width/slope", "VCO1 pw/slope", "%", 0, 0, 0, 0.5f }, { "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 modulation", "VCO2 mod", "%", 0, 0, 0, 0.f },
{ "VCO2 coarse", "VCO2 coarse", "", 0, 0, 6, 0.5f }, { "VCO2 coarse", "VCO2 coarse", "", 0, 0, 6, 0.5f },
{ "VCO2 fine", "VCO2 fine", "st", 0, 0, 0, 0.5f }, { "VCO2 fine", "VCO2 fine", "st", 0, 0, 0, 0.5f },
{ "VCO2 waveform", "VCO2 wave", "", 0, 0, 2, 0.f }, { "VCO2 waveform", "VCO2 wave", "", 0, 0, 2, 0.f },
{ "VCO2 pulse width/slope", "VCO2 pw/slope", "%", 0, 0, 0, 0.5f }, { "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 kyboard control", "VCO3 kbd ctrl", "", 0, 0, 1, 1.f },
{ "VCO3 coarse", "VCO3 coarse", "", 0, 0, 6, 0.5f }, { "VCO3 coarse", "VCO3 coarse", "", 0, 0, 6, 0.5f },
{ "VCO3 fine", "VCO3 fine", "st", 0, 0, 0, 0.5f }, { "VCO3 fine", "VCO3 fine", "st", 0, 0, 0, 0.5f },
{ "VCO3 waveform", "VCO3 wave", "", 0, 0, 2, 0.f }, { "VCO3 waveform", "VCO3 wave", "", 0, 0, 2, 0.f },
{ "VCO3 pulse width/slope", "VCO3 pw/slope", "%", 0, 0, 0, 0.5f }, { "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 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 modulation", "VCF mod", "%", 0, 0, 0, 0.f },
{ "VCF keyboard control", "VCF kbd ctrl", "", 0, 0, 3, 0.f }, { "VCF keyboard control", "VCF kbd ctrl", "", 0, 0, 3, 0.f },
{ "VCF cutoff", "VCF cutoff", "Hz", 0, 0, 0, 1.f }, { "VCF cutoff", "VCF cutoff", "Hz", 0, 0, 0, 1.f },

View File

@ -74,7 +74,7 @@ var parameters = [
defaultValue: 0.5 defaultValue: 0.5
}, },
{ {
name: "VCO1 volume", name: "VCO1 level",
output: false, output: false,
defaultValue: 1.0 defaultValue: 1.0
}, },
@ -106,7 +106,7 @@ var parameters = [
defaultValue: 0.5 defaultValue: 0.5
}, },
{ {
name: "VCO2 volume", name: "VCO2 level",
output: false, output: false,
defaultValue: 0.0 defaultValue: 0.0
}, },
@ -139,7 +139,7 @@ var parameters = [
defaultValue: 0.5 defaultValue: 0.5
}, },
{ {
name: "VCO3 volume", name: "VCO3 level",
output: false, output: false,
defaultValue: 0.0 defaultValue: 0.0
}, },
@ -150,7 +150,7 @@ var parameters = [
step: 1 step: 1
}, },
{ {
name: "Noise volume", name: "Noise level",
output: false, output: false,
defaultValue: 0.0 defaultValue: 0.0
}, },

View File

@ -32,7 +32,7 @@
#include <bw_osc_filt.h> #include <bw_osc_filt.h>
#include <bw_svf.h> #include <bw_svf.h>
#include <bw_env_gen.h> #include <bw_env_gen.h>
#include <bw_vol.h> #include <bw_gain.h>
#include <bw_env_follow.h> #include <bw_env_follow.h>
enum { enum {
@ -61,7 +61,7 @@ struct _bw_example_synth_simple {
bw_svf_state svf_state; bw_svf_state svf_state;
bw_env_gen_coeffs env_gen_coeffs; bw_env_gen_coeffs env_gen_coeffs;
bw_env_gen_state env_gen_state; 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_coeffs env_follow_coeffs;
bw_env_follow_state env_follow_state; 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_osc_pulse_init(&instance->osc_pulse_coeffs);
bw_svf_init(&instance->svf_coeffs); bw_svf_init(&instance->svf_coeffs);
bw_env_gen_init(&instance->env_gen_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_env_follow_init(&instance->env_follow_coeffs);
bw_osc_pulse_set_antialiasing(&instance->osc_pulse_coeffs, 1); 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_osc_pulse_set_sample_rate(&instance->osc_pulse_coeffs, sample_rate);
bw_svf_set_sample_rate(&instance->svf_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_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); 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_svf_reset_state(&instance->svf_coeffs, &instance->svf_state);
bw_env_gen_reset_coeffs(&instance->env_gen_coeffs); bw_env_gen_reset_coeffs(&instance->env_gen_coeffs);
bw_env_gen_reset_state(&instance->env_gen_coeffs, &instance->env_gen_state); 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_coeffs(&instance->env_follow_coeffs);
bw_env_follow_reset_state(&instance->env_follow_coeffs, &instance->env_follow_state); bw_env_follow_reset_state(&instance->env_follow_coeffs, &instance->env_follow_state);
instance->note = -1; 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); bw_env_gen_process(&instance->env_gen_coeffs, &instance->env_gen_state, instance->buf, n);
for (int j = 0; j < n; j++) for (int j = 0; j < n; j++)
out[j] *= instance->buf[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); 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; instance->params[index] = value;
switch (index) { switch (index) {
case p_volume: 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; break;
case p_portamento: case p_portamento:
bw_phase_gen_set_portamento_tau(&instance->phase_gen_coeffs, value); bw_phase_gen_set_portamento_tau(&instance->phase_gen_coeffs, value);

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 {{{
* <ul>
* <li>Version <strong>0.3.0</strong>:
* <ul>
* <li>First release.</li>
* </ul>
* </li>
* </ul>
* }}}
*/
#ifndef _BW_ALLPASS1_H
#define _BW_ALLPASS1_H
#ifdef __cplusplus
extern "C" {
#endif
#include <bw_common.h>
/*! 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 <bw_math.h>
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

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 {{{
* <ul>
* <li>Version <strong>0.3.0</strong>:
* <ul>
* <li>First release.</li>
* </ul>
* </li>
* </ul>
* }}}
*/
#ifndef _BW_ALLPASS2_H
#define _BW_ALLPASS2_H
#ifdef __cplusplus
extern "C" {
#endif
#include <bw_common.h>
/*! 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 <bw_math.h>
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

View File

@ -21,7 +21,9 @@
/*! /*!
* module_type {{{ dsp }}} * module_type {{{ dsp }}}
* version {{{ 0.3.0 }}} * 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 {{{ * description {{{
* Feedforward compressor/limiter with independent sidechain input. * 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 <bw_math.h> #include <bw_math.h>
#include <bw_env_follow.h> #include <bw_env_follow.h>
#include <bw_vol.h> #include <bw_gain.h>
#include <bw_one_pole.h> #include <bw_one_pole.h>
struct _bw_comp_coeffs { struct _bw_comp_coeffs {
// Sub-components // Sub-components
bw_env_follow_coeffs env_follow_coeffs; 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_coeffs smooth_coeffs;
bw_one_pole_state smooth_thresh_state; bw_one_pole_state smooth_thresh_state;
bw_one_pole_state smooth_ratio_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) { static inline void bw_comp_init(bw_comp_coeffs *BW_RESTRICT coeffs) {
bw_env_follow_init(&coeffs->env_follow_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); bw_one_pole_set_tau(&coeffs->smooth_coeffs, 0.05f);
coeffs->thresh = 1.f; coeffs->thresh = 1.f;
coeffs->ratio = 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) { 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_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_set_sample_rate(&coeffs->smooth_coeffs, sample_rate);
bw_one_pole_reset_coeffs(&coeffs->smooth_coeffs); bw_one_pole_reset_coeffs(&coeffs->smooth_coeffs);
} }
static inline void bw_comp_reset_coeffs(bw_comp_coeffs *BW_RESTRICT coeffs) { static inline void bw_comp_reset_coeffs(bw_comp_coeffs *BW_RESTRICT coeffs) {
bw_env_follow_reset_coeffs(&coeffs->env_follow_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_thresh_state, coeffs->thresh);
bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_ratio_state, coeffs->ratio); 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) { 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_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) { 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_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); 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); 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 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 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; 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) { 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) { 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) { 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 #ifdef __cplusplus

View File

@ -23,13 +23,14 @@
* version {{{ 0.3.0 }}} * version {{{ 0.3.0 }}}
* requires {{{ bw_config bw_common bw_math bw_one_pole }}} * requires {{{ bw_config bw_common bw_math bw_one_pole }}}
* description {{{ * description {{{
* Volume control. * Gain.
* }}} * }}}
* changelog {{{ * changelog {{{
* <ul> * <ul>
* <li>Version <strong>0.3.0</strong>: * <li>Version <strong>0.3.0</strong>:
* <ul> * <ul>
* <li>Changed volume parameter API to express values in linear gain * <li>Renamed as bw_gain.</li>
* <li>Changed gain parameter API to express values in linear gain
* and dB.</li> * and dB.</li>
* </ul> * </ul>
* </li> * </li>
@ -47,8 +48,8 @@
* }}} * }}}
*/ */
#ifndef _BW_VOL_H #ifndef _BW_GAIN_H
#define _BW_VOL_H #define _BW_GAIN_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -57,71 +58,70 @@ extern "C" {
#include <bw_common.h> #include <bw_common.h>
/*! api {{{ /*! 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. * 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`. * 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`. * 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. * 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`. * 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`. * 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 * Processes one input sample `x` using `coeffs` and returns the
* corresponding output sample. * 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 * 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 * first `n_samples` of the output buffer `y`, while using and updating
* `coeffs` (control and audio rate). * `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 * Sets the gain parameter to the given `value` (linear gain) in `coeffs`.
* `coeffs`.
* *
* Default value: `1.f`. * 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`. * Default value: `0.f`.
* }}} */ * }}} */
@ -134,54 +134,54 @@ static inline void bw_vol_set_volume_dB(bw_vol_coeffs *BW_RESTRICT coeffs, float
#include <bw_math.h> #include <bw_math.h>
#include <bw_one_pole.h> #include <bw_one_pole.h>
struct _bw_vol_coeffs { struct _bw_gain_coeffs {
// Sub-components // Sub-components
bw_one_pole_coeffs smooth_coeffs; bw_one_pole_coeffs smooth_coeffs;
bw_one_pole_state smooth_state; bw_one_pole_state smooth_state;
// Parameters // 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_init(&coeffs->smooth_coeffs);
bw_one_pole_set_tau(&coeffs->smooth_coeffs, 0.05f); 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_set_sample_rate(&coeffs->smooth_coeffs, sample_rate);
bw_one_pole_reset_coeffs(&coeffs->smooth_coeffs); bw_one_pole_reset_coeffs(&coeffs->smooth_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) {
bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->volume); 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) { 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->volume); 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; 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++) { for (int i = 0; i < n_samples; i++) {
bw_vol_update_coeffs_audio(coeffs); bw_gain_update_coeffs_audio(coeffs);
y[i] = bw_vol_process1(coeffs, x[i]); y[i] = bw_gain_process1(coeffs, x[i]);
} }
} }
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) {
coeffs->volume = value; coeffs->gain = value;
} }
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) {
coeffs->volume = bw_dB2linf_3(value); coeffs->gain = bw_dB2linf_3(value);
} }
#ifdef __cplusplus #ifdef __cplusplus

215
include/bw_lowpass1.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 {{{
* <ul>
* <li>Version <strong>0.3.0</strong>:
* <ul>
* <li>First release.</li>
* </ul>
* </li>
* </ul>
* }}}
*/
#ifndef _BW_LOWPASS1_H
#define _BW_LOWPASS1_H
#ifdef __cplusplus
extern "C" {
#endif
#include <bw_common.h>
/*! 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 <bw_math.h>
#include <bw_one_pole.h>
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

View File

@ -25,6 +25,9 @@
* description {{{ * description {{{
* One-pole (6 dB/oct) lowpass filter with unitary DC gain, separate attack * One-pole (6 dB/oct) lowpass filter with unitary DC gain, separate attack
* and decay time constants, and sticky target-reach threshold. * and decay time constants, and sticky target-reach threshold.
*
* This is better suited to implement smoothing than
* [bw_lowpass1](bw_lowpass1).
* }}} * }}}
* changelog {{{ * changelog {{{
* <ul> * <ul>