mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-01-19 07:50:49 +00:00
Make chorus capable of sample rate change. (#639)
This commit is contained in:
parent
a89399476e
commit
ff14432cd9
3 changed files with 124 additions and 63 deletions
|
@ -261,7 +261,7 @@ static void set_sinus_frequency(sinus_modulator *mod,
|
|||
y(n) = a1 . y(n-1) - y(n-2)
|
||||
out = a1 . buffer1 - buffer2
|
||||
|
||||
@param pointer on modulator structure.
|
||||
@param mod pointer on modulator structure.
|
||||
@return current value of the modulator sine wave.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod)
|
||||
|
@ -293,6 +293,11 @@ static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod)
|
|||
in the period relative to the beginning of the period.
|
||||
For example: 0 is the beginning of the period, 1/4 is at 1/4 of the period
|
||||
relative to the beginning.
|
||||
|
||||
@param mod pointer on modulator structure.
|
||||
@param freq frequency of the oscillator in Hz.
|
||||
@param sample_rate sample rate on audio output in Hz.
|
||||
@param frac_phase initial phase (see comment above).
|
||||
-----------------------------------------------------------------------------*/
|
||||
static void set_triangle_frequency(triang_modulator *mod, float freq,
|
||||
float sample_rate, float frac_phase)
|
||||
|
@ -333,6 +338,9 @@ static void set_triangle_frequency(triang_modulator *mod, float freq,
|
|||
/*-----------------------------------------------------------------------------
|
||||
Get current value of triangular oscillator
|
||||
y(n) = y(n-1) + dy
|
||||
|
||||
@param mod pointer on triang_modulator structure.
|
||||
@return current value.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static FLUID_INLINE fluid_real_t get_mod_triang(triang_modulator *mod)
|
||||
{
|
||||
|
@ -354,11 +362,13 @@ static FLUID_INLINE fluid_real_t get_mod_triang(triang_modulator *mod)
|
|||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
Reads the sample value out of the modulated delay line.
|
||||
@param mdl, pointer on modulated delay line.
|
||||
@return the sample value.
|
||||
|
||||
@param chorus pointer on chorus unit.
|
||||
@param mod pointer on modulator structure.
|
||||
@return current value.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus,
|
||||
modulator *mod)
|
||||
modulator *mod)
|
||||
{
|
||||
fluid_real_t out_index; /* new modulated index position */
|
||||
int int_out_index; /* integer part of out_index */
|
||||
|
@ -431,6 +441,9 @@ static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus,
|
|||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Push a sample val into the delay line
|
||||
|
||||
@param dl delay line to push value into.
|
||||
@param val the value to push into dl.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#define push_in_delay_line(dl, val) \
|
||||
{\
|
||||
|
@ -444,13 +457,15 @@ static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus,
|
|||
|
||||
center_pos_mod is initialized so that the delay between center_pos_mod and
|
||||
line_in is: mod_depth + INTERP_SAMPLES_NBR.
|
||||
|
||||
@param chorus pointer on chorus unit.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static void set_center_position(fluid_chorus_t *chorus)
|
||||
{
|
||||
int center;
|
||||
|
||||
/* Sets the modulation rate. This rate defines how often
|
||||
the center position (center_pos_mod ) is modulated .
|
||||
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
|
||||
|
@ -484,6 +499,63 @@ static void set_center_position(fluid_chorus_t *chorus)
|
|||
chorus->index_rate = chorus->mod_rate;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Update internal parameters dependent of sample rate.
|
||||
- mod_depth.
|
||||
- mod_rate, center_pos_mod, and index rate.
|
||||
- modulators frequency.
|
||||
|
||||
@param chorus, pointer on chorus unit.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static void update_parameters_from_sample_rate(fluid_chorus_t *chorus)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* initialize modulation depth (peak to peak) (in samples) */
|
||||
/* convert modulation depth in ms to sample number */
|
||||
chorus->mod_depth = (int)(chorus->depth_ms / 1000.0
|
||||
* chorus->sample_rate);
|
||||
|
||||
/* the delay line is fixed. So we reduce mod_depth (if necessary) */
|
||||
if(chorus->mod_depth > MAX_SAMPLES)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).",
|
||||
MAX_SAMPLES);
|
||||
chorus->mod_depth = MAX_SAMPLES;
|
||||
/* set depth_ms to maximum to avoid spamming console with above warning */
|
||||
chorus->depth_ms = (chorus->mod_depth * 1000) / chorus->sample_rate;
|
||||
}
|
||||
|
||||
chorus->mod_depth /= 2; /* amplitude is peak to peek / 2 */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("depth_ms:%f, depth_samples/2:%d\n", chorus->depth_ms, chorus->mod_depth);
|
||||
#endif
|
||||
|
||||
/* Initializes the modulated center position:
|
||||
mod_rate, center_pos_mod, and index rate.
|
||||
*/
|
||||
set_center_position(chorus); /* must be called before set_xxxx_frequency() */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("mod_rate:%d\n", chorus->mod_rate);
|
||||
#endif
|
||||
|
||||
/* initialize modulator frequency */
|
||||
for(i = 0; i < chorus->number_blocks; i++)
|
||||
{
|
||||
set_sinus_frequency(&chorus->mod[i].sinus,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)((360.0f / (float) chorus->number_blocks) * i));
|
||||
|
||||
set_triangle_frequency(&chorus->mod[i].triang,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)i / chorus->number_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Modulated delay line initialization.
|
||||
|
||||
|
@ -491,7 +563,7 @@ static void set_center_position(fluid_chorus_t *chorus)
|
|||
Remark: the function sets the internal size accordling to the length delay_length.
|
||||
The size is augmented by INTERP_SAMPLES_NBR to take account of interpolation.
|
||||
|
||||
@param chorus, pointer chorus unit.
|
||||
@param chorus, pointer on chorus unit.
|
||||
@param delay_length the length of the delay line in samples.
|
||||
@return FLUID_OK if success , FLUID_FAILED if memory error.
|
||||
|
||||
|
@ -545,8 +617,11 @@ static int new_mod_delay_line(fluid_chorus_t *chorus, int delay_length)
|
|||
API
|
||||
------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Create the chorus unit.
|
||||
* @sample_rate audio sample rate in Hz.
|
||||
* Create the chorus unit. Once created the chorus have no parameters set, so
|
||||
* fluid_chorus_set() must be called at least one time after calling
|
||||
* new_fluid_chorus().
|
||||
*
|
||||
* @param sample_rate, audio sample rate in Hz.
|
||||
* @return pointer on chorus unit.
|
||||
*/
|
||||
fluid_chorus_t *
|
||||
|
@ -577,15 +652,11 @@ new_fluid_chorus(fluid_real_t sample_rate)
|
|||
|
||||
if(new_mod_delay_line(chorus, MAX_SAMPLES) == FLUID_FAILED)
|
||||
{
|
||||
goto error_recovery;
|
||||
delete_fluid_chorus(chorus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return chorus;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_chorus(chorus);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -628,15 +699,16 @@ fluid_chorus_reset(fluid_chorus_t *chorus)
|
|||
|
||||
/**
|
||||
* Set one or more chorus parameters.
|
||||
* @param chorus Chorus instance
|
||||
* @param set Flags indicating which chorus parameters to set (#fluid_chorus_set_t)
|
||||
*
|
||||
* @param chorus Chorus instance.
|
||||
* @param set Flags indicating which chorus parameters to set (#fluid_chorus_set_t).
|
||||
* @param nr Chorus voice count (0-99, CPU time consumption proportional to
|
||||
* this value)
|
||||
* @param level Chorus level (0.0-10.0)
|
||||
* @param speed Chorus speed in Hz (0.1-5.0)
|
||||
* this value).
|
||||
* @param level Chorus level (0.0-10.0).
|
||||
* @param speed Chorus speed in Hz (0.1-5.0).
|
||||
* @param depth_ms Chorus depth (max value depends on synth sample rate,
|
||||
* 0.0-21.0 is safe for sample rate values up to 96KHz)
|
||||
* @param type Chorus waveform type (#fluid_chorus_mod)
|
||||
* 0.0-21.0 is safe for sample rate values up to 96KHz).
|
||||
* @param type Chorus waveform type (#fluid_chorus_mod).
|
||||
*/
|
||||
void
|
||||
fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
||||
|
@ -713,45 +785,8 @@ fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
|||
chorus->level = 0.1;
|
||||
}
|
||||
|
||||
/* initialize modulation depth (peak to peak) (in samples)*/
|
||||
chorus->mod_depth = (int)(chorus->depth_ms / 1000.0 /* convert modulation depth in ms to s*/
|
||||
* chorus->sample_rate);
|
||||
|
||||
if(chorus->mod_depth > MAX_SAMPLES)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
|
||||
chorus->mod_depth = MAX_SAMPLES;
|
||||
// set depth to maximum to avoid spamming console with above warning
|
||||
chorus->depth_ms = (chorus->mod_depth * 1000) / chorus->sample_rate;
|
||||
}
|
||||
|
||||
chorus->mod_depth /= 2; /* amplitude is peak to peek / 2 */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("depth_ms:%f, depth_samples/2:%d\n", chorus->depth_ms, chorus->mod_depth);
|
||||
#endif
|
||||
/* Initializes the modulated center position:
|
||||
mod_rate, center_pos_mod, and index rate.
|
||||
*/
|
||||
set_center_position(chorus); /* must be called before set_xxxx_frequency() */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("mod_rate:%d\n", chorus->mod_rate);
|
||||
#endif
|
||||
|
||||
/* initialize modulator frequency */
|
||||
for(i = 0; i < chorus->number_blocks; i++)
|
||||
{
|
||||
set_sinus_frequency(&chorus->mod[i].sinus,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)((360.0f / (float) chorus->number_blocks) * i));
|
||||
|
||||
set_triangle_frequency(&chorus->mod[i].triang,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)i / chorus->number_blocks);
|
||||
}
|
||||
/* update parameters dependant of sample rate */
|
||||
update_parameters_from_sample_rate(chorus);
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("lfo type:%d\n", chorus->type);
|
||||
|
@ -859,6 +894,32 @@ fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Applies a sample rate change on the chorus.
|
||||
* Note that while the chorus is used by calling any fluid_chorus_processXXX()
|
||||
* function, calling fluid_chorus_samplerate_change() isn't multi task safe.
|
||||
* To deal properly with this issue follow the steps:
|
||||
* 1) Stop chorus processing (i.e disable calling to any fluid_chorus_processXXX().
|
||||
* chorus functions.
|
||||
* 2) Change sample rate by calling fluid_chorus_samplerate_change().
|
||||
* 3) Restart chorus processing (i.e enabling calling any fluid_chorus_processXXX()
|
||||
* chorus functions.
|
||||
*
|
||||
* Another solution is to substitute step (2):
|
||||
* 2.1) delete the chorus by calling delete_fluid_chorus().
|
||||
* 2.2) create the chorus by calling new_fluid_chorus().
|
||||
*
|
||||
* @param chorus pointer on the chorus.
|
||||
* @param sample_rate new sample rate value.
|
||||
*/
|
||||
void
|
||||
fluid_chorus_samplerate_change(fluid_chorus_t *chorus, fluid_real_t sample_rate)
|
||||
{
|
||||
chorus->sample_rate = sample_rate;
|
||||
|
||||
/* update parameters dependant of sample rate */
|
||||
update_parameters_from_sample_rate(chorus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process chorus by mixing the result in output buffer.
|
||||
|
|
|
@ -53,6 +53,8 @@ void fluid_chorus_reset(fluid_chorus_t *chorus);
|
|||
|
||||
void fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
||||
fluid_real_t speed, fluid_real_t depth_ms, int type);
|
||||
void
|
||||
fluid_chorus_samplerate_change(fluid_chorus_t *chorus, fluid_real_t sample_rate);
|
||||
|
||||
void fluid_chorus_processmix(fluid_chorus_t *chorus, const fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
|
|
@ -679,11 +679,9 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
|
|||
{
|
||||
if(mixer->fx[i].chorus)
|
||||
{
|
||||
delete_fluid_chorus(mixer->fx[i].chorus);
|
||||
fluid_chorus_samplerate_change(mixer->fx[i].chorus, samplerate);
|
||||
}
|
||||
|
||||
mixer->fx[i].chorus = new_fluid_chorus(samplerate);
|
||||
|
||||
if(mixer->fx[i].reverb)
|
||||
{
|
||||
fluid_revmodel_samplerate_change(mixer->fx[i].reverb, samplerate);
|
||||
|
|
Loading…
Reference in a new issue