add prewarp ctrl in bw_{lp1,mm1}, used in bw_{l,h}s1, fixed bw_{l,h}s2
This commit is contained in:
parent
fe21e533f9
commit
1eeba2252a
2
TODO
2
TODO
@ -19,7 +19,7 @@ code:
|
||||
* common smoothing policy (as control rate as possible?) - smoothing control?
|
||||
* avoid "force" in coeffs update by using inline functions?
|
||||
* should rather use backward Euler in bw_onepole?
|
||||
* Q to slope and viceversa functions in 2nd order shelf filters?
|
||||
* Q to slope and viceversa functions in 2nd order shelf filters? keep updated values (seamless switch, syncrhonicity)?
|
||||
|
||||
build system:
|
||||
* make makefiles handle paths with spaces etc
|
||||
|
@ -150,6 +150,11 @@ static inline void bw_hs1_set_high_gain_dB(bw_hs1_coeffs *BW_RESTRICT coeffs, fl
|
||||
struct _bw_hs1_coeffs {
|
||||
// Sub-components
|
||||
bw_mm1_coeffs mm1_coeffs;
|
||||
|
||||
// Parameters
|
||||
float cutoff;
|
||||
float high_gain;
|
||||
char update;
|
||||
};
|
||||
|
||||
struct _bw_hs1_state {
|
||||
@ -158,15 +163,30 @@ struct _bw_hs1_state {
|
||||
|
||||
static inline void bw_hs1_init(bw_hs1_coeffs *BW_RESTRICT coeffs) {
|
||||
bw_mm1_init(&coeffs->mm1_coeffs);
|
||||
bw_mm1_set_prewarp_at_cutoff(&coeffs->mm1_coeffs, 0);
|
||||
bw_mm1_set_coeffs_x(&coeffs->mm1_coeffs, 0.f);
|
||||
bw_mm1_set_coeffs_lp(&coeffs->mm1_coeffs, 1.f);
|
||||
coeffs->cutoff = 1e3f;
|
||||
coeffs->dc_gain = 1.f;
|
||||
}
|
||||
|
||||
static inline void bw_hs1_set_sample_rate(bw_hs1_coeffs *BW_RESTRICT coeffs, float sample_rate) {
|
||||
bw_mm1_set_sample_rate(&coeffs->mm1_coeffs, sample_rate);
|
||||
}
|
||||
|
||||
static inline void _bw_hs1_update_mm1_params(bw_ls1_coeffs *BW_RESTRICT coeffs) {
|
||||
if (coeffs->update) {
|
||||
bw_mm1_set_cutoff(&coeffs->mm1_coeffs, coeffs->cutoff * bw_sqrtf_2(coeffs->dc_gain));
|
||||
bw_mm1_set_coeff_x(&coeffs->mm1_coeffs, coeffs->dc_gain);
|
||||
bw_mm1_set_coeff_lp(&coeffs->mm1_coeffs, 1.f - coeffs->dc_gain);
|
||||
bw_mm1_set_prewarp_freq(&coeffs->mm1_coeffs, coeffs->cutoff);
|
||||
coeffs->update = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_hs1_reset_coeffs(bw_hs1_coeffs *BW_RESTRICT coeffs) {
|
||||
coeffs->update = 1;
|
||||
_bw_hs1_update_mm1_params(coeffs);
|
||||
bw_mm1_reset_coeffs(&coeffs->mm1_coeffs);
|
||||
}
|
||||
|
||||
@ -175,6 +195,7 @@ static inline void bw_hs1_reset_state(const bw_hs1_coeffs *BW_RESTRICT coeffs, b
|
||||
}
|
||||
|
||||
static inline void bw_hs1_update_coeffs_ctrl(bw_hs1_coeffs *BW_RESTRICT coeffs) {
|
||||
_bw_hs1_update_mm1_params(coeffs);
|
||||
bw_mm1_update_coeffs_ctrl(&coeffs->mm1_coeffs);
|
||||
}
|
||||
|
||||
@ -195,12 +216,17 @@ static inline void bw_hs1_process(bw_hs1_coeffs *BW_RESTRICT coeffs, bw_hs1_stat
|
||||
}
|
||||
|
||||
static inline void bw_hs1_set_cutoff(bw_hs1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
bw_mm1_set_cutoff(&coeffs->mm1_coeffs, value);
|
||||
if (value != coeffs->cutoff) {
|
||||
coeffs->cutoff = value;
|
||||
coeffs->update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_hs1_set_high_gain_lin(bw_hs1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
bw_mm1_set_coeff_x(&coeffs->mm1_coeffs, value);
|
||||
bw_mm1_set_coeff_lp(&coeffs->mm1_coeffs, 1.f - value);
|
||||
if (value != coeffs->high_gain) {
|
||||
coeffs->high_gain = value;
|
||||
coeffs->update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_hs1_set_high_gain_dB(bw_hs1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
|
@ -213,17 +213,7 @@ static inline void bw_hs2_set_sample_rate(bw_hs2_coeffs *BW_RESTRICT coeffs, flo
|
||||
bw_mm2_set_sample_rate(&coeffs->mm2_coeffs, sample_rate);
|
||||
}
|
||||
|
||||
static inline void bw_hs2_reset_coeffs(bw_hs2_coeffs *BW_RESTRICT coeffs) {
|
||||
bw_mm2_reset_coeffs(&coeffs->mm2_coeffs);
|
||||
coeffs->param_changed = ~0;
|
||||
bw_hs2_update_coeffs_ctrl(coeffs);
|
||||
}
|
||||
|
||||
static inline void bw_hs2_reset_state(const bw_hs2_coeffs *BW_RESTRICT coeffs, bw_hs2_state *BW_RESTRICT state) {
|
||||
bw_mm2_reset_state(&coeffs->mm2_coeffs, &state->mm2_state);
|
||||
}
|
||||
|
||||
static inline void bw_hs2_update_coeffs_ctrl(bw_hs2_coeffs *BW_RESTRICT coeffs) {
|
||||
static inline void _bw_ls2_update_mm2_params(bw_ls1_coeffs *BW_RESTRICT coeffs) {
|
||||
if (coeffs->param_changed) {
|
||||
if (coeffs->param_changed & _BW_HS2_PARAM_GAIN) {
|
||||
coeffs->sg = bw_math_sqrtf_2(coeffs->gain);
|
||||
@ -244,6 +234,20 @@ static inline void bw_hs2_update_coeffs_ctrl(bw_hs2_coeffs *BW_RESTRICT coeffs)
|
||||
}
|
||||
coeffs->param_changed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_hs2_reset_coeffs(bw_hs2_coeffs *BW_RESTRICT coeffs) {
|
||||
coeffs->param_changed = ~0;
|
||||
_bw_hs2_update_mm2_params(coeffs);
|
||||
bw_mm2_reset_coeffs(&coeffs->mm2_coeffs);
|
||||
}
|
||||
|
||||
static inline void bw_hs2_reset_state(const bw_hs2_coeffs *BW_RESTRICT coeffs, bw_hs2_state *BW_RESTRICT state) {
|
||||
bw_mm2_reset_state(&coeffs->mm2_coeffs, &state->mm2_state);
|
||||
}
|
||||
|
||||
static inline void bw_hs2_update_coeffs_ctrl(bw_hs2_coeffs *BW_RESTRICT coeffs) {
|
||||
_bw_hs2_update_mm2_params(coeffs);
|
||||
bw_mm2_update_coeffs_ctrl(&coeffs->mm2_coeffs);
|
||||
}
|
||||
|
||||
|
@ -119,6 +119,25 @@ static inline void bw_lp1_set_cutoff(bw_lp1_coeffs *BW_RESTRICT coeffs, float va
|
||||
* Sets the cutoff frequency `value` (Hz) in `coeffs`.
|
||||
*
|
||||
* Default value: `1e3f`.
|
||||
*
|
||||
* #### bw_lp1_set_prewarp_at_cutoff()
|
||||
* ```>>> */
|
||||
static inline void bw_lp1_set_prewarp_at_cutoff(bw_lp1_coeffs *BW_RESTRICT coeffs, char value);
|
||||
/*! <<<```
|
||||
* Sets whether bilinear transform prewarping frequency should match the
|
||||
* cutoff frequency (non-`0`) or not (`0`).
|
||||
*
|
||||
* Default value: non-`0` (on).
|
||||
*
|
||||
* #### bw_lp1_set_prewarp_freq()
|
||||
* ```>>> */
|
||||
static inline void bw_lp1_set_prewarp_freq(bw_lp1_coeffs *BW_RESTRICT coeffs, float value);
|
||||
/*! <<<```
|
||||
* Sets the prewarping frequency `value` (Hz) in `coeffs`.
|
||||
*
|
||||
* Only used when the prewarp\_at\_cutoff parameter is off.
|
||||
*
|
||||
* Default value: `1e3f`.
|
||||
* }}} */
|
||||
|
||||
/*** Implementation ***/
|
||||
@ -132,11 +151,13 @@ static inline void bw_lp1_set_cutoff(bw_lp1_coeffs *BW_RESTRICT coeffs, float va
|
||||
struct _bw_lp1_coeffs {
|
||||
// Sub-components
|
||||
bw_one_pole_coeffs smooth_coeffs;
|
||||
bw_one_pole_state smooth_state;
|
||||
bw_one_pole_state smooth_cutoff_state;
|
||||
bw_one_pole_state smooth_prewarp_freq_state;
|
||||
|
||||
// Coefficients
|
||||
float t_k;
|
||||
|
||||
float prewarp_k;
|
||||
float t;
|
||||
float X_x;
|
||||
float X_X_z1;
|
||||
@ -144,6 +165,7 @@ struct _bw_lp1_coeffs {
|
||||
|
||||
// Parameters
|
||||
float cutoff;
|
||||
float prewarp_freq;
|
||||
};
|
||||
|
||||
struct _bw_lp1_state {
|
||||
@ -156,6 +178,8 @@ static inline void bw_lp1_init(bw_lp1_coeffs *BW_RESTRICT 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;
|
||||
coeffs->prewarp_freq = 1e3f;
|
||||
coeffs->prewarp_k = 1.f;
|
||||
}
|
||||
|
||||
static inline void bw_lp1_set_sample_rate(bw_lp1_coeffs *BW_RESTRICT coeffs, float sample_rate) {
|
||||
@ -165,20 +189,29 @@ static inline void bw_lp1_set_sample_rate(bw_lp1_coeffs *BW_RESTRICT coeffs, flo
|
||||
}
|
||||
|
||||
static inline void _bw_lp1_do_update_coeffs(bw_lp1_coeffs *BW_RESTRICT coeffs, char force) {
|
||||
float cutoff_cur = bw_one_pole_get_y_z1(&coeffs->smooth_state);
|
||||
const float prewarp_freq = coeffs->prewarp_freq + coeffs->prewarp_k * (coeffs->cutoff - coeffs->prewarp_freq);
|
||||
float prewarp_freq_cur = bw_one_pole_get_y_z1(&coeffs->smooth_prewarp_freq_state);
|
||||
float cutoff_cur = bw_one_pole_get_y_z1(&coeffs->smooth_cutoff_state);
|
||||
const char prewarp_freq_changed = force || prewarp_freq != prewarp_freq_cur;
|
||||
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_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;
|
||||
if (prewarp_freq_changed || cutoff_changed) {
|
||||
if (prewarp_freq_changed) {
|
||||
prewarp_freq_cur = bw_one_pole_process1_sticky_rel(&coeffs->smooth_coeffs, &coeffs->smooth_prewarp_freq_state, prewarp_freq);
|
||||
coeffs->t = bw_tanf_3(coeffs->t_k * prewarp_freq_cur);
|
||||
}
|
||||
if (cutoff_changed) {
|
||||
cutoff_cur = bw_one_pole_process1_sticky_rel(&coeffs->smooth_coeffs, &coeffs->smooth_cutoff_state, coeffs->cutoff);
|
||||
coeffs->y_X = bw_rcpf_2(cutoff_cur);
|
||||
}
|
||||
const float k = cutoff_cur * bw_rcpf_2(cutoff_cur * coeffs->t + prewarp_freq_cur);
|
||||
coeffs->X_x = k * prewarp_freq_cur;
|
||||
coeffs->X_X_z1 = k * coeffs->t;
|
||||
coeffs->y_X = bw_rcpf_2(cutoff_cur);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_lp1_reset_coeffs(bw_lp1_coeffs *BW_RESTRICT coeffs) {
|
||||
bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_state, coeffs->cutoff);
|
||||
bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_cutoff_state, coeffs->cutoff);
|
||||
bw_one_pole_reset_state(&coeffs->smooth_coeffs, &coeffs->smooth_prewarp_freq_state, coeffs->prewarp_freq + coeffs->prewarp_k * (coeffs->cutoff - coeffs->prewarp_freq));
|
||||
_bw_lp1_do_update_coeffs(coeffs, 1);
|
||||
}
|
||||
|
||||
@ -213,6 +246,14 @@ static inline void bw_lp1_set_cutoff(bw_lp1_coeffs *BW_RESTRICT coeffs, float va
|
||||
coeffs->cutoff = value;
|
||||
}
|
||||
|
||||
static inline void bw_lp1_set_prewarp_at_cutoff(bw_lp1_coeffs *BW_RESTRICT coeffs, char value) {
|
||||
coeffs->prewarp_k = value ? 1.f : 0.f;
|
||||
}
|
||||
|
||||
static inline void bw_lp1_set_prewarp_freq(bw_lp1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
coeffs->prewarp_freq = value;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -148,6 +148,11 @@ static inline void bw_ls1_set_dc_gain_dB(bw_ls1_coeffs *BW_RESTRICT coeffs, floa
|
||||
struct _bw_ls1_coeffs {
|
||||
// Sub-components
|
||||
bw_mm1_coeffs mm1_coeffs;
|
||||
|
||||
// Parameters
|
||||
float cutoff;
|
||||
float dc_gain;
|
||||
char update;
|
||||
};
|
||||
|
||||
struct _bw_ls1_state {
|
||||
@ -156,15 +161,29 @@ struct _bw_ls1_state {
|
||||
|
||||
static inline void bw_ls1_init(bw_ls1_coeffs *BW_RESTRICT coeffs) {
|
||||
bw_mm1_init(&coeffs->mm1_coeffs);
|
||||
bw_mm1_set_prewarp_at_cutoff(&coeffs->mm1_coeffs, 0);
|
||||
bw_mm1_set_coeffs_x(&coeffs->mm1_coeffs, 1.f);
|
||||
bw_mm1_set_coeffs_lp(&coeffs->mm1_coeffs, 0.f);
|
||||
coeffs->cutoff = 1e3f;
|
||||
coeffs->dc_gain = 1.f;
|
||||
}
|
||||
|
||||
static inline void bw_ls1_set_sample_rate(bw_ls1_coeffs *BW_RESTRICT coeffs, float sample_rate) {
|
||||
bw_mm1_set_sample_rate(&coeffs->mm1_coeffs, sample_rate);
|
||||
}
|
||||
|
||||
static inline void _bw_ls1_update_mm1_params(bw_ls1_coeffs *BW_RESTRICT coeffs) {
|
||||
if (coeffs->update) {
|
||||
bw_mm1_set_cutoff(&coeffs->mm1_coeffs, coeffs->cutoff * bw_rcpf_2(bw_sqrtf_2(coeffs->dc_gain)));
|
||||
bw_mm1_set_coeff_lp(&coeffs->mm1_coeffs, coeffs->dc_gain - 1.f);
|
||||
bw_mm1_set_prewarp_freq(&coeffs->mm1_coeffs, coeffs->cutoff);
|
||||
coeffs->update = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_ls1_reset_coeffs(bw_ls1_coeffs *BW_RESTRICT coeffs) {
|
||||
coeffs->update = 1;
|
||||
_bw_ls1_update_mm1_params(coeffs);
|
||||
bw_mm1_reset_coeffs(&coeffs->mm1_coeffs);
|
||||
}
|
||||
|
||||
@ -173,6 +192,7 @@ static inline void bw_ls1_reset_state(const bw_ls1_coeffs *BW_RESTRICT coeffs, b
|
||||
}
|
||||
|
||||
static inline void bw_ls1_update_coeffs_ctrl(bw_ls1_coeffs *BW_RESTRICT coeffs) {
|
||||
_bw_ls1_update_mm1_params(coeffs);
|
||||
bw_mm1_update_coeffs_ctrl(&coeffs->mm1_coeffs);
|
||||
}
|
||||
|
||||
@ -193,11 +213,17 @@ static inline void bw_ls1_process(bw_ls1_coeffs *BW_RESTRICT coeffs, bw_ls1_stat
|
||||
}
|
||||
|
||||
static inline void bw_ls1_set_cutoff(bw_ls1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
bw_mm1_set_cutoff(&coeffs->mm1_coeffs, value);
|
||||
if (value != coeffs->cutoff) {
|
||||
coeffs->cutoff = value;
|
||||
coeffs->update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_ls1_set_dc_gain_lin(bw_ls1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
bw_mm1_set_coeff_lp(&coeffs->mm1_coeffs, value - 1.f);
|
||||
if (value != coeffs->dc_gain) {
|
||||
coeffs->dc_gain = value;
|
||||
coeffs->update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_ls1_set_dc_gain_dB(bw_ls1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
|
@ -214,17 +214,7 @@ static inline void bw_ls2_set_sample_rate(bw_ls2_coeffs *BW_RESTRICT coeffs, flo
|
||||
bw_mm2_set_sample_rate(&coeffs->mm2_coeffs, sample_rate);
|
||||
}
|
||||
|
||||
static inline void bw_ls2_reset_coeffs(bw_ls2_coeffs *BW_RESTRICT coeffs) {
|
||||
bw_mm2_reset_coeffs(&coeffs->mm2_coeffs);
|
||||
coeffs->param_changed = ~0;
|
||||
bw_ls2_update_coeffs_ctrl(coeffs);
|
||||
}
|
||||
|
||||
static inline void bw_ls2_reset_state(const bw_ls2_coeffs *BW_RESTRICT coeffs, bw_ls2_state *BW_RESTRICT state) {
|
||||
bw_mm2_reset_state(&coeffs->mm2_coeffs, &state->mm2_state);
|
||||
}
|
||||
|
||||
static inline void bw_ls2_update_coeffs_ctrl(bw_ls2_coeffs *BW_RESTRICT coeffs) {
|
||||
static inline void _bw_ls2_update_mm2_params(bw_ls1_coeffs *BW_RESTRICT coeffs) {
|
||||
if (coeffs->param_changed) {
|
||||
if (coeffs->param_changed & _BW_LS2_PARAM_GAIN) {
|
||||
coeffs->sg = bw_math_sqrtf_2(coeffs->gain);
|
||||
@ -245,6 +235,20 @@ static inline void bw_ls2_update_coeffs_ctrl(bw_ls2_coeffs *BW_RESTRICT coeffs)
|
||||
}
|
||||
coeffs->param_changed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bw_ls2_reset_coeffs(bw_ls2_coeffs *BW_RESTRICT coeffs) {
|
||||
coeffs->param_changed = ~0;
|
||||
_bw_ls2_update_mm2_params(coeffs);
|
||||
bw_mm2_reset_coeffs(&coeffs->mm2_coeffs);
|
||||
}
|
||||
|
||||
static inline void bw_ls2_reset_state(const bw_ls2_coeffs *BW_RESTRICT coeffs, bw_ls2_state *BW_RESTRICT state) {
|
||||
bw_mm2_reset_state(&coeffs->mm2_coeffs, &state->mm2_state);
|
||||
}
|
||||
|
||||
static inline void bw_ls2_update_coeffs_ctrl(bw_ls2_coeffs *BW_RESTRICT coeffs) {
|
||||
_bw_ls2_update_mm2_params(coeffs);
|
||||
bw_mm2_update_coeffs_ctrl(&coeffs->mm2_coeffs);
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,23 @@ static inline void bw_mm1_set_cutoff(bw_mm1_coeffs *BW_RESTRICT coeffs, float va
|
||||
*
|
||||
* Default value: `1e3f`.
|
||||
*
|
||||
* #### bw_mm1_set_prewarp_at_cutoff()
|
||||
* ```>>> */
|
||||
static inline void bw_mm1_set_prewarp_at_cutoff(bw_mm1_coeffs *BW_RESTRICT coeffs, char value);
|
||||
/*! <<<```
|
||||
* Sets whether bilinear transform prewarping frequency should match the
|
||||
* cutoff frequency (non-`0`) or not (`0`).
|
||||
*
|
||||
* Default value: non-`0` (on).
|
||||
*
|
||||
* #### bw_mm1_set_prewarp_freq()
|
||||
* ```>>> */
|
||||
static inline void bw_mm1_set_prewarp_freq(bw_mm1_coeffs *BW_RESTRICT coeffs, float value);
|
||||
/*! <<<```
|
||||
* Sets the prewarping frequency `value` (Hz) in `coeffs`.
|
||||
*
|
||||
* Only used when the prewarp\_at\_cutoff parameter is off.
|
||||
*
|
||||
* #### bw_mm1_set_coeff_x()
|
||||
* ```>>> */
|
||||
static inline void bw_mm1_set_coeff_x(bw_mm1_coeffs *BW_RESTRICT coeffs, float value);
|
||||
@ -210,6 +227,14 @@ static inline void bw_mm1_set_cutoff(bw_mm1_coeffs *BW_RESTRICT coeffs, float va
|
||||
bw_lp1_set_cutoff(&coeffs->lp1_coeffs, value);
|
||||
}
|
||||
|
||||
static inline void bw_mm1_set_prewarp_at_cutoff(bw_mm1_coeffs *BW_RESTRICT coeffs, char value) {
|
||||
bw_lp1_set_prewarp_at_cutoff(&coeffs->lp1_coeffs, value);
|
||||
}
|
||||
|
||||
static inline void bw_mm1_set_prewarp_freq(bw_mm1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
bw_lp1_set_prewarp_freq(&coeffs->lp1_coeffs, value);
|
||||
}
|
||||
|
||||
static inline void bw_mm1_set_coeff_x(bw_mm1_coeffs *BW_RESTRICT coeffs, float value) {
|
||||
bw_gain_set_gain_lin(&coeffs->gain_x_coeffs, value);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user