1. 算法原理
合唱即多人一起唱歌,以下是算法的原理图:
/*
*
* * gain-in ___
* ibuff -----+--------------------------------------------->| |
* | _________ | |
* | | | * level 1 | |
* +---->| delay 1 |----------------------------->| |
* | |_________| | |
* | /|\ | |
* : | | |
* : +-----------------+ +--------------+ | + |
* : | Delay control 1 |<--| mod. speed 1 | | |
* : +-----------------+ +--------------+ | |
* | _________ | |
* | | | * level n | |
* +---->| delay n |----------------------------->| |
* |_________| | |
* /|\ |___|
* | |
* +-----------------+ +--------------+ | * gain-out
* | Delay control n |<--| mod. speed n | |
* +-----------------+ +--------------+ +----->obuff
*
*
*/
2. 代码实现
void dsound_chorus_processmix(dsound_chorus_t* chorus, dsound_real_t *in,
dsound_real_t *left_out, dsound_real_t *right_out)
{
int sample_index;
int i;
dsound_real_t d_in, d_out;
for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
d_in = in[sample_index];
d_out = 0.0f;
# if 0
/* Debug: Listen to the chorus signal only */
left_out[sample_index]=0;
right_out[sample_index]=0;
#endif
/* Write the current sample into the circular buffer */
chorus->chorusbuf[chorus->counter] = d_in;
for (i = 0; i < chorus->number_blocks; i++) {
int ii;
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
/* The value in the lookup table is so, that this expression
* will always be positive. It will always include a number of
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
* remain positive at all times. */
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
- chorus->lookup_tab[chorus->phase[i]]);
int pos_samples = pos_subsamples/INTERPOLATION_SUBSAMPLES;
/* modulo divide by INTERPOLATION_SUBSAMPLES */
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
/* Add the delayed signal to the chorus sum d_out Note: The
* delay in the delay line moves backwards for increasing
* delay!*/
/* The & in chorusbuf[...] is equivalent to a division modulo
MAX_SAMPLES, only faster. */
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
* chorus->sinc_table[ii][pos_subsamples];
pos_samples--;
};
/* Cycle the phase of the modulating LFO */
chorus->phase[i]++;
chorus->phase[i] %= (chorus->modulation_period_samples);
} /* foreach chorus block */
d_out *= chorus->level;
/* Add the chorus sum d_out to output */
left_out[sample_index] += d_out;
right_out[sample_index] += d_out;
/* Move forward in circular buffer */
chorus->counter++;
chorus->counter %= MAX_SAMPLES;
} /* foreach sample */
}