Allow the reverb to pre allocate delay lines. (#638)

This PR allows the reverb to pre-allocate the memory needed for the maximum sample-rate of the synth. That means that on sample rate change there are no memory allocation and the function fluid_revmodel_samplerate_change() should always return FLUID_OK.

The PR addresses discussion in #608.
This commit is contained in:
jjceresa 2020-05-01 13:26:52 +02:00 committed by GitHub
parent 791dac6736
commit 6aea18bef4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 279 additions and 213 deletions

View file

@ -120,17 +120,17 @@
* freeverb | 2 x 8 comb | 0.670 % | 204616 | ringing
* | 2 x 4 all-pass | | |
* ----------|---------------------------------------------------------------
* FDN | 8 | 0.650 % | 112160 | far less
* modulated | |(feeverb - 3%) | (55% freeverb) | ringing
* FDN | 8 | 0.650 % | 112480 | far less
* modulated | |(feeverb - 3%) | (56% freeverb) | ringing
* |---------------------------------------------------------------
* | 12 | 0.942 % | 168240 | best than
* | 12 | 0.942 % | 168720 | best than
* | |(freeverb + 41%) | (82 %freeverb) | 8 lines
*---------------------------------------------------------------------------
*
* Note:
* Values in this column is the memory consumption for sample rate <= 44100Hz.
* For sample rate > 44100Hz , multiply these values by (sample rate / 44100Hz).
*
* For example: for sample rate 96000Hz, the memory consumed is 244760 bytes
*
*----------------------------------------------------------------------------
* 'Denormalise' method to avoid loss of performance.
@ -182,7 +182,7 @@
/* Number of delay lines (must be only 8 or 12)
8 is the default.
12 produces a better quality but is +50% cpu expensive
12 produces a better quality but is +50% cpu expensive.
*/
#define NBR_DELAYS 8 /* default*/
@ -274,7 +274,7 @@ a flatter response on comb filter. So the input gain is set to 0.1 rather 1.0. *
/*
Number of samples to add to the desired length of a delay line. This
allow to take account of modulation interpolation.
1 is sufficient with MOD_DEPTH equal to 6.
1 is sufficient with MOD_DEPTH equal to 4.
*/
#define INTERP_SAMPLES_NBR 1
@ -368,7 +368,7 @@ static void set_fdn_delay_lpf(fdn_delay_lpf *lpf,
typedef struct
{
fluid_real_t *line; /* buffer line */
int size; /* effective internal size (in samples) */
int size; /* effective internal size (in samples) */
/*-------------*/
int line_in; /* line in position */
int line_out; /* line out position */
@ -500,115 +500,6 @@ typedef struct
fluid_real_t buffer;
} mod_delay_line;
/*-----------------------------------------------------------------------------
Modulated delay line initialization.
Sets the length line ( alloc delay samples).
Remark: the function sets the internal size accordling to the length delay_length.
As the delay line is a modulated line, its internal size is augmented by mod_depth.
The size is also augmented by INTERP_SAMPLES_NBR to take account of interpolation.
@param mdl, pointer on modulated delay line.
@param delay_length the length of the delay line in samples.
@param mod_depth depth of the modulation in samples (amplitude of the sine wave).
@param mod_rate the rate of the modulation in samples.
@return FLUID_OK if success , FLUID_FAILED if memory error.
Return FLUID_OK if success, FLUID_FAILED if memory error.
-----------------------------------------------------------------------------*/
static int set_mod_delay_line(mod_delay_line *mdl,
int delay_length,
int mod_depth,
int mod_rate
)
{
/*-----------------------------------------------------------------------*/
/* checks parameter */
if(delay_length < 1)
{
return FLUID_FAILED;
}
/* limits mod_depth to the requested delay length */
if(mod_depth >= delay_length)
{
FLUID_LOG(FLUID_INFO,
"fdn reverb: modulation depth has been limited");
mod_depth = delay_length - 1;
}
mdl->mod_depth = mod_depth;
/*-----------------------------------------------------------------------
allocates delay_line and initialize members:
- line, size, line_in, line_out...
*/
{
/* total size of the line:
size = INTERP_SAMPLES_NBR + mod_depth + delay_length */
mdl->dl.size = delay_length + mod_depth + INTERP_SAMPLES_NBR;
mdl->dl.line = FLUID_ARRAY(fluid_real_t, mdl->dl.size);
if(! mdl->dl.line)
{
return FLUID_FAILED;
}
clear_delay_line(&mdl->dl); /* clears the buffer */
/* Initializes line_in to the start of the buffer */
mdl->dl.line_in = 0;
/* Initializes line_out index INTERP_SAMPLES_NBR samples after line_in */
/* so that the delay between line_out and line_in is:
mod_depth + delay_length */
mdl->dl.line_out = mdl->dl.line_in + INTERP_SAMPLES_NBR;
}
/* Damping low pass filter -------------------*/
mdl->dl.damping.buffer = 0;
/*------------------------------------------------------------------------
Initializes modulation members:
- modulated center position: center_pos_mod
- index rate to know when to update center_pos_mod:index_rate
- modulation rate (the speed at which center_pos_mod is modulated: mod_rate
- interpolator member: buffer, frac_pos_mod
-------------------------------------------------------------------------*/
/* Sets the modulation rate. This rate defines how often
the center position (center_pos_mod ) is modulated .
The value is expressed in samples. The default value is 1 that means that
center_pos_mod is updated at every sample.
For example with a value of 2, the center position position will be
updated only one time every 2 samples only.
*/
mdl->mod_rate = 1; /* default modulation rate: every one sample */
if(mod_rate > mdl->dl.size)
{
FLUID_LOG(FLUID_INFO,
"fdn reverb: modulation rate is out of range");
}
else
{
mdl->mod_rate = mod_rate;
}
/* Initializes the modulated center position (center_pos_mod) so that:
- the delay between line_out and center_pos_mod is mod_depth.
- the delay between center_pos_mod and line_in is delay_length.
*/
mdl->center_pos_mod = (fluid_real_t) INTERP_SAMPLES_NBR + mod_depth;
/* index rate to control when to update center_pos_mod */
/* Important: must be set to get center_pos_mod immediately used for the
reading of first sample (see get_mod_delay()) */
mdl->index_rate = mdl->mod_rate;
/* initializes 1st order All-Pass interpolator members */
mdl->buffer = 0; /* previous delay sample value */
mdl->frac_pos_mod = 0; /* fractional position (between consecutives sample) */
return FLUID_OK;
}
/*-----------------------------------------------------------------------------
Return norminal delay length
@ -702,6 +593,7 @@ static FLUID_INLINE fluid_real_t get_mod_delay(mod_delay_line *mdl)
struct _fluid_late
{
fluid_real_t samplerate; /* sample rate */
fluid_real_t sample_rate_max; /* sample rate maximum */
/*----- High pass tone corrector -------------------------------------*/
fluid_real_t tone_buffer;
fluid_real_t b1, b2;
@ -904,118 +796,220 @@ static void delete_fluid_rev_late(fluid_late *late)
}
}
/*-----------------------------------------------------------------------------
Creates all modulated lines.
@param late, pointer on the fnd late reverb to initialize.
@param sample_rate, the audio sample rate.
@return FLUID_OK if success, FLUID_FAILED otherwise.
-----------------------------------------------------------------------------*/
static int create_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate)
/* Nominal delay lines length table (in samples) */
static const int nom_delay_length[NBR_DELAYS] =
{
/* Delay lines length table (in samples) */
static const int delay_length[NBR_DELAYS] =
{
DELAY_L0, DELAY_L1, DELAY_L2, DELAY_L3,
DELAY_L4, DELAY_L5, DELAY_L6, DELAY_L7,
#if (NBR_DELAYS == 12)
DELAY_L8, DELAY_L9, DELAY_L10, DELAY_L11
#endif
};
DELAY_L0, DELAY_L1, DELAY_L2, DELAY_L3,
DELAY_L4, DELAY_L5, DELAY_L6, DELAY_L7,
#if (NBR_DELAYS == 12)
DELAY_L8, DELAY_L9, DELAY_L10, DELAY_L11
#endif
};
int result; /* return value */
int i;
/*
1)"modal density" is one property that contributes to the quality of the reverb tail.
The more is the modal density, the less are unwanted resonant frequencies
build during the decay time: modal density = total delay / sample rate.
/*
1)"modal density" is one property that contributes to the quality of the reverb tail.
The more is the modal density, the less are unwanted resonant frequencies
build during the decay time: modal density = total delay / sample rate.
Delay line's length given by static table delay_length[] are nominal
to get minimum modal density of 0.15 at sample rate 44100Hz.
Here we set length_factor to 2 to multiply this nominal modal
density by 2. This leads to a default modal density of 0.15 * 2 = 0.3 for
sample rate <= 44100.
Delay line's length given by static table delay_length[] is nominal
to get minimum modal density of 0.15 at sample rate 44100Hz.
Here we set length_factor to 2 to multiply this nominal modal
density by 2. This leads to a default modal density of 0.15 * 2 = 0.3 for
sample rate <= 44100.
For sample rate > 44100, length_factor is multiplied by
sample_rate / 44100. This ensures that the default modal density keeps inchanged.
(Without this compensation, the default modal density would be diminished for
new sample rate change above 44100Hz).
For sample rate > 44100, length_factor is multiplied by
sample_rate / 44100. This ensures that the default modal density keeps inchanged.
(Without this compensation, the default modal density would be diminished for
new sample rate change above 44100Hz).
2)Modulated delay line contributes to diminish resonnant frequencies (often called "ringing").
Modulation depth (mod_depth) is set to nominal value of MOD_DEPTH at sample rate 44100Hz.
For sample rate > 44100, mod_depth is multiplied by sample_rate / 44100. This ensures
that the effect of modulated delay line keeps inchanged.
*/
fluid_real_t length_factor = 2.0f;
fluid_real_t mod_depth = MOD_DEPTH;
2)Modulated delay line contributes to diminish resonnant frequencies (often called "ringing").
Modulation depth (mod_depth) is set to nominal value of MOD_DEPTH at sample rate 44100Hz.
For sample rate > 44100, mod_depth is multiplied by sample_rate / 44100. This ensures
that the effect of modulated delay line remains inchanged.
*/
static void compensate_from_sample_rate(fluid_real_t sample_rate,
fluid_real_t *mod_depth,
fluid_real_t *length_factor)
{
*mod_depth = MOD_DEPTH;
*length_factor = 2.0f;
if(sample_rate > 44100.0f)
{
fluid_real_t sample_rate_factor = sample_rate/44100.0f;
length_factor *= sample_rate_factor;
mod_depth *= sample_rate_factor;
*length_factor *= sample_rate_factor;
*mod_depth *= sample_rate_factor;
}
}
/*-----------------------------------------------------------------------------
Creates all modulated lines.
@param late, pointer on the fnd late reverb to initialize.
@param sample_rate_max, the maximum audio sample rate expected.
@return FLUID_OK if success, FLUID_FAILED otherwise.
-----------------------------------------------------------------------------*/
static int create_mod_delay_lines(fluid_late *late,
fluid_real_t sample_rate_max)
{
int i;
fluid_real_t mod_depth, length_factor;
/* compute mod_depth, length factor */
compensate_from_sample_rate(sample_rate_max, &mod_depth, &length_factor);
late->sample_rate_max = sample_rate_max;
#ifdef INFOS_PRINT // allows message to be printed on the console.
printf("length_factor:%f, mod_depth:%f\n", length_factor, mod_depth);
/* Print: modal density and total memory bytes */
{
int i;
int total_delay; /* total delay in samples */
for (i = 0, total_delay = 0; i < NBR_DELAYS; i++)
int total_delay = 0; /* total delay in samples */
for (i = 0; i < NBR_DELAYS; i++)
{
total_delay += length_factor * delay_length[i];
int length = (length_factor * nom_delay_length[i])
+ mod_depth + INTERP_SAMPLES_NBR;
total_delay += length;
}
/* modal density and total memory bytes */
printf("modal density:%f, total memory:%d bytes\n",
total_delay / sample_rate , total_delay * sizeof(fluid_real_t));
printf("modal density:%f, total delay:%d, total memory:%d bytes\n",
total_delay / sample_rate_max ,total_delay ,
total_delay * sizeof(fluid_real_t));
}
#endif
for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */
{
/* allocate delay line and set local delay lines's parameters */
result = set_mod_delay_line(&late->mod_delay_lines[i],
delay_length[i] * length_factor,
mod_depth, MOD_RATE);
int delay_length = nom_delay_length[i] * length_factor;
mod_delay_line *mdl = &late->mod_delay_lines[i];
if(result == FLUID_FAILED)
/*-------------------------------------------------------------------*/
/* checks parameter */
if(delay_length < 1)
{
return FLUID_FAILED;
}
/* Sets local Modulators parameters: frequency and phase
Each modulateur are shifted of MOD_PHASE degree
/* limits mod_depth to the requested delay length */
if(mod_depth >= delay_length)
{
FLUID_LOG(FLUID_INFO,
"fdn reverb: modulation depth has been limited");
mod_depth = delay_length - 1;
}
/*---------------------------------------------------------------------
allocates delay lines
*/
set_mod_frequency(&late->mod_delay_lines[i].mod,
MOD_FREQ * MOD_RATE,
late->samplerate,
(float)(MOD_PHASE * i));
/* real size of the line in use (in samples):
size = INTERP_SAMPLES_NBR + mod_depth + delay_length */
mdl->dl.size = delay_length + mod_depth + INTERP_SAMPLES_NBR;
mdl->dl.line = FLUID_ARRAY(fluid_real_t, mdl->dl.size);
if(! mdl->dl.line)
{
return FLUID_FAILED;
}
}
return FLUID_OK;
}
/*-----------------------------------------------------------------------------
Creates the fdn reverb.
Initialize all modulated lines.
@param late, pointer on the fnd late reverb to initialize.
@param sample_rate the sample rate.
@param sample_rate, the audio sample rate.
@return FLUID_OK if success, FLUID_FAILED otherwise.
-----------------------------------------------------------------------------*/
static int create_fluid_rev_late(fluid_late *late, fluid_real_t sample_rate)
static void initialize_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate)
{
FLUID_MEMSET(late, 0, sizeof(fluid_late));
int i;
fluid_real_t mod_depth, length_factor;
/* update delay line parameter dependant of sample rate */
late->samplerate = sample_rate;
/*--------------------------------------------------------------------------
First initialize the modulated delay lines
*/
/* compute mod_depth, length factor */
compensate_from_sample_rate(sample_rate, &mod_depth, &length_factor);
if(create_mod_delay_lines(late, sample_rate) == FLUID_FAILED)
for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */
{
return FLUID_FAILED;
}
mod_delay_line *mdl = &late->mod_delay_lines[i];
int delay_length = nom_delay_length[i] * length_factor;
return FLUID_OK;
/* limits mod_depth to the requested delay length */
if(mod_depth >= delay_length)
{
mod_depth = delay_length - 1;
}
mdl->mod_depth = mod_depth;
clear_delay_line(&mdl->dl); /* clears the buffer */
/* Initializes line_in to the start of the buffer */
mdl->dl.line_in = 0;
/* Initializes line_out index INTERP_SAMPLES_NBR samples after
line_in so that the delay between line_out and line_in is:
mod_depth + delay_length
*/
mdl->dl.line_out = mdl->dl.line_in + INTERP_SAMPLES_NBR;
/* Damping low pass filter ------------------------------------------*/
mdl->dl.damping.buffer = 0;
/*---------------------------------------------------------------------
Initializes modulation members:
- modulated center position: center_pos_mod
- modulation rate (the speed at which center_pos_mod is modulated: mod_rate
- index rate to know when to update center_pos_mod:index_rate
- interpolator member: buffer, frac_pos_mod
---------------------------------------------------------------------*/
/* Initializes the modulated center position (center_pos_mod) so that:
- the delay between line_out and center_pos_mod is mod_depth.
- the delay between center_pos_mod and line_in is delay_length.
*/
mdl->center_pos_mod = (fluid_real_t) INTERP_SAMPLES_NBR + mod_depth;
/* Sets the modulation rate. This rate defines how often
the center position (center_pos_mod ) is modulated .
The value is expressed in samples. The default value is 1 that means that
center_pos_mod is updated at every sample.
For example with a value of 2, the center position position will be
updated only one time every 2 samples only.
*/
if(MOD_RATE < 1 || MOD_RATE > mdl->dl.size)
{
FLUID_LOG(FLUID_INFO, "fdn reverb: modulation rate is out of range");
mdl->mod_rate = 1; /* default modulation rate: every one sample */
}
else
{
mdl->mod_rate = MOD_RATE;
}
/* index rate to control when to update center_pos_mod.
Important: must be set to get center_pos_mod immediately used for
the reading of first sample (see get_mod_delay())
*/
mdl->index_rate = mdl->mod_rate;
/* initializes first order All-Pass interpolator members */
mdl->buffer = 0; /* previous delay sample value */
mdl->frac_pos_mod = 0; /* frac. position (between consecutives sample) */
/* Sets local Modulators parameters: frequency and phase.
Each modulateur are shifted of MOD_PHASE degree
*/
set_mod_frequency(&mdl->mod,
MOD_FREQ * MOD_RATE,
sample_rate,
(float)(MOD_PHASE * i));
}
}
/*
@ -1077,20 +1071,27 @@ fluid_revmodel_update(fluid_revmodel_t *rev)
/*----------------------------------------------------------------------------
Reverb API
-----------------------------------------------------------------------------*/
/*
* Creates a reverb. One created the reverb have no parameters set, so
* Creates a reverb. Once created the reverb have no parameters set, so
* fluid_revmodel_set() must be called at least one time after calling
* new_fluid_revmodel().
*
* @param sample_rate sample rate in Hz.
* @param sample_rate_max maximum sample rate expected in Hz.
*
* @param sample_rate actual sample rate needed in Hz.
* @return pointer on the new reverb or NULL if memory error.
* Reverb API.
*/
fluid_revmodel_t *
new_fluid_revmodel(fluid_real_t sample_rate)
new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate)
{
fluid_revmodel_t *rev;
if(sample_rate <= 0)
{
return NULL;
}
rev = FLUID_NEW(fluid_revmodel_t);
if(rev == NULL)
@ -1098,13 +1099,33 @@ new_fluid_revmodel(fluid_real_t sample_rate)
return NULL;
}
/* create fdn reverb */
if(create_fluid_rev_late(&rev->late, sample_rate) != FLUID_OK)
FLUID_MEMSET(&rev->late, 0, sizeof(fluid_late));
/*--------------------------------------------------------------------------
Create fdn late reverb.
*/
/* update minimum value for sample_rate_max */
if(sample_rate > sample_rate_max)
{
sample_rate_max = sample_rate;
}
/*--------------------------------------------------------------------------
Allocate the modulated delay lines
*/
if(create_mod_delay_lines(&rev->late, sample_rate_max) == FLUID_FAILED)
{
delete_fluid_revmodel(rev);
return NULL;
}
/*--------------------------------------------------------------------------
Initialize the fdn reverb
*/
/* Initialize all modulated lines. */
initialize_mod_delay_lines(&rev->late, sample_rate);
return rev;
}
@ -1131,7 +1152,8 @@ delete_fluid_revmodel(fluid_revmodel_t *rev)
/*
* Sets one or more reverb parameters. Note this must be called at least one
* time after calling new_fluid_revmodel().
* time after calling new_fluid_revmodel() and before any call to
* fluid_revmodel_processXXX() and fluid_revmodel_samplerate_change().
*
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
* function, calling fluid_revmodel_set() could produce audible clics.
@ -1152,6 +1174,8 @@ void
fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
fluid_real_t damping, fluid_real_t width, fluid_real_t level)
{
fluid_return_if_fail(rev != NULL);
/*-----------------------------------*/
if(set & FLUID_REVMODEL_SET_ROOMSIZE)
{
@ -1185,12 +1209,15 @@ fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
/*
* Applies a sample rate change on the reverb.
* fluid_revmodel_set() must be called at least one time before calling
* this function.
*
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
* function, calling fluid_revmodel_samplerate_change() isn't multi task safe because
* delay line are memory reallocated. To deal properly with this issue follow
* the steps:
* function, calling fluid_revmodel_samplerate_change() isn't multi task safe.
* To deal properly with this issue follow the steps:
* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().
* reverb functions.
* Optionally, call fluid_revmodel_reset() to damp the reverb.
* 2) Change sample rate by calling fluid_revmodel_samplerate_change().
* 3) Restart reverb processing (i.e enabling calling of any fluid_revmodel_processXXX()
* reverb functions.
@ -1199,29 +1226,44 @@ fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
* 2.1) delete the reverb by calling delete_fluid_revmodel().
* 2.2) create the reverb by calling new_fluid_revmodel().
*
* The best solution would be that this function be called only by the same task
* calling fluid_revmodel_processXXX().
*
* @param rev the reverb.
* @param sample_rate new sample rate value.
* @return FLUID_OK if success, FLUID_FAILED otherwise (memory error).
* @param sample_rate new sample rate value. Must be <= sample_rate_max
* @return FLUID_OK if success, FLUID_FAILED if new sample rate is greater
* then the maximumum sample rate set at creation time. The reverb will
* continue to work but with possible lost of quality.
* If this is a problem, the caller should follow steps 2.1 and 2.2.
* Reverb API.
*/
int
fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)
{
rev->late.samplerate = sample_rate; /* new sample rate value */
int status = FLUID_OK;
/* free all delay lines */
delete_fluid_rev_late(&rev->late);
fluid_return_val_if_fail(rev != NULL, FLUID_FAILED);
/* create all delay lines */
if(create_mod_delay_lines(&rev->late, sample_rate) == FLUID_FAILED)
if(sample_rate > rev->late.sample_rate_max)
{
return FLUID_FAILED; /* memory error */
FLUID_LOG(FLUID_WARN,
"fdn reverb: sample rate %.0f Hz is deduced to %.0f Hz\n",
sample_rate, rev->late.sample_rate_max);
/* Reduce sample rate to the maximum value set at creation time.
The reverb will continue to work with possible lost of quality.
*/
sample_rate = rev->late.sample_rate_max;
status = FLUID_FAILED;
}
/* Initialize all modulated lines according to sample rate change. */
initialize_mod_delay_lines(&rev->late, sample_rate);
/* updates damping filter coefficients according to sample rate change */
update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);
return FLUID_OK;
return status;
}
/*
@ -1233,6 +1275,8 @@ fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate
void
fluid_revmodel_reset(fluid_revmodel_t *rev)
{
fluid_return_if_fail(rev != NULL);
fluid_revmodel_init(rev);
}
@ -1347,7 +1391,7 @@ fluid_revmodel_processreplace(fluid_revmodel_t *rev, const fluid_real_t *in,
right_out[k] = out_right * rev->wet1 + out_left * rev->wet2;
As wet1 is integrated in stereo coefficient wet 1 is now
integrated in out_left and out_right we simplify previous
integrated in out_left and out_right, so we simplify previous
relation by suppression of one multiply as this:
left_out[k] = out_left + out_right * rev->wet2;
@ -1467,7 +1511,7 @@ void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in,
right_out[k] += out_right * rev->wet1 + out_left * rev->wet2;
As wet1 is integrated in stereo coefficient wet 1 is now
integrated in out_left and out_right we simplify previous
integrated in out_left and out_right, so we simplify previous
relation by suppression of one multiply as this:
left_out[k] += out_left + out_right * rev->wet2;

View file

@ -58,7 +58,9 @@ typedef struct _fluid_revmodel_presets_t
/*
* reverb
*/
fluid_revmodel_t *new_fluid_revmodel(fluid_real_t sample_rate);
fluid_revmodel_t *
new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate);
void delete_fluid_revmodel(fluid_revmodel_t *rev);
void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in,

View file

@ -114,7 +114,9 @@ fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *e
fluid_rvoice_eventhandler_t *
new_fluid_rvoice_eventhandler(int queuesize,
int finished_voices_size, int bufs, int fx_bufs, int fx_units, fluid_real_t sample_rate, int extra_threads, int prio)
int finished_voices_size, int bufs, int fx_bufs, int fx_units,
fluid_real_t sample_rate_max, fluid_real_t sample_rate,
int extra_threads, int prio)
{
fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
@ -145,7 +147,8 @@ new_fluid_rvoice_eventhandler(int queuesize,
goto error_recovery;
}
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, sample_rate, eventhandler, extra_threads, prio);
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units,
sample_rate_max, sample_rate, eventhandler, extra_threads, prio);
if(eventhandler->mixer == NULL)
{

View file

@ -50,7 +50,7 @@ struct _fluid_rvoice_eventhandler_t
fluid_rvoice_eventhandler_t *new_fluid_rvoice_eventhandler(
int queuesize, int finished_voices_size, int bufs,
int fx_bufs, int fx_units, fluid_real_t sample_rate, int, int);
int fx_bufs, int fx_units, fluid_real_t sample_rate_max, fluid_real_t sample_rate, int, int);
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *);

View file

@ -685,6 +685,13 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
if(mixer->fx[i].reverb)
{
fluid_revmodel_samplerate_change(mixer->fx[i].reverb, samplerate);
/*
fluid_revmodel_samplerate_change() shouldn't fail if the reverb was created
with sample_rate_max set to the maximum sample rate indicated in the settings.
If this condition isn't respected, the reverb will continue to work but with
lost of quality.
*/
}
}
@ -704,7 +711,11 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
* @param fx_buf_count number of stereo effect buffers
*/
fluid_rvoice_mixer_t *
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, fluid_real_t sample_rate, fluid_rvoice_eventhandler_t *evthandler, int extra_threads, int prio)
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units,
fluid_real_t sample_rate_max,
fluid_real_t sample_rate,
fluid_rvoice_eventhandler_t *evthandler,
int extra_threads, int prio)
{
int i;
fluid_rvoice_mixer_t *mixer = FLUID_NEW(fluid_rvoice_mixer_t);
@ -733,7 +744,8 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, fluid_real
for(i = 0; i < fx_units; i++)
{
mixer->fx[i].reverb = new_fluid_revmodel(sample_rate);
/* create reverb and chorus units */
mixer->fx[i].reverb = new_fluid_revmodel(sample_rate_max, sample_rate);
mixer->fx[i].chorus = new_fluid_chorus(sample_rate);
if(mixer->fx[i].reverb == NULL || mixer->fx[i].chorus == NULL)

View file

@ -38,7 +38,8 @@ int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer);
int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer);
#endif
fluid_rvoice_mixer_t *new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units,
fluid_real_t sample_rate, fluid_rvoice_eventhandler_t *, int, int);
fluid_real_t sample_rate_max, fluid_real_t sample_rate,
fluid_rvoice_eventhandler_t *, int, int);
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *);

View file

@ -607,6 +607,7 @@ new_fluid_synth(fluid_settings_t *settings)
char *important_channels;
int i, nbuf, prio_level = 0;
int with_ladspa = 0;
fluid_real_t sample_rate_min, sample_rate_max;
/* initialize all the conversion tables and other stuff */
if(fluid_atomic_int_compare_and_exchange(&fluid_synth_initialized, 0, 1))
@ -637,6 +638,7 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony);
fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate);
fluid_settings_getnum_range(settings, "synth.sample-rate", &sample_rate_min, &sample_rate_max);
fluid_settings_getint(settings, "synth.midi-channels", &synth->midi_channels);
fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels);
fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
@ -778,7 +780,9 @@ new_fluid_synth(fluid_settings_t *settings)
/* Allocate event queue for rvoice mixer */
/* In an overflow situation, a new voice takes about 50 spaces in the queue! */
synth->eventhandler = new_fluid_rvoice_eventhandler(synth->polyphony * 64,
synth->polyphony, nbuf, synth->effects_channels, synth->effects_groups, synth->sample_rate, synth->cores - 1, prio_level);
synth->polyphony, nbuf, synth->effects_channels, synth->effects_groups,
sample_rate_max, synth->sample_rate,
synth->cores - 1, prio_level);
if(synth->eventhandler == NULL)
{