support multiple effects units

adds a new setting "synth.effects-groups" that allows multiple effects
units, in order to render effects of each midi channel to a separate
audio channel
This commit is contained in:
derselbst 2018-07-04 17:09:45 +02:00
parent 5ea6bed2d4
commit 88fda6f99b
8 changed files with 182 additions and 99 deletions

View file

@ -398,7 +398,9 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
}
fluid_settings_getint(settings, "synth.effects-channels", &dev->num_fx_ports);
fluid_settings_getint(settings, "synth.effects-groups", &i);
dev->num_fx_ports *= i;
dev->fx_ports = FLUID_ARRAY(jack_port_t *, 2 * dev->num_fx_ports);
if(dev->fx_ports == NULL)

View file

@ -114,7 +114,7 @@ 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, 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, int extra_threads, int prio)
{
fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
@ -145,7 +145,7 @@ new_fluid_rvoice_eventhandler(int queuesize,
goto error_recovery;
}
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate, eventhandler, extra_threads, prio);
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, 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, fluid_real_t sample_rate, int, int);
int fx_bufs, int fx_units, fluid_real_t sample_rate, int, int);
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *);

View file

@ -82,14 +82,11 @@ struct _fluid_mixer_fx_t
{
fluid_revmodel_t *reverb; /**< Reverb unit */
fluid_chorus_t *chorus; /**< Chorus unit */
int with_reverb; /**< Should the synth use the built-in reverb unit? */
int with_chorus; /**< Should the synth use the built-in chorus unit? */
int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
};
struct _fluid_rvoice_mixer_t
{
fluid_mixer_fx_t fx;
fluid_mixer_fx_t *fx;
fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
fluid_rvoice_eventhandler_t *eventhandler;
@ -98,6 +95,10 @@ struct _fluid_rvoice_mixer_t
int polyphony; /**< Read-only: Length of voices array */
int active_voices; /**< Read-only: Number of non-null voices */
int current_blockcount; /**< Read-only: how many blocks to process this time */
int fx_units;
int with_reverb; /**< Should the synth use the built-in reverb unit? */
int with_chorus; /**< Should the synth use the built-in chorus unit? */
int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
#ifdef LADSPA
fluid_ladspa_fx_t *ladspa_fx; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
@ -126,28 +127,26 @@ static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t *mixer, int threa
static FLUID_INLINE void
fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcount)
{
int i;
const int fx_channels_per_unit = mixer->buffers.fx_buf_count / mixer->fx_units;
int i, f;
void (*reverb_process_func)(fluid_revmodel_t *rev, fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
void (*chorus_process_func)(fluid_chorus_t *chorus, fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
fluid_real_t *out_rev_l, *out_rev_r, *out_ch_l, *out_ch_r;
// all dry unprocessed mono input is stored in the left channel
fluid_real_t *in_rev = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
fluid_real_t *in_ch = in_rev;
fluid_profile_ref_var(prof_ref);
in_rev = &in_rev[SYNTH_REVERB_CHANNEL * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
in_ch = &in_ch [SYNTH_CHORUS_CHANNEL * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
if(mixer->fx.mix_fx_to_out)
if(mixer->mix_fx_to_out)
{
out_rev_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
out_rev_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
out_ch_l = &out_rev_l[0 * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
out_ch_r = &out_rev_r[0 * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
// mix effects to first stereo channel
out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
reverb_process_func = fluid_revmodel_processmix;
chorus_process_func = fluid_chorus_processmix;
@ -155,36 +154,51 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun
}
else
{
// mix effects to respective stereo effects channel
out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
out_rev_l = &out_rev_l[SYNTH_REVERB_CHANNEL * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
out_rev_r = &out_rev_r[SYNTH_REVERB_CHANNEL * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
out_ch_l = &out_ch_l[SYNTH_CHORUS_CHANNEL * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
out_ch_r = &out_ch_r[SYNTH_CHORUS_CHANNEL * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE];
reverb_process_func = fluid_revmodel_processreplace;
chorus_process_func = fluid_chorus_processreplace;
}
if(mixer->fx.with_reverb)
if(mixer->with_reverb)
{
for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
for(f = 0; f < mixer->fx_units; f++)
{
reverb_process_func(mixer->fx.reverb, &in_rev[i], &out_rev_l[i], &out_rev_r[i]);
int buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL;
for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
{
int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + i;
reverb_process_func(mixer->fx[f].reverb,
&in_rev[samp_idx],
mixer->mix_fx_to_out ? &out_rev_l[i] : &out_rev_l[samp_idx],
mixer->mix_fx_to_out ? &out_rev_r[i] : &out_rev_r[samp_idx]);
}
}
fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref, 0,
current_blockcount * FLUID_BUFSIZE);
}
if(mixer->fx.with_chorus)
if(mixer->with_chorus)
{
for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
for(f = 0; f < mixer->fx_units; f++)
{
chorus_process_func(mixer->fx.chorus, &in_ch[i], &out_ch_l[i], &out_ch_r[i]);
int buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL;
for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
{
int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + i;
chorus_process_func(mixer->fx[f].chorus,
&in_ch [samp_idx],
mixer->mix_fx_to_out ? &out_ch_l[i] : &out_ch_l[samp_idx],
mixer->mix_fx_to_out ? &out_ch_r[i] : &out_ch_r[samp_idx]);
}
}
fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref, 0,
@ -213,8 +227,10 @@ fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbu
{
fluid_real_t *base_ptr;
int i;
int with_reverb = buffers->mixer->fx.with_reverb;
int with_chorus = buffers->mixer->fx.with_chorus;
const int fx_channels_per_unit = buffers->fx_buf_count / buffers->mixer->fx_units;
const int offset = buffers->buf_count * 2;
int with_reverb = buffers->mixer->with_reverb;
int with_chorus = buffers->mixer->with_chorus;
/* Set up the reverb and chorus buffers only when the effect is enabled or
* when LADSPA is active. Nonexisting buffers are detected in the DSP loop.
@ -225,11 +241,24 @@ fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbu
with_chorus = (with_chorus | with_ladspa);
#endif
// all the dry, non-processed mono audio for effects is to be stored in the left buffers
base_ptr = fluid_align_ptr(buffers->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
outbufs[buffers->buf_count * 2 + SYNTH_REVERB_CHANNEL] = (with_reverb) ? &base_ptr[SYNTH_REVERB_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT] : NULL;
outbufs[buffers->buf_count * 2 + SYNTH_CHORUS_CHANNEL] = (with_chorus) ? &base_ptr[SYNTH_CHORUS_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT] : NULL;
for(i = 0; i < buffers->mixer->fx_units; i++)
{
int fx_idx = i * fx_channels_per_unit;
outbufs[offset + fx_idx + SYNTH_REVERB_CHANNEL] =
(with_reverb)
? &base_ptr[(fx_idx + SYNTH_REVERB_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
: NULL;
outbufs[offset + fx_idx + SYNTH_CHORUS_CHANNEL] =
(with_chorus)
? &base_ptr[(fx_idx + SYNTH_CHORUS_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
: NULL;
}
/* The output associated with a MIDI channel is wrapped around
* using the number of audio groups as modulo divider. This is
* typically the number of output channels on the 'sound card',
@ -256,7 +285,7 @@ fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbu
outbufs[i * 2 + 1] = &base_ptr[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
}
return buffers->buf_count * 2 + 2;
return offset + buffers->fx_buf_count;
}
@ -628,16 +657,20 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
fluid_rvoice_mixer_t *mixer = obj;
fluid_real_t samplerate = param[1].real; // becausee fluid_synth_update_mixer() puts real into arg2
if(mixer->fx.chorus)
int i;
for(i = 0; i < mixer->fx_units; i++)
{
delete_fluid_chorus(mixer->fx.chorus);
}
if(mixer->fx[i].chorus)
{
delete_fluid_chorus(mixer->fx[i].chorus);
}
mixer->fx.chorus = new_fluid_chorus(samplerate);
mixer->fx[i].chorus = new_fluid_chorus(samplerate);
if(mixer->fx.reverb)
{
fluid_revmodel_samplerate_change(mixer->fx.reverb, samplerate);
if(mixer->fx[i].reverb)
{
fluid_revmodel_samplerate_change(mixer->fx[i].reverb, samplerate);
}
}
#if LADSPA
@ -656,8 +689,9 @@ 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, 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, fluid_rvoice_eventhandler_t *evthandler, int extra_threads, int prio)
{
int i;
fluid_rvoice_mixer_t *mixer = FLUID_NEW(fluid_rvoice_mixer_t);
if(mixer == NULL)
@ -668,18 +702,25 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate
FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
mixer->eventhandler = evthandler;
mixer->fx_units = fx_units;
mixer->buffers.buf_count = buf_count;
mixer->buffers.fx_buf_count = fx_buf_count;
mixer->buffers.fx_buf_count = fx_buf_count * fx_units;
/* allocate the reverb module */
mixer->fx.reverb = new_fluid_revmodel(sample_rate);
mixer->fx.chorus = new_fluid_chorus(sample_rate);
if(mixer->fx.reverb == NULL || mixer->fx.chorus == NULL)
mixer->fx = FLUID_ARRAY(fluid_mixer_fx_t, fx_units);
FLUID_MEMSET(mixer->fx, 0, fx_units * sizeof(*mixer->fx));
for(i = 0; i < fx_units; i++)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
delete_fluid_rvoice_mixer(mixer);
return NULL;
mixer->fx[i].reverb = new_fluid_revmodel(sample_rate);
mixer->fx[i].chorus = new_fluid_chorus(sample_rate);
if(mixer->fx[i].reverb == NULL || mixer->fx[i].chorus == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
delete_fluid_rvoice_mixer(mixer);
return NULL;
}
}
if(!fluid_mixer_buffers_init(&mixer->buffers, mixer))
@ -727,6 +768,8 @@ fluid_mixer_buffers_free(fluid_mixer_buffers_t *buffers)
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer)
{
int i;
fluid_return_if_fail(mixer != NULL);
#if ENABLE_MIXER_THREADS
@ -755,16 +798,21 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer)
#endif
fluid_mixer_buffers_free(&mixer->buffers);
if(mixer->fx.reverb)
for(i = 0; i < mixer->fx_units; i++)
{
delete_fluid_revmodel(mixer->fx.reverb);
}
if(mixer->fx.chorus)
{
delete_fluid_chorus(mixer->fx.chorus);
if(mixer->fx[i].reverb)
{
delete_fluid_revmodel(mixer->fx[i].reverb);
}
if(mixer->fx[i].chorus)
{
delete_fluid_chorus(mixer->fx[i].chorus);
}
}
FLUID_FREE(mixer->fx);
FLUID_FREE(mixer->rvoices);
FLUID_FREE(mixer);
}
@ -818,19 +866,19 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled)
fluid_rvoice_mixer_t *mixer = obj;
int on = param[0].i;
mixer->fx.with_reverb = on;
mixer->with_reverb = on;
}
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled)
{
fluid_rvoice_mixer_t *mixer = obj;
int on = param[0].i;
mixer->fx.with_chorus = on;
mixer->with_chorus = on;
}
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on)
{
mixer->fx.mix_fx_to_out = on;
mixer->mix_fx_to_out = on;
}
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params)
@ -843,7 +891,11 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params)
fluid_real_t depth_ms = param[4].real;
int type = param[5].i;
fluid_chorus_set(mixer->fx.chorus, set, nr, level, speed, depth_ms, type);
int i;
for(i = 0; i < mixer->fx_units; i++)
{
fluid_chorus_set(mixer->fx[i].chorus, set, nr, level, speed, depth_ms, type);
}
}
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params)
@ -855,19 +907,31 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params)
fluid_real_t width = param[3].real;
fluid_real_t level = param[4].real;
fluid_revmodel_set(mixer->fx.reverb, set, roomsize, damping, width, level);
int i;
for(i = 0; i < mixer->fx_units; i++)
{
fluid_revmodel_set(mixer->fx[i].reverb, set, roomsize, damping, width, level);
}
}
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb)
{
fluid_rvoice_mixer_t *mixer = obj;
fluid_revmodel_reset(mixer->fx.reverb);
int i;
for(i = 0; i < mixer->fx_units; i++)
{
fluid_revmodel_reset(mixer->fx[i].reverb);
}
}
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus)
{
fluid_rvoice_mixer_t *mixer = obj;
fluid_chorus_reset(mixer->fx.chorus);
int i;
for(i = 0; i < mixer->fx_units; i++)
{
fluid_chorus_reset(mixer->fx[i].chorus);
}
}
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t *mixer,

View file

@ -37,7 +37,7 @@ int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer);
#if WITH_PROFILING
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,
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);
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *);

View file

@ -223,6 +223,7 @@ void fluid_synth_settings(fluid_settings_t *settings)
fluid_settings_register_int(settings, "synth.audio-channels", 1, 1, 128, 0);
fluid_settings_register_int(settings, "synth.audio-groups", 1, 1, 128, 0);
fluid_settings_register_int(settings, "synth.effects-channels", 2, 2, 2, 0);
fluid_settings_register_int(settings, "synth.effects-groups", 1, 1, 128, 0);
fluid_settings_register_num(settings, "synth.sample-rate", 44100.0f, 8000.0f, 96000.0f, 0);
fluid_settings_register_int(settings, "synth.device-id", 0, 0, 126, 0);
fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 256, 0);
@ -638,6 +639,7 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels);
fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
fluid_settings_getint(settings, "synth.effects-groups", &synth->effects_groups);
fluid_settings_getnum_float(settings, "synth.gain", &synth->gain);
fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
@ -776,7 +778,7 @@ 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->sample_rate, synth->cores - 1, prio_level);
synth->polyphony, nbuf, synth->effects_channels, synth->effects_groups, synth->sample_rate, synth->cores - 1, prio_level);
if(synth->eventhandler == NULL)
{
@ -3534,10 +3536,10 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
{
fluid_real_t *left_in, *fx_left_in;
fluid_real_t *right_in, *fx_right_in;
int nfxchan, naudchan;
int nfxchan, nfxunits, naudchan;
double time = fluid_utime();
int i, num, count;
int i, f, num, count;
float cpu_load;
@ -3546,9 +3548,10 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
fluid_return_val_if_fail(nout % 2 == 0, FLUID_FAILED);
nfxchan = synth->effects_channels;
nfxunits = synth->effects_groups;
naudchan = synth->audio_channels;
fluid_return_val_if_fail(0 <= nfx / 2 && nfx / 2 <= nfxchan, FLUID_FAILED);
fluid_return_val_if_fail(0 <= nfx / 2 && nfx / 2 <= nfxchan * nfxunits, FLUID_FAILED);
fluid_return_val_if_fail(0 <= nout / 2 && nout / 2 <= naudchan, FLUID_FAILED);
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
@ -3594,26 +3597,32 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
if(nfx != 0)
{
for(i = 0; i < nfxchan; i++)
// loop over all effects units
for(f = 0; f < nfxunits; f++)
{
int j;
float *out_buf = fx[(i * 2) % nfx];
if(out_buf != NULL)
// write out all effects (i.e. reverb and chorus)
for(i = 0; i < nfxchan; i++)
{
for(j = 0; j < num; j++)
int j;
int buf_idx = f * nfxchan + i;
float *out_buf = fx[(buf_idx * 2) % nfx];
if(out_buf != NULL)
{
out_buf[j] += (float) fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
for(j = 0; j < num; j++)
{
out_buf[j] += (float) fx_left_in[buf_idx * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
}
}
}
out_buf = fx[(i * 2 + 1) % nfx];
out_buf = fx[(buf_idx * 2 + 1) % nfx];
if(out_buf != NULL)
{
for(j = 0; j < num; j++)
if(out_buf != NULL)
{
out_buf[j] += (float) fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
for(j = 0; j < num; j++)
{
out_buf[j] += (float) fx_right_in[buf_idx * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
}
}
}
}
@ -3660,26 +3669,32 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
if(nfx != 0)
{
for(i = 0; i < nfxchan; i++)
// loop over all effects units
for(f = 0; f < nfxunits; f++)
{
int j;
float *out_buf = fx[(i * 2) % nfx];
if(out_buf != NULL)
// write out all effects (i.e. reverb and chorus)
for(i = 0; i < nfxchan; i++)
{
for(j = 0; j < num; j++)
int j;
int buf_idx = f * nfxchan + i;
float *out_buf = fx[(buf_idx * 2) % nfx];
if(out_buf != NULL)
{
out_buf[j + count] += (float) fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
for(j = 0; j < num; j++)
{
out_buf[j + count] += (float) fx_left_in[buf_idx * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
}
}
}
out_buf = fx[(i * 2 + 1) % nfx];
out_buf = fx[(buf_idx * 2 + 1) % nfx];
if(out_buf != NULL)
{
for(j = 0; j < num; j++)
if(out_buf != NULL)
{
out_buf[j + count] += (float) fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
for(j = 0; j < num; j++)
{
out_buf[j + count] += (float) fx_right_in[buf_idx * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
}
}
}
}

View file

@ -118,6 +118,7 @@ struct _fluid_synth_t
int audio_groups; /**< the number of (stereo) 'sub'groups from the synth.
Typically equal to audio_channels. */
int effects_channels; /**< the number of effects channels (>= 2) */
int effects_groups; /**< the number of effects units (>= 1) */
int state; /**< the synthesizer state */
fluid_atomic_uint_t ticks_since_start; /**< the number of audio samples since the start */
unsigned int start; /**< the start in msec, as returned by system clock */

View file

@ -352,11 +352,12 @@ fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, voice->synth_gain);
/* Set up buffer mapping, should be done more flexible in the future. */
i = channel->synth->audio_groups;
UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 2, i * 2 + SYNTH_REVERB_CHANNEL);
UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 3, i * 2 + SYNTH_CHORUS_CHANNEL);
i = 2 * channel->synth->audio_groups;
i += (voice->chan % channel->synth->effects_groups) * channel->synth->effects_channels;
UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 2, i + SYNTH_REVERB_CHANNEL);
UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 3, i + SYNTH_CHORUS_CHANNEL);
i = 2 * (voice->chan % i);
i = 2 * (voice->chan % channel->synth->audio_groups);
UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 0, i);
UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 1, i + 1);