Example #1
0
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;

  /* calculate the frequency of the resonant filter in Hz */
  fres = fluid_ct2hz(iir_filter->fres + fres_mod);

  /* FIXME - Still potential for a click during turn on, can we interpolate
     between 20khz cutoff and 0 Q? */

  /* I removed the optimization of turning the filter off when the
   * resonance frequence is above the maximum frequency. Instead, the
   * filter frequency is set to a maximum of 0.45 times the sampling
   * rate. For a 44100 kHz sampling rate, this amounts to 19845
   * Hz. The reason is that there were problems with anti-aliasing when the
   * synthesizer was run at lower sampling rates. Thanks to Stephan
   * Tassart for pointing me to this bug. By turning the filter on and
   * clipping the maximum filter frequency at 0.45*srate, the filter
   * is used as an anti-aliasing filter. */

  if (fres > 0.45f * output_rate)
    fres = 0.45f * output_rate;
  else if (fres < 5)
    fres = 5;

  /* if filter enabled and there is a significant frequency change.. */
  if ((abs (fres - iir_filter->last_fres) > 0.01))
  {
   /* 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);
  }


  fluid_check_fpe ("voice_write DSP coefficients");

}
Example #2
0
void Voice::dsp_float_config()
      {
      /* Initialize the coefficients for the interpolation. The math comes
       * from a mail, posted by Olli Niemitalo to the music-dsp mailing
       * list (I found it in the music-dsp archives
       * http://www.smartelectronix.com/musicdsp/).  */

      for (int i = 0; i < FLUID_INTERP_MAX; i++) {
            double x = (double) i / (double) FLUID_INTERP_MAX;

            interp_coeff[i][0] = (float)(x * (-0.5 + x * (1 - 0.5 * x)));
            interp_coeff[i][1] = (float)(1.0 + x * x * (1.5 * x - 2.5));
            interp_coeff[i][2] = (float)(x * (0.5 + x * (2.0 - 1.5 * x)));
            interp_coeff[i][3] = (float)(0.5 * x * x * (x - 1.0));

            interp_coeff_linear[i][0] = (float)(1.0 - x);
            interp_coeff_linear[i][1] = (float)x;
            }

      /* i: Offset in terms of whole samples */
      for (int i = 0; i < SINC_INTERP_ORDER; i++) {
            /* i2: Offset in terms of fractional samples ('subsamples') */
            for (int i2 = 0; i2 < FLUID_INTERP_MAX; i2++) {
                  /* center on middle of table */
                  double i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
                     + (double)i2 / (double)FLUID_INTERP_MAX;

                  /* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
                  double v;
                  if (fabs (i_shifted) > 0.000001) {
                        v = (float)sin (i_shifted * M_PI) / (M_PI * i_shifted);
                        /* Hamming window */
                        v *= (float)0.5 * (1.0 + cos (2.0 * M_PI * i_shifted / (float)SINC_INTERP_ORDER));
                        }
                  else
                        v = 1.0;
                  sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
                  }
            }
      fluid_check_fpe("interpolation table calculation");
      }
Example #3
0
/**
 * @return -1 if voice has finished, 0 if it's currently quiet, 1 otherwise
 */
static inline int
fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
{
  fluid_real_t target_amp;	/* target amplitude */

  if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVDELAY)
    return -1;	/* The volume amplitude is in hold phase. No sound is produced. */

  if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
  {
    /* the envelope is in the attack section: ramp linearly to max value.
     * A positive modlfo_to_vol should increase volume (negative attenuation).
     */
    target_amp = fluid_atten2amp (voice->dsp.attenuation)
      * fluid_cb2amp (fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
      * fluid_adsr_env_get_val(&voice->envlfo.volenv);
  }
  else
  {
    fluid_real_t amplitude_that_reaches_noise_floor;
    fluid_real_t amp_max;

    target_amp = fluid_atten2amp (voice->dsp.attenuation)
      * fluid_cb2amp (960.0f * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
		      + fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);

    /* We turn off a voice, if the volume has dropped low enough. */

    /* A voice can be turned off, when an estimate for the volume
     * (upper bound) falls below that volume, that will drop the
     * sample below the noise floor.
     */

    /* If the loop amplitude is known, we can use it if the voice loop is within
     * the sample loop
     */

    /* Is the playing pointer already in the loop? */
    if (voice->dsp.has_looped)
      amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_loop;
    else
      amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;

    /* voice->attenuation_min is a lower boundary for the attenuation
     * now and in the future (possibly 0 in the worst case).  Now the
     * amplitude of sample and volenv cannot exceed amp_max (since
     * volenv_val can only drop):
     */

    amp_max = fluid_atten2amp (voice->dsp.min_attenuation_cB) * 
              fluid_adsr_env_get_val(&voice->envlfo.volenv);

    /* And if amp_max is already smaller than the known amplitude,
     * which will attenuate the sample below the noise floor, then we
     * can safely turn off the voice. Duh. */
    if (amp_max < amplitude_that_reaches_noise_floor)
    {
      return 0;
    }
  }

  /* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
  voice->dsp.amp_incr = (target_amp - voice->dsp.amp) / FLUID_BUFSIZE;

  fluid_check_fpe ("voice_write amplitude calculation");

  /* no volume and not changing? - No need to process */
  if ((voice->dsp.amp == 0.0f) && (voice->dsp.amp_incr == 0.0f))
    return -1;

  return 1;
}
Example #4
0
/**
 * Synthesize a voice to a buffer.
 *
 * @param voice rvoice to synthesize
 * @param dsp_buf Audio buffer to synthesize to (#FLUID_BUFSIZE in length)
 * @return Count of samples written to dsp_buf. (-1 means voice is currently 
 * quiet, 0 .. #FLUID_BUFSIZE-1 means voice finished.)
 *
 * Panning, reverb and chorus are processed separately. The dsp interpolation
 * routine is in (fluid_dsp_float.c).
 */
int
fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
{
  int ticks = voice->envlfo.ticks;
  int count;

  /******************* sample sanity check **********/

  if (!voice->dsp.sample)
    return 0;
  if (voice->dsp.check_sample_sanity_flag)
    fluid_rvoice_check_sample_sanity(voice);

  /******************* noteoff check ****************/

  if (voice->envlfo.noteoff_ticks != 0 && 
      voice->envlfo.ticks >= voice->envlfo.noteoff_ticks) {
    fluid_rvoice_noteoff(voice, 0);
  }

  voice->envlfo.ticks += FLUID_BUFSIZE;

  /******************* vol env **********************/

  fluid_adsr_env_calc(&voice->envlfo.volenv, 1);
  fluid_check_fpe ("voice_write vol env");
  if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED)
    return 0;

  /******************* mod env **********************/

  fluid_adsr_env_calc(&voice->envlfo.modenv, 0);
  fluid_check_fpe ("voice_write mod env");

  /******************* lfo **********************/

  fluid_lfo_calc(&voice->envlfo.modlfo, ticks);
  fluid_check_fpe ("voice_write mod LFO");
  fluid_lfo_calc(&voice->envlfo.viblfo, ticks);
  fluid_check_fpe ("voice_write vib LFO");

  /******************* amplitude **********************/

  count = fluid_rvoice_calc_amp(voice);
  if (count <= 0) 
    return count;

  /******************* phase **********************/

  /* Calculate the number of samples, that the DSP loop advances
   * through the original waveform with each step in the output
   * buffer. It is the ratio between the frequencies of original
   * waveform and output waveform.*/
  voice->dsp.phase_incr = fluid_ct2hz_real(voice->dsp.pitch + 
     fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch
     + fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch
     + fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_pitch) 
     / voice->dsp.root_pitch_hz;

  fluid_check_fpe ("voice_write phase calculation");

  /* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
  if (voice->dsp.phase_incr == 0) voice->dsp.phase_incr = 1;

  voice->dsp.is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
    || (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
	&& fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);

  /*********************** run the dsp chain ************************
   * The sample is mixed with the output buffer.
   * The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
   * Depending on the position in the loop and the loop size, this
   * may require several runs. */
  voice->dsp.dsp_buf = dsp_buf; 

  switch (voice->dsp.interp_method)
  {
    case FLUID_INTERP_NONE:
      count = fluid_rvoice_dsp_interpolate_none (&voice->dsp);
      break;
    case FLUID_INTERP_LINEAR:
      count = fluid_rvoice_dsp_interpolate_linear (&voice->dsp);
      break;
    case FLUID_INTERP_4THORDER:
    default:
      count = fluid_rvoice_dsp_interpolate_4th_order (&voice->dsp);
      break;
    case FLUID_INTERP_7THORDER:
      count = fluid_rvoice_dsp_interpolate_7th_order (&voice->dsp);
      break;
  }
  fluid_check_fpe ("voice_write interpolation");
  if (count == 0)
    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 +
 		        fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);

  fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);

  return count;
}
Example #5
0
/* Purpose:
 *
 * Make sure, that sample start / end point and loop points are in
 * proper order. When starting up, calculate the initial phase.
 * TODO: Investigate whether this can be moved from rvoice to voice.
 */
static void
fluid_rvoice_check_sample_sanity(fluid_rvoice_t* voice)
{
    int min_index_nonloop=(int) voice->dsp.sample->start;
    int max_index_nonloop=(int) voice->dsp.sample->end;

    /* make sure we have enough samples surrounding the loop */
    int min_index_loop=(int) voice->dsp.sample->start + FLUID_MIN_LOOP_PAD;
    int max_index_loop=(int) voice->dsp.sample->end - FLUID_MIN_LOOP_PAD + 1;	/* 'end' is last valid sample, loopend can be + 1 */
    fluid_check_fpe("voice_check_sample_sanity start");

    if (!voice->dsp.check_sample_sanity_flag){
	return;
    }

#if 0
    printf("Sample from %i to %i\n",voice->dsp.sample->start, voice->dsp.sample->end);
    printf("Sample loop from %i %i\n",voice->dsp.sample->loopstart, voice->dsp.sample->loopend);
    printf("Playback from %i to %i\n", voice->dsp.start, voice->dsp.end);
    printf("Playback loop from %i to %i\n",voice->dsp.loopstart, voice->dsp.loopend);
#endif

    /* Keep the start point within the sample data */
    if (voice->dsp.start < min_index_nonloop){
	voice->dsp.start = min_index_nonloop;
    } else if (voice->dsp.start > max_index_nonloop){
	voice->dsp.start = max_index_nonloop;
    }

    /* Keep the end point within the sample data */
    if (voice->dsp.end < min_index_nonloop){
      voice->dsp.end = min_index_nonloop;
    } else if (voice->dsp.end > max_index_nonloop){
      voice->dsp.end = max_index_nonloop;
    }

    /* Keep start and end point in the right order */
    if (voice->dsp.start > voice->dsp.end){
	int temp = voice->dsp.start;
	voice->dsp.start = voice->dsp.end;
	voice->dsp.end = temp;
	/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
    }

    /* Zero length? */
    if (voice->dsp.start == voice->dsp.end){
	fluid_rvoice_voiceoff(voice);
	return;
    }

    if ((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
	|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) {
	/* Keep the loop start point within the sample data */
	if (voice->dsp.loopstart < min_index_loop){
	    voice->dsp.loopstart = min_index_loop;
      } else if (voice->dsp.loopstart > max_index_loop){
	voice->dsp.loopstart = max_index_loop;
      }

      /* Keep the loop end point within the sample data */
      if (voice->dsp.loopend < min_index_loop){
	voice->dsp.loopend = min_index_loop;
      } else if (voice->dsp.loopend > max_index_loop){
	voice->dsp.loopend = max_index_loop;
      }

      /* Keep loop start and end point in the right order */
      if (voice->dsp.loopstart > voice->dsp.loopend){
	int temp = voice->dsp.loopstart;
	voice->dsp.loopstart = voice->dsp.loopend;
	voice->dsp.loopend = temp;
	/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
      }

      /* Loop too short? Then don't loop. */
      if (voice->dsp.loopend < voice->dsp.loopstart + FLUID_MIN_LOOP_SIZE){
	  voice->dsp.samplemode = FLUID_UNLOOPED;
      }

      /* The loop points may have changed. Obtain a new estimate for the loop volume. */
      /* Is the voice loop within the sample loop? */
      if ((int)voice->dsp.loopstart >= (int)voice->dsp.sample->loopstart
	  && (int)voice->dsp.loopend <= (int)voice->dsp.sample->loopend){
	/* Is there a valid peak amplitude available for the loop? */
	if (voice->dsp.sample->amplitude_that_reaches_noise_floor_is_valid){
	  voice->dsp.amplitude_that_reaches_noise_floor_loop=voice->dsp.sample->amplitude_that_reaches_noise_floor / voice->dsp.synth_gain;
	} else {
	  /* Worst case */
	  voice->dsp.amplitude_that_reaches_noise_floor_loop=voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
	};
      };

    } /* if sample mode is looped */

    /* Run startup specific code (only once, when the voice is started) */
    if (voice->dsp.check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP){
      if (max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE){
        if ((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
	    || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)){
	  voice->dsp.samplemode = FLUID_UNLOOPED;
	}
      }

      /* Set the initial phase of the voice (using the result from the
	 start offset modulators). */
      fluid_phase_set_int(voice->dsp.phase, voice->dsp.start);
    } /* if startup */

    /* Is this voice run in loop mode, or does it run straight to the
       end of the waveform data? */
    if (((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) && 
        (fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE))
	|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) {
      /* Yes, it will loop as soon as it reaches the loop point.  In
       * this case we must prevent, that the playback pointer (phase)
       * happens to end up beyond the 2nd loop point, because the
       * point has moved.  The DSP algorithm is unable to cope with
       * that situation.  So if the phase is beyond the 2nd loop
       * point, set it to the start of the loop. No way to avoid some
       * noise here.  Note: If the sample pointer ends up -before the
       * first loop point- instead, then the DSP loop will just play
       * the sample, enter the loop and proceed as expected => no
       * actions required.
       */
      int index_in_sample = fluid_phase_index(voice->dsp.phase);
      if (index_in_sample >= voice->dsp.loopend){
	/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
	fluid_phase_set_int(voice->dsp.phase, voice->dsp.loopstart);
      }
    }
/*    FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->dsp.start, voice->dsp.end, voice->dsp.loopstart, voice->dsp.loopend); */

    /* Sample sanity has been assured. Don't check again, until some
       sample parameter is changed by modulation. */
    voice->dsp.check_sample_sanity_flag=0;
#if 0
    printf("Sane? playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend);
#endif
    fluid_check_fpe("voice_check_sample_sanity");
}
Example #6
0
/*
 * Variable description:
 * - dsp_a1, dsp_a2, dsp_b0, dsp_b1, dsp_b2: Filter coefficients
 *
 * A couple of variables are used internally, their results are discarded:
 * - dsp_i: Index through the output buffer
 * - dsp_phase_fractional: The fractional part of dsp_phase
 * - dsp_coeff: A table of four coefficients, depending on the fractional phase.
 *              Used to interpolate between samples.
 * - dsp_process_buffer: Holds the processed signal between stages
 * - dsp_centernode: delay line for the IIR filter
 * - dsp_hist1: same
 * - dsp_hist2: same
 */
void 
fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
                       fluid_real_t *dsp_buf, int count)
{
  /* IIR filter sample history */
  fluid_real_t dsp_hist1 = iir_filter->hist1;
  fluid_real_t dsp_hist2 = iir_filter->hist2;

  /* IIR filter coefficients */
  fluid_real_t dsp_a1 = iir_filter->a1;
  fluid_real_t dsp_a2 = iir_filter->a2;
  fluid_real_t dsp_b02 = iir_filter->b02;
  fluid_real_t dsp_b1 = iir_filter->b1;
  int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count;

  fluid_real_t dsp_centernode;
  int dsp_i;

  /* filter (implement the voice filter according to SoundFont standard) */

  /* Check for denormal number (too close to zero). */
  if (fabs (dsp_hist1) < 1e-20) dsp_hist1 = 0.0f;  /* FIXME JMG - Is this even needed? */

  /* Two versions of the filter loop. One, while the filter is
  * changing towards its new setting. The other, if the filter
  * doesn't change.
  */

  if (dsp_filter_coeff_incr_count > 0)
  {
    fluid_real_t dsp_a1_incr = iir_filter->a1_incr;
    fluid_real_t dsp_a2_incr = iir_filter->a2_incr;
    fluid_real_t dsp_b02_incr = iir_filter->b02_incr;
    fluid_real_t dsp_b1_incr = iir_filter->b1_incr;


    /* Increment is added to each filter coefficient filter_coeff_incr_count times. */
    for (dsp_i = 0; dsp_i < count; dsp_i++)
    {
      /* The filter is implemented in Direct-II form. */
      dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
      dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
      dsp_hist2 = dsp_hist1;
      dsp_hist1 = dsp_centernode;

      if (dsp_filter_coeff_incr_count-- > 0)
      {
        fluid_real_t old_b02 = dsp_b02;
	dsp_a1 += dsp_a1_incr;
	dsp_a2 += dsp_a2_incr;
	dsp_b02 += dsp_b02_incr;
	dsp_b1 += dsp_b1_incr;

        /* Compensate history to avoid the filter going havoc with large frequency changes */
	if (iir_filter->compensate_incr && fabs(dsp_b02) > 0.001) {
          fluid_real_t compensate = old_b02 / dsp_b02;
          dsp_centernode *= compensate;
          dsp_hist1 *= compensate;
          dsp_hist2 *= compensate;
        }
      }
    } /* for dsp_i */
  }
  else /* The filter parameters are constant.  This is duplicated to save time. */
  {
    for (dsp_i = 0; dsp_i < count; dsp_i++)
    { /* The filter is implemented in Direct-II form. */
      dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
      dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
      dsp_hist2 = dsp_hist1;
      dsp_hist1 = dsp_centernode;
    }
  }

  iir_filter->hist1 = dsp_hist1;
  iir_filter->hist2 = dsp_hist2;
  iir_filter->a1 = dsp_a1;
  iir_filter->a2 = dsp_a2;
  iir_filter->b02 = dsp_b02;
  iir_filter->b1 = dsp_b1;
  iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;

  fluid_check_fpe ("voice_filter");
}
Example #7
0
static FLUID_INLINE void
fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter, 
                                        int transition_samples, 
                                        fluid_real_t output_rate)
{

  /*
    * Those equations from Robert Bristow-Johnson's `Cookbook
    * formulae for audio EQ biquad filter coefficients', obtained
    * from Harmony-central.com / Computer / Programming. They are
    * the result of the bilinear transform on an analogue filter
    * prototype. To quote, `BLT frequency warping has been taken
    * into account for both significant frequency relocation and for
    * bandwidth readjustment'. */

  fluid_real_t omega = (fluid_real_t) (2.0 * M_PI * 
                       (iir_filter->last_fres / ((float) output_rate)));
  fluid_real_t sin_coeff = (fluid_real_t) sin(omega);
  fluid_real_t cos_coeff = (fluid_real_t) cos(omega);
  fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->q_lin);
  fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff);

  /* Calculate the filter coefficients. All coefficients are
   * normalized by a0. Think of `a1' as `a1/a0'.
   *
   * Here a couple of multiplications are saved by reusing common expressions.
   * The original equations should be:
   *  iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain;
   *  iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
   *  iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */

  fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
  fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
  fluid_real_t b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain;
   /* both b0 -and- b2 */
  fluid_real_t b02_temp = b1_temp * 0.5f;

  iir_filter->compensate_incr = 0;

  if (iir_filter->filter_startup || (transition_samples == 0))
  {
   /* The filter is calculated, because the voice was started up.
    * In this case set the filter coefficients without delay.
    */
    iir_filter->a1 = a1_temp;
    iir_filter->a2 = a2_temp;
    iir_filter->b02 = b02_temp;
    iir_filter->b1 = b1_temp;
    iir_filter->filter_coeff_incr_count = 0;
    iir_filter->filter_startup = 0;
//       printf("Setting initial filter coefficients.\n");
  }
  else
  {

    /* The filter frequency is changed.  Calculate an increment
     * factor, so that the new setting is reached after one buffer
     * length. x_incr is added to the current value FLUID_BUFSIZE
     * times. The length is arbitrarily chosen. Longer than one
     * buffer will sacrifice some performance, though.  Note: If
     * the filter is still too 'grainy', then increase this number
     * at will.
     */

    iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples;
    iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples;
    iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples;
    iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples;
    if (fabs(iir_filter->b02) > 0.0001) {
      fluid_real_t quota = b02_temp / iir_filter->b02;
      iir_filter->compensate_incr = quota < 0.5 || quota > 2;
    }
    /* Have to add the increments filter_coeff_incr_count times. */
    iir_filter->filter_coeff_incr_count = transition_samples;
  }
  fluid_check_fpe ("voice_write filter calculation");
}