mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 06:51:54 +00:00
remove fluid_rvoice_mixer_set_threads() as rvoice event function
Changing the number of rendering threads on-the-fly is not considered to be a usecase. In fact it will cause glitchy audio if doing so while synthesizing because all rendering threads are killed and their mixdown buffers are reallocated. This change should fix glitchy audio that might occur at the beginning of synthesization, as the rvoice_event for thread allocation may be dispatched (too) late.
This commit is contained in:
parent
8f6a602495
commit
b70b24ce0a
5 changed files with 47 additions and 49 deletions
|
@ -109,7 +109,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 finished_voices_size, int bufs, int fx_bufs, fluid_real_t sample_rate, int extra_threads, int prio)
|
||||
{
|
||||
fluid_rvoice_eventhandler_t* eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
|
||||
if (eventhandler == NULL) {
|
||||
|
@ -131,7 +131,7 @@ new_fluid_rvoice_eventhandler(int queuesize,
|
|||
if (eventhandler->queue == NULL)
|
||||
goto error_recovery;
|
||||
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate, eventhandler);
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate, eventhandler, extra_threads, prio);
|
||||
if (eventhandler->mixer == NULL)
|
||||
goto error_recovery;
|
||||
|
||||
|
|
|
@ -48,7 +48,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 fx_bufs, fluid_real_t sample_rate, int, int);
|
||||
|
||||
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t*);
|
||||
|
||||
|
|
|
@ -117,10 +117,11 @@ struct _fluid_rvoice_mixer_t {
|
|||
|
||||
#if ENABLE_MIXER_THREADS
|
||||
static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t* mixer);
|
||||
static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count, int prio_level);
|
||||
#endif
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
|
||||
fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer, int current_blockcount)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -166,26 +167,26 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
|
|||
|
||||
|
||||
if (mixer->fx.with_reverb) {
|
||||
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
for (i=0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
reverb_process_func(mixer->fx.reverb, &in_rev[i], &out_rev_l[i], &out_rev_r[i]);
|
||||
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref,0,
|
||||
mixer->current_blockcount * FLUID_BUFSIZE);
|
||||
current_blockcount * FLUID_BUFSIZE);
|
||||
}
|
||||
|
||||
if (mixer->fx.with_chorus) {
|
||||
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
for (i=0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
chorus_process_func(mixer->fx.chorus, &in_ch[i], &out_ch_l[i], &out_ch_r[i]);
|
||||
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref,0,
|
||||
mixer->current_blockcount * FLUID_BUFSIZE);
|
||||
current_blockcount * FLUID_BUFSIZE);
|
||||
}
|
||||
|
||||
#ifdef LADSPA
|
||||
/* Run the signal through the LADSPA Fx unit. The buffers have already been
|
||||
* set up in fluid_rvoice_mixer_set_ladspa. */
|
||||
if (mixer->ladspa_fx) {
|
||||
fluid_ladspa_run(mixer->ladspa_fx, mixer->current_blockcount, FLUID_BUFSIZE);
|
||||
fluid_ladspa_run(mixer->ladspa_fx, current_blockcount, FLUID_BUFSIZE);
|
||||
fluid_check_fpe("LADSPA");
|
||||
}
|
||||
#endif
|
||||
|
@ -494,12 +495,11 @@ fluid_mixer_buffers_zero(fluid_mixer_buffers_t* buffers, int current_blockcount)
|
|||
static int
|
||||
fluid_mixer_buffers_init(fluid_mixer_buffers_t* buffers, fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
int samplecount;
|
||||
const int samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||
|
||||
buffers->mixer = mixer;
|
||||
buffers->buf_count = buffers->mixer->buffers.buf_count;
|
||||
buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
|
||||
samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||
buffers->buf_count = mixer->buffers.buf_count;
|
||||
buffers->fx_buf_count = mixer->buffers.fx_buf_count;
|
||||
|
||||
/* Local mono voice buf */
|
||||
buffers->local_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, samplecount, FLUID_DEFAULT_ALIGNMENT);
|
||||
|
@ -563,7 +563,7 @@ 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)
|
||||
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)
|
||||
{
|
||||
fluid_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
|
||||
if (mixer == NULL) {
|
||||
|
@ -599,6 +599,12 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate
|
|||
delete_fluid_rvoice_mixer(mixer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(fluid_rvoice_mixer_set_threads(mixer, extra_threads, prio) != FLUID_OK)
|
||||
{
|
||||
delete_fluid_rvoice_mixer(mixer);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return mixer;
|
||||
|
@ -837,10 +843,10 @@ fluid_mixer_thread_func (void* data)
|
|||
}
|
||||
|
||||
static void
|
||||
fluid_mixer_buffers_mix(fluid_mixer_buffers_t* dst, fluid_mixer_buffers_t* src)
|
||||
fluid_mixer_buffers_mix(fluid_mixer_buffers_t* dst, fluid_mixer_buffers_t* src, int current_blockcount)
|
||||
{
|
||||
int i,j;
|
||||
int scount = dst->mixer->current_blockcount * FLUID_BUFSIZE;
|
||||
int scount = current_blockcount * FLUID_BUFSIZE;
|
||||
int minbuf;
|
||||
fluid_real_t *FLUID_RESTRICT base_src;
|
||||
fluid_real_t *FLUID_RESTRICT base_dst;
|
||||
|
@ -906,8 +912,8 @@ fluid_mixer_buffers_mix(fluid_mixer_buffers_t* dst, fluid_mixer_buffers_t* src)
|
|||
/**
|
||||
* Go through all threads and see if someone is finished for mixing
|
||||
*/
|
||||
static FLUID_INLINE int
|
||||
fluid_mixer_mix_in(fluid_rvoice_mixer_t* mixer, int extra_threads)
|
||||
static int
|
||||
fluid_mixer_mix_in(fluid_rvoice_mixer_t* mixer, int extra_threads, int current_blockcount)
|
||||
{
|
||||
int i, result, hasmixed;
|
||||
do {
|
||||
|
@ -921,7 +927,7 @@ fluid_mixer_mix_in(fluid_rvoice_mixer_t* mixer, int extra_threads)
|
|||
break;
|
||||
case THREAD_BUF_VALID:
|
||||
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_NODATA);
|
||||
fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i]);
|
||||
fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i], current_blockcount);
|
||||
hasmixed = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -960,7 +966,7 @@ fluid_render_loop_multithread(fluid_rvoice_mixer_t* mixer, int current_blockcoun
|
|||
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
|
||||
|
||||
// If thread is finished, mix it in
|
||||
while (fluid_mixer_mix_in(mixer, extra_threads)) {
|
||||
while (fluid_mixer_mix_in(mixer, extra_threads, current_blockcount)) {
|
||||
// Otherwise get a voice and render it
|
||||
fluid_rvoice_t* rvoice = fluid_mixer_get_mt_rvoice(mixer);
|
||||
if (rvoice != NULL) {
|
||||
|
@ -985,7 +991,7 @@ fluid_render_loop_multithread(fluid_rvoice_mixer_t* mixer, int current_blockcoun
|
|||
}
|
||||
}
|
||||
//FLUID_LOG(FLUID_DBG, "Blockcount: %d, mixed %d of %d voices myself, waits = %d",
|
||||
// mixer->current_blockcount, test, mixer->active_voices, waits);
|
||||
// current_blockcount, test, mixer->active_voices, waits);
|
||||
}
|
||||
|
||||
static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t* mixer)
|
||||
|
@ -1010,21 +1016,16 @@ static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t* mixer)
|
|||
mixer->thread_count = 0;
|
||||
mixer->threads = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Update amount of extra mixer threads.
|
||||
* @param thread_count Number of extra mixer threads for multi-core rendering
|
||||
* @param prio_level real-time prio level for the extra mixer threads
|
||||
*/
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_threads)
|
||||
static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count, int prio_level)
|
||||
{
|
||||
#if ENABLE_MIXER_THREADS
|
||||
char name[16];
|
||||
int i;
|
||||
fluid_rvoice_mixer_t* mixer = obj;
|
||||
int thread_count = param[0].i;
|
||||
int prio_level = param[1].real;
|
||||
|
||||
// Kill all existing threads first
|
||||
if (mixer->thread_count)
|
||||
|
@ -1033,30 +1034,30 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_threads)
|
|||
}
|
||||
|
||||
if (thread_count == 0)
|
||||
return;
|
||||
return FLUID_OK;
|
||||
|
||||
// Now prepare the new threads
|
||||
fluid_atomic_int_set(&mixer->threads_should_terminate, 0);
|
||||
mixer->threads = FLUID_ARRAY(fluid_mixer_buffers_t, thread_count);
|
||||
if (mixer->threads == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return;
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
FLUID_MEMSET(mixer->threads, 0, thread_count*sizeof(fluid_mixer_buffers_t));
|
||||
mixer->thread_count = thread_count;
|
||||
for (i=0; i < thread_count; i++) {
|
||||
fluid_mixer_buffers_t* b = &mixer->threads[i];
|
||||
if (!fluid_mixer_buffers_init(b, mixer))
|
||||
return;
|
||||
return FLUID_FAILED;
|
||||
fluid_atomic_int_set(&b->ready, THREAD_BUF_NODATA);
|
||||
FLUID_SNPRINTF (name, sizeof (name), "mixer%d", i);
|
||||
b->thread = new_fluid_thread(name, fluid_mixer_thread_func, b, prio_level, 0);
|
||||
if (!b->thread)
|
||||
return;
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
#endif
|
||||
return FLUID_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Synthesize audio into buffers
|
||||
|
@ -1073,7 +1074,7 @@ fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
|
|||
// Zero buffers
|
||||
fluid_mixer_buffers_zero(&mixer->buffers, blockcount);
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref, mixer->active_voices,
|
||||
mixer->current_blockcount * FLUID_BUFSIZE);
|
||||
blockcount * FLUID_BUFSIZE);
|
||||
|
||||
#if ENABLE_MIXER_THREADS
|
||||
if (mixer->thread_count > 0)
|
||||
|
@ -1086,7 +1087,7 @@ fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
|
|||
|
||||
|
||||
// Process reverb & chorus
|
||||
fluid_rvoice_mixer_process_fx(mixer);
|
||||
fluid_rvoice_mixer_process_fx(mixer, blockcount);
|
||||
|
||||
// Call the callback and pack active voice array
|
||||
fluid_rvoice_mixer_process_finished_voices(mixer);
|
||||
|
|
|
@ -41,7 +41,7 @@ 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,
|
||||
fluid_real_t sample_rate, fluid_rvoice_eventhandler_t*);
|
||||
fluid_real_t sample_rate, fluid_rvoice_eventhandler_t*, int, int);
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
|
||||
|
||||
|
@ -57,7 +57,6 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params);
|
|||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus);
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_threads);
|
||||
|
||||
|
||||
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on);
|
||||
|
|
|
@ -589,7 +589,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
fluid_synth_t* synth;
|
||||
fluid_sfloader_t* loader;
|
||||
char *important_channels;
|
||||
int i, nbuf;
|
||||
int i, nbuf, prio_level = 0;
|
||||
int with_ladspa = 0;
|
||||
|
||||
/* initialize all the conversion tables and other stuff */
|
||||
|
@ -739,11 +739,17 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
fluid_atomic_int_set(&synth->ticks_since_start, 0);
|
||||
synth->tuning = NULL;
|
||||
fluid_private_init(synth->tuning_iter);
|
||||
|
||||
|
||||
/* Initialize multi-core variables if multiple cores enabled */
|
||||
if (synth->cores > 1)
|
||||
{
|
||||
fluid_settings_getint (synth->settings, "audio.realtime-prio", &prio_level);
|
||||
}
|
||||
|
||||
/* 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->polyphony, nbuf, synth->effects_channels, synth->sample_rate, synth->cores-1, prio_level);
|
||||
|
||||
if (synth->eventhandler == NULL)
|
||||
goto error_recovery;
|
||||
|
@ -866,15 +872,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
depth,
|
||||
FLUID_CHORUS_DEFAULT_TYPE);
|
||||
}
|
||||
|
||||
/* Initialize multi-core variables if multiple cores enabled */
|
||||
if (synth->cores > 1)
|
||||
{
|
||||
int prio_level = 0;
|
||||
fluid_settings_getint (synth->settings, "audio.realtime-prio", &prio_level);
|
||||
fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_threads,
|
||||
synth->cores-1, prio_level);
|
||||
}
|
||||
|
||||
|
||||
synth->bank_select = FLUID_BANK_STYLE_GS;
|
||||
if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "gm"))
|
||||
|
|
Loading…
Reference in a new issue