Skip to content

Commit

Permalink
Fix filter processing order in DSP chain (#1444)
Browse files Browse the repository at this point in the history
  • Loading branch information
derselbst authored Dec 8, 2024
1 parent d814a62 commit e604d9e
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 108 deletions.
40 changes: 21 additions & 19 deletions src/rvoice/fluid_rvoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,22 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
|| (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
&& fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);

/*************** resonant filter ******************/
// Only "prepare" the filter here, the filter itself will be applied in the dsp_interpolation routines below.
// This is to satisfy SF2 Section 9.1.8, particularly, the filtered output must be gain-adjusted by the volEnv.
// Applying the filter after applying the gain from the volEnv might cause audible clicks for when turning off
// voices that are filtered by a high Q, see https://github.com/FluidSynth/fluidsynth/issues/1427
//
// Note that at this point we are using voice->dsp.output_rate which is set to the synth's output rate, because
// the filter will receive the interpolated waveform.

fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
modenv_val * voice->envlfo.modenv_to_fc);

/* additional custom filter - only uses the fixed modulator, no lfos... */
fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0);

/*********************** run the dsp chain ************************
* The sample is mixed with the output buffer.
* The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
Expand All @@ -449,28 +465,26 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
//
// Currently, this does access the sample buffers, which is redundant and could be optimized away.
// On the other hand, entering this if-clause is not supposed to happen often.
//
// Also note, that we're returning directly without running the IIR filter below.
return fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping);
return fluid_rvoice_dsp_interpolate_none(voice, dsp_buf, is_looping);
}

switch(voice->dsp.interp_method)
{
case FLUID_INTERP_NONE:
count = fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping);
count = fluid_rvoice_dsp_interpolate_none(voice, dsp_buf, is_looping);
break;

case FLUID_INTERP_LINEAR:
count = fluid_rvoice_dsp_interpolate_linear(&voice->dsp, dsp_buf, is_looping);
count = fluid_rvoice_dsp_interpolate_linear(voice, dsp_buf, is_looping);
break;

case FLUID_INTERP_4THORDER:
default:
count = fluid_rvoice_dsp_interpolate_4th_order(&voice->dsp, dsp_buf, is_looping);
count = fluid_rvoice_dsp_interpolate_4th_order(voice, dsp_buf, is_looping);
break;

case FLUID_INTERP_7THORDER:
count = fluid_rvoice_dsp_interpolate_7th_order(&voice->dsp, dsp_buf, is_looping);
count = fluid_rvoice_dsp_interpolate_7th_order(voice, dsp_buf, is_looping);
break;
}

Expand All @@ -482,18 +496,6 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
return count;
}

/*************** resonant filter ******************/

fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
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, 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, voice->dsp.output_rate);

return count;
}

Expand Down
8 changes: 4 additions & 4 deletions src/rvoice/fluid_rvoice.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,10 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample);

/* defined in fluid_rvoice_dsp.c */
void fluid_rvoice_dsp_config(void);
int fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
int fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
int fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
int fluid_rvoice_dsp_interpolate_none(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
int fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
int fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);


/*
Expand Down
Loading

0 comments on commit e604d9e

Please sign in to comment.