Skip to content

Commit

Permalink
Implement a linear smoothing of fres
Browse files Browse the repository at this point in the history
interpolation for Q still missing, updating the coeffs when Q changes still missing
  • Loading branch information
derselbst committed Nov 16, 2024
1 parent 269ae5a commit 897dcca
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 23 deletions.
59 changes: 45 additions & 14 deletions src/rvoice/fluid_iir_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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");
}
Expand All @@ -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);
Expand All @@ -330,22 +349,34 @@ 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
* forced by setting last_fres to -1. The flag filter_startup
* 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");

}

15 changes: 8 additions & 7 deletions src/rvoice/fluid_iir_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 */
};
Expand Down
4 changes: 2 additions & 2 deletions src/rvoice/fluid_rvoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 897dcca

Please sign in to comment.