From 897dccac0ae0cf18bc36a22326a31c7de30bb27f Mon Sep 17 00:00:00 2001 From: derselbst Date: Sun, 10 Nov 2024 12:44:50 +0100 Subject: [PATCH] Implement a linear smoothing of fres interpolation for Q still missing, updating the coeffs when Q changes still missing --- src/rvoice/fluid_iir_filter.c | 59 ++++++++++++++++++++++++++--------- src/rvoice/fluid_iir_filter.h | 15 ++++----- src/rvoice/fluid_rvoice.c | 4 +-- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/rvoice/fluid_iir_filter.c b/src/rvoice/fluid_iir_filter.c index e4577b94e..6e55c3cb8 100644 --- a/src/rvoice/fluid_iir_filter.c +++ b/src/rvoice/fluid_iir_filter.c @@ -22,6 +22,11 @@ #include "fluid_sys.h" #include "fluid_conv.h" + +static FLUID_INLINE void +fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, fluid_real_t output_rate); + + /** * Applies a low- or high-pass filter with variable cutoff frequency and quality factor * for a given biquad transfer function: @@ -48,7 +53,7 @@ */ void fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, - fluid_real_t *dsp_buf, int count) + fluid_real_t *dsp_buf, int count, fluid_real_t output_rate) { if(iir_filter->type == FLUID_IIR_DISABLED || iir_filter->q_lin == 0) { @@ -65,6 +70,9 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, fluid_real_t dsp_a2 = iir_filter->a2; fluid_real_t dsp_b02 = iir_filter->b02; fluid_real_t dsp_b1 = iir_filter->b1; + + fluid_real_t fres_incr = iir_filter->fres_incr; + int fres_incr_count = iir_filter->fres_incr_count; fluid_real_t dsp_centernode; int dsp_i; @@ -94,6 +102,22 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, // dsp_buf[dsp_i] = dsp_b02 * dsp_input + dsp_hist1; // dsp_hist1 = dsp_b1 * dsp_input - dsp_a1 * dsp_buf[dsp_i] + dsp_hist2; // dsp_hist2 = dsp_b02 * dsp_input - dsp_a2 * dsp_buf[dsp_i]; + + if(fres_incr_count > 0) + { + --fres_incr_count; + iir_filter->last_fres += fres_incr; + + FLUID_LOG(FLUID_DBG, "last_fres: %f | target_fres: %f", iir_filter->last_fres, iir_filter->target_fres); + + fluid_iir_filter_calculate_coefficients(iir_filter, output_rate); + + // re-read coeffs + dsp_a1 = iir_filter->a1; + dsp_a2 = iir_filter->a2; + dsp_b02 = iir_filter->b02; + dsp_b1 = iir_filter->b1; + } } iir_filter->hist1 = dsp_hist1; @@ -102,12 +126,13 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, iir_filter->a2 = dsp_a2; iir_filter->b02 = dsp_b02; iir_filter->b1 = dsp_b1; + + iir_filter->fres_incr_count = fres_incr_count; fluid_check_fpe("voice_filter"); } } - DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init) { fluid_iir_filter_t *iir_filter = obj; @@ -139,7 +164,6 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres) fluid_real_t fres = param[0].real; iir_filter->fres = fres; - iir_filter->last_fres = -1.; FLUID_LOG(FLUID_DBG, "fluid_iir_filter_set_fres: fres= %f [acents]",fres); } @@ -219,14 +243,10 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q) */ iir_filter->filter_gain /= FLUID_SQRT(q); } - - /* The synthesis loop will have to recalculate the filter coefficients. */ - iir_filter->last_fres = -1.; } static FLUID_INLINE void fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, - int transition_samples, fluid_real_t output_rate) { /* FLUID_IIR_Q_LINEAR may switch the filter off by setting Q==0 */ @@ -294,7 +314,6 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, iir_filter->a2 = a2_temp; iir_filter->b02 = b02_temp; iir_filter->b1 = b1_temp; - iir_filter->filter_startup = 0; fluid_check_fpe("voice_write filter calculation"); } @@ -305,7 +324,7 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, fluid_real_t output_rate, fluid_real_t fres_mod) { - fluid_real_t fres; + fluid_real_t fres, fres_diff; /* calculate the frequency of the resonant filter in Hz */ fres = fluid_ct2hz(iir_filter->fres + fres_mod); @@ -330,8 +349,10 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, } FLUID_LOG(FLUID_DBG, "%f + %f = %f cents = %f Hz | Q: %f", iir_filter->fres, fres_mod, iir_filter->fres + fres_mod, fres, iir_filter->q_lin); + /* if filter enabled and there is a significant frequency change.. */ - if(iir_filter->type != FLUID_IIR_DISABLED && FLUID_FABS(fres - iir_filter->last_fres) > 0.01f) + fres_diff = fres - iir_filter->last_fres; + if(iir_filter->type != FLUID_IIR_DISABLED && FLUID_FABS(fres_diff) > 0.01f) { /* The filter coefficients have to be recalculated (filter * parameters have changed). Recalculation for various reasons is @@ -339,13 +360,23 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, * indicates, that the DSP loop runs for the first time, in this * case, the filter is set directly, instead of smoothly fading * between old and new settings. */ - iir_filter->last_fres = fres; - fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE, - output_rate); + if(iir_filter->filter_startup) + { + iir_filter->fres_incr_count = 0; + iir_filter->last_fres = fres; + iir_filter->filter_startup = 0; + } + else + { + static const int fres_incr_count = FLUID_BUFSIZE; + iir_filter->fres_incr = fres_diff / (fres_incr_count); + iir_filter->fres_incr_count = fres_incr_count; + } + iir_filter->target_fres = fres; + fluid_iir_filter_calculate_coefficients(iir_filter, output_rate); } fluid_check_fpe("voice_write DSP coefficients"); } - diff --git a/src/rvoice/fluid_iir_filter.h b/src/rvoice/fluid_iir_filter.h index 93b73489a..cf18d178b 100644 --- a/src/rvoice/fluid_iir_filter.h +++ b/src/rvoice/fluid_iir_filter.h @@ -30,7 +30,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres); DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q); void fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, - fluid_real_t *dsp_buf, int dsp_buf_count); + fluid_real_t *dsp_buf, int dsp_buf_count, fluid_real_t output_rate); void fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter); @@ -54,13 +54,14 @@ struct _fluid_iir_filter_t fluid_real_t a2; /* a1 / a0 */ fluid_real_t hist1, hist2; /* Sample history for the IIR filter */ - int filter_startup; /* Flag: If set, the filter will be set directly. - Else it changes smoothly. */ + int filter_startup; /* Flag: If set, the filter will be set directly. Else it changes smoothly. */ - fluid_real_t fres; /* the resonance frequency, in absolute cents */ - fluid_real_t last_fres; /* Current resonance frequency of the IIR filter in Hz */ - /* Serves as a flag: A deviation between fres and last_fres */ - /* indicates, that the filter has to be recalculated. */ + fluid_real_t fres; /* The desired resonance frequency, in absolute cents, this filter is currently set to */ + fluid_real_t last_fres; /* The filter's currently (smoothed out) resonance frequency in Hz, which will converge towards its target fres once fres_incr_count has become zero */ + fluid_real_t target_fres; /* The filter's target fres, that last_fres should converge towards - for debugging only */ + fluid_real_t fres_incr; /* The linear increment of fres on each sample */ + int fres_incr_count; /* The number of samples left for the smoothed last_fres adjustment to complete */ + fluid_real_t q_lin; /* the q-factor on a linear scale */ fluid_real_t filter_gain; /* Gain correction factor, depends on q */ }; diff --git a/src/rvoice/fluid_rvoice.c b/src/rvoice/fluid_rvoice.c index 9c0ea28a5..5b96fb774 100644 --- a/src/rvoice/fluid_rvoice.c +++ b/src/rvoice/fluid_rvoice.c @@ -488,11 +488,11 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc + modenv_val * voice->envlfo.modenv_to_fc); - fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count); + fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count, voice->dsp.output_rate); /* additional custom filter - only uses the fixed modulator, no lfos... */ fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0); - fluid_iir_filter_apply(&voice->resonant_custom_filter, dsp_buf, count); + fluid_iir_filter_apply(&voice->resonant_custom_filter, dsp_buf, count, voice->dsp.output_rate); return count; }