mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-24 04:42:03 +00:00
Fix incorrect samplerate for reverb and chorus, closes ticket #89.
Thanks to jaz001 for the patch!
This commit is contained in:
parent
2479c03b78
commit
f84a9b9885
6 changed files with 111 additions and 92 deletions
|
@ -72,18 +72,25 @@ struct _fluid_allpass {
|
|||
};
|
||||
|
||||
void fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size);
|
||||
void fluid_allpass_release(fluid_comb* comb);
|
||||
void fluid_allpass_init(fluid_allpass* allpass);
|
||||
void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
|
||||
fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
|
||||
|
||||
void
|
||||
fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size)
|
||||
fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
|
||||
{
|
||||
allpass->bufidx = 0;
|
||||
allpass->buffer = buf;
|
||||
allpass->buffer = FLUID_ARRAY(fluid_real_t,size);
|
||||
allpass->bufsize = size;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_allpass_release(fluid_allpass* allpass)
|
||||
{
|
||||
FLUID_FREE(allpass->buffer);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_allpass_init(fluid_allpass* allpass)
|
||||
{
|
||||
|
@ -144,7 +151,8 @@ struct _fluid_comb {
|
|||
int bufidx;
|
||||
};
|
||||
|
||||
void fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size);
|
||||
void fluid_comb_setbuffer(fluid_comb* comb, int size);
|
||||
void fluid_comb_release(fluid_comb* comb);
|
||||
void fluid_comb_init(fluid_comb* comb);
|
||||
void fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val);
|
||||
fluid_real_t fluid_comb_getdamp(fluid_comb* comb);
|
||||
|
@ -152,14 +160,20 @@ void fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val);
|
|||
fluid_real_t fluid_comb_getfeedback(fluid_comb* comb);
|
||||
|
||||
void
|
||||
fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size)
|
||||
fluid_comb_setbuffer(fluid_comb* comb, int size)
|
||||
{
|
||||
comb->filterstore = 0;
|
||||
comb->bufidx = 0;
|
||||
comb->buffer = buf;
|
||||
comb->buffer = FLUID_ARRAY(fluid_real_t,size);
|
||||
comb->bufsize = size;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_release(fluid_comb* comb)
|
||||
{
|
||||
FLUID_FREE(comb->buffer);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_init(fluid_comb* comb)
|
||||
{
|
||||
|
@ -244,29 +258,29 @@ fluid_comb_getfeedback(fluid_comb* comb)
|
|||
The values were obtained by listening tests.
|
||||
*/
|
||||
#define combtuningL1 1116
|
||||
#define combtuningR1 1116 + stereospread
|
||||
#define combtuningR1 (1116 + stereospread)
|
||||
#define combtuningL2 1188
|
||||
#define combtuningR2 1188 + stereospread
|
||||
#define combtuningR2 (1188 + stereospread)
|
||||
#define combtuningL3 1277
|
||||
#define combtuningR3 1277 + stereospread
|
||||
#define combtuningR3 (1277 + stereospread)
|
||||
#define combtuningL4 1356
|
||||
#define combtuningR4 1356 + stereospread
|
||||
#define combtuningR4 (1356 + stereospread)
|
||||
#define combtuningL5 1422
|
||||
#define combtuningR5 1422 + stereospread
|
||||
#define combtuningR5 (1422 + stereospread)
|
||||
#define combtuningL6 1491
|
||||
#define combtuningR6 1491 + stereospread
|
||||
#define combtuningR6 (1491 + stereospread)
|
||||
#define combtuningL7 1557
|
||||
#define combtuningR7 1557 + stereospread
|
||||
#define combtuningR7 (1557 + stereospread)
|
||||
#define combtuningL8 1617
|
||||
#define combtuningR8 1617 + stereospread
|
||||
#define combtuningR8 (1617 + stereospread)
|
||||
#define allpasstuningL1 556
|
||||
#define allpasstuningR1 556 + stereospread
|
||||
#define allpasstuningR1 (556 + stereospread)
|
||||
#define allpasstuningL2 441
|
||||
#define allpasstuningR2 441 + stereospread
|
||||
#define allpasstuningR2 (441 + stereospread)
|
||||
#define allpasstuningL3 341
|
||||
#define allpasstuningR3 341 + stereospread
|
||||
#define allpasstuningR3 (341 + stereospread)
|
||||
#define allpasstuningL4 225
|
||||
#define allpasstuningR4 225 + stereospread
|
||||
#define allpasstuningR4 (225 + stereospread)
|
||||
|
||||
struct _fluid_revmodel_t {
|
||||
fluid_real_t roomsize;
|
||||
|
@ -285,39 +299,14 @@ struct _fluid_revmodel_t {
|
|||
/* Allpass filters */
|
||||
fluid_allpass allpassL[numallpasses];
|
||||
fluid_allpass allpassR[numallpasses];
|
||||
/* Buffers for the combs */
|
||||
fluid_real_t bufcombL1[combtuningL1];
|
||||
fluid_real_t bufcombR1[combtuningR1];
|
||||
fluid_real_t bufcombL2[combtuningL2];
|
||||
fluid_real_t bufcombR2[combtuningR2];
|
||||
fluid_real_t bufcombL3[combtuningL3];
|
||||
fluid_real_t bufcombR3[combtuningR3];
|
||||
fluid_real_t bufcombL4[combtuningL4];
|
||||
fluid_real_t bufcombR4[combtuningR4];
|
||||
fluid_real_t bufcombL5[combtuningL5];
|
||||
fluid_real_t bufcombR5[combtuningR5];
|
||||
fluid_real_t bufcombL6[combtuningL6];
|
||||
fluid_real_t bufcombR6[combtuningR6];
|
||||
fluid_real_t bufcombL7[combtuningL7];
|
||||
fluid_real_t bufcombR7[combtuningR7];
|
||||
fluid_real_t bufcombL8[combtuningL8];
|
||||
fluid_real_t bufcombR8[combtuningR8];
|
||||
/* Buffers for the allpasses */
|
||||
fluid_real_t bufallpassL1[allpasstuningL1];
|
||||
fluid_real_t bufallpassR1[allpasstuningR1];
|
||||
fluid_real_t bufallpassL2[allpasstuningL2];
|
||||
fluid_real_t bufallpassR2[allpasstuningR2];
|
||||
fluid_real_t bufallpassL3[allpasstuningL3];
|
||||
fluid_real_t bufallpassR3[allpasstuningR3];
|
||||
fluid_real_t bufallpassL4[allpasstuningL4];
|
||||
fluid_real_t bufallpassR4[allpasstuningR4];
|
||||
};
|
||||
|
||||
static void fluid_revmodel_update(fluid_revmodel_t* rev);
|
||||
static void fluid_revmodel_init(fluid_revmodel_t* rev);
|
||||
void fluid_set_revmodel_buffers(fluid_revmodel_t* rev, int sample_rate);
|
||||
|
||||
fluid_revmodel_t*
|
||||
new_fluid_revmodel()
|
||||
new_fluid_revmodel(int sample_rate)
|
||||
{
|
||||
fluid_revmodel_t* rev;
|
||||
rev = FLUID_NEW(fluid_revmodel_t);
|
||||
|
@ -325,31 +314,8 @@ new_fluid_revmodel()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Tie the components to their buffers */
|
||||
fluid_comb_setbuffer(&rev->combL[0], rev->bufcombL1, combtuningL1);
|
||||
fluid_comb_setbuffer(&rev->combR[0], rev->bufcombR1, combtuningR1);
|
||||
fluid_comb_setbuffer(&rev->combL[1], rev->bufcombL2, combtuningL2);
|
||||
fluid_comb_setbuffer(&rev->combR[1], rev->bufcombR2, combtuningR2);
|
||||
fluid_comb_setbuffer(&rev->combL[2], rev->bufcombL3, combtuningL3);
|
||||
fluid_comb_setbuffer(&rev->combR[2], rev->bufcombR3, combtuningR3);
|
||||
fluid_comb_setbuffer(&rev->combL[3], rev->bufcombL4, combtuningL4);
|
||||
fluid_comb_setbuffer(&rev->combR[3], rev->bufcombR4, combtuningR4);
|
||||
fluid_comb_setbuffer(&rev->combL[4], rev->bufcombL5, combtuningL5);
|
||||
fluid_comb_setbuffer(&rev->combR[4], rev->bufcombR5, combtuningR5);
|
||||
fluid_comb_setbuffer(&rev->combL[5], rev->bufcombL6, combtuningL6);
|
||||
fluid_comb_setbuffer(&rev->combR[5], rev->bufcombR6, combtuningR6);
|
||||
fluid_comb_setbuffer(&rev->combL[6], rev->bufcombL7, combtuningL7);
|
||||
fluid_comb_setbuffer(&rev->combR[6], rev->bufcombR7, combtuningR7);
|
||||
fluid_comb_setbuffer(&rev->combL[7], rev->bufcombL8, combtuningL8);
|
||||
fluid_comb_setbuffer(&rev->combR[7], rev->bufcombR8, combtuningR8);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[0], rev->bufallpassL1, allpasstuningL1);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[0], rev->bufallpassR1, allpasstuningR1);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[1], rev->bufallpassL2, allpasstuningL2);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[1], rev->bufallpassR2, allpasstuningR2);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[2], rev->bufallpassL3, allpasstuningL3);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[2], rev->bufallpassR3, allpasstuningR3);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[3], rev->bufallpassL4, allpasstuningL4);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[3], rev->bufallpassR4, allpasstuningR4);
|
||||
fluid_set_revmodel_buffers(rev, sample_rate);
|
||||
|
||||
/* Set default values */
|
||||
fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
|
||||
|
@ -360,28 +326,63 @@ new_fluid_revmodel()
|
|||
fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
|
||||
|
||||
/* set values manually, since calling set functions causes update
|
||||
and all values should be initialized for an update */
|
||||
rev->roomsize = initialroom * scaleroom + offsetroom;
|
||||
rev->damp = initialdamp * scaledamp;
|
||||
rev->wet = initialwet * scalewet;
|
||||
rev->width = initialwidth;
|
||||
rev->gain = fixedgain;
|
||||
fluid_revmodel_set(rev,FLUID_REVMODEL_SET_ALL,initialroom,initialdamp,initialwidth,initialwet);
|
||||
|
||||
/* now its okay to update reverb */
|
||||
fluid_revmodel_update(rev);
|
||||
|
||||
/* Clear all buffers */
|
||||
fluid_revmodel_init(rev);
|
||||
return rev;
|
||||
}
|
||||
|
||||
void
|
||||
delete_fluid_revmodel(fluid_revmodel_t* rev)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < numcombs;i++) {
|
||||
fluid_comb_release(&rev->combL[i]);
|
||||
fluid_comb_release(&rev->combR[i]);
|
||||
}
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_release(&rev->allpassL[i]);
|
||||
fluid_allpass_release(&rev->allpassR[i]);
|
||||
}
|
||||
|
||||
FLUID_FREE(rev);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_set_revmodel_buffers(fluid_revmodel_t* rev, int sample_rate) {
|
||||
|
||||
float srfactor = sample_rate/44100.0f;
|
||||
|
||||
fluid_comb_setbuffer(&rev->combL[0], combtuningL1*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[0], combtuningR1*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[1], combtuningL2*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[1], combtuningR2*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[2], combtuningL3*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[2], combtuningR3*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[3], combtuningL4*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[3], combtuningR4*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[4], combtuningL5*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[4], combtuningR5*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[5], combtuningL6*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[5], combtuningR6*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[6], combtuningL7*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[6], combtuningR7*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[7], combtuningL8*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[7], combtuningR8*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[0], allpasstuningL1*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[0], allpasstuningR1*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[1], allpasstuningL2*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[1], allpasstuningR2*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[2], allpasstuningL3*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[2], allpasstuningR3*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[3], allpasstuningL4*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[3], allpasstuningR4*srfactor);
|
||||
|
||||
/* Clear all buffers */
|
||||
fluid_revmodel_init(rev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fluid_revmodel_init(fluid_revmodel_t* rev)
|
||||
{
|
||||
|
@ -417,7 +418,7 @@ fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
|
|||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2 * in[k] + DC_OFFSET) * rev->gain;
|
||||
input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
|
||||
|
||||
/* Accumulate comb filters in parallel */
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
|
@ -455,7 +456,7 @@ fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
|||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2 * in[k] + DC_OFFSET) * rev->gain;
|
||||
input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
|
||||
|
||||
/* Accumulate comb filters in parallel */
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
|
@ -484,8 +485,8 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
|
|||
/* Recalculate internal values after parameter change */
|
||||
int i;
|
||||
|
||||
rev->wet1 = rev->wet * (rev->width / 2 + 0.5f);
|
||||
rev->wet2 = rev->wet * ((1 - rev->width) / 2);
|
||||
rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
|
||||
rev->wet2 = rev->wet * ((1.0f - rev->width) / 2.0f);
|
||||
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
|
||||
|
@ -529,3 +530,17 @@ fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
|
|||
|
||||
fluid_revmodel_update (rev);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, int sample_rate) {
|
||||
int i;
|
||||
for (i = 0; i < numcombs;i++) {
|
||||
fluid_comb_release(&rev->combL[i]);
|
||||
fluid_comb_release(&rev->combR[i]);
|
||||
}
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_release(&rev->allpassL[i]);
|
||||
fluid_allpass_release(&rev->allpassR[i]);
|
||||
}
|
||||
fluid_set_revmodel_buffers(rev, sample_rate);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ typedef struct _fluid_revmodel_presets_t {
|
|||
/*
|
||||
* reverb
|
||||
*/
|
||||
fluid_revmodel_t* new_fluid_revmodel(void);
|
||||
fluid_revmodel_t* new_fluid_revmodel(int sample_rate);
|
||||
void delete_fluid_revmodel(fluid_revmodel_t* rev);
|
||||
|
||||
void fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
|
@ -68,4 +68,6 @@ void fluid_revmodel_reset(fluid_revmodel_t* rev);
|
|||
void fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
|
||||
float damping, float width, float level);
|
||||
|
||||
void fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, int sample_rate);
|
||||
|
||||
#endif /* _FLUID_REV_H */
|
||||
|
|
|
@ -220,7 +220,7 @@ finished_voice_callback(void* userdata, fluid_rvoice_t* rvoice)
|
|||
}
|
||||
|
||||
fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
|
||||
int is_threadsafe, int queuesize, int finished_voices_size, int bufs, int fx_bufs)
|
||||
int is_threadsafe, int queuesize, int finished_voices_size, int bufs, int fx_bufs, int sample_rate)
|
||||
{
|
||||
fluid_rvoice_eventhandler_t* eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
|
||||
if (eventhandler == NULL) {
|
||||
|
@ -242,7 +242,7 @@ fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
|
|||
if (eventhandler->queue == NULL)
|
||||
goto error_recovery;
|
||||
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs);
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate);
|
||||
if (eventhandler->mixer == NULL)
|
||||
goto error_recovery;
|
||||
fluid_rvoice_mixer_set_finished_voices_callback(eventhandler->mixer,
|
||||
|
|
|
@ -519,6 +519,8 @@ fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samp
|
|||
if (mixer->fx.chorus)
|
||||
delete_fluid_chorus(mixer->fx.chorus);
|
||||
mixer->fx.chorus = new_fluid_chorus(samplerate);
|
||||
if (mixer->fx.reverb)
|
||||
fluid_revmodel_samplerate_change(mixer->fx.reverb, samplerate);
|
||||
for (i=0; i < mixer->active_voices; i++)
|
||||
fluid_rvoice_set_output_rate(mixer->rvoices[i], samplerate);
|
||||
}
|
||||
|
@ -529,7 +531,7 @@ fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samp
|
|||
* @param fx_buf_count number of stereo effect buffers
|
||||
*/
|
||||
fluid_rvoice_mixer_t*
|
||||
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count)
|
||||
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int sample_rate)
|
||||
{
|
||||
fluid_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
|
||||
if (mixer == NULL) {
|
||||
|
@ -542,8 +544,8 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count)
|
|||
mixer->buffers.buf_blocks = FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||
|
||||
/* allocate the reverb module */
|
||||
mixer->fx.reverb = new_fluid_revmodel();
|
||||
mixer->fx.chorus = new_fluid_chorus(44100); /* FIXME: Hardcoded sample rate */
|
||||
mixer->fx.reverb = new_fluid_revmodel(sample_rate);
|
||||
mixer->fx.chorus = new_fluid_chorus(sample_rate);
|
||||
if (mixer->fx.reverb == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
delete_fluid_rvoice_mixer(mixer);
|
||||
|
|
|
@ -41,7 +41,7 @@ int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount);
|
|||
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_real_t*** left, fluid_real_t*** right);
|
||||
|
||||
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count);
|
||||
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int sample_rate);
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
|
||||
|
||||
|
|
|
@ -665,7 +665,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
/* In an overflow situation, a new voice takes about 50 spaces in the queue! */
|
||||
synth->eventhandler = new_fluid_rvoice_eventhandler(i, synth->polyphony*64,
|
||||
synth->polyphony,
|
||||
nbuf, synth->effects_channels);
|
||||
nbuf, synth->effects_channels, (int)synth->sample_rate);
|
||||
if (synth->eventhandler == NULL)
|
||||
goto error_recovery;
|
||||
|
||||
|
|
Loading…
Reference in a new issue