Rewrite overflow so that an extra rvoice is used, and make sure samples are ref/dref under mutex.

This commit is contained in:
David Henningsson 2011-03-27 13:54:52 +00:00
parent cabb6ad315
commit f7d87aa1a8
5 changed files with 108 additions and 49 deletions

View file

@ -648,13 +648,8 @@ void fluid_rvoice_set_samplemode(fluid_rvoice_t* voice, enum fluid_loop value)
void
fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value)
{
if (voice->dsp.sample) {
fluid_sample_decr_ref(voice->dsp.sample);
voice->dsp.sample = NULL;
}
voice->dsp.sample = value;
if (value) {
voice->dsp.sample = value;
fluid_sample_incr_ref(voice->dsp.sample);
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
}
}
@ -664,10 +659,6 @@ fluid_rvoice_voiceoff(fluid_rvoice_t* voice)
{
fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVFINISHED);
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVFINISHED);
if (voice->dsp.sample) {
fluid_sample_decr_ref(voice->dsp.sample);
voice->dsp.sample = NULL;
}
}

View file

@ -309,7 +309,7 @@ fluid_mixer_buffers_render_one(fluid_mixer_buffers_t* buffers,
fluid_finish_rvoice(buffers, voice);
}
}
/*
static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
fluid_rvoice_t* voice)
{
@ -325,35 +325,35 @@ static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
fvc = buffers->finished_voice_count;
return retval;
}
*/
int
fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice)
{
// Check if this voice is already in array, this can happen in some overflow conditions
int i, j=0;
for (i=0; i < mixer->active_voices; i++) {
if (mixer->rvoices[i] == voice)
j++;
}
if (j > 0) {
// It's already present, make sure it won't get deleted right away
#ifdef ENABLE_MIXER_THREADS
for (i=0; i < mixer->thread_count; i++)
fluid_mixer_buffers_replace_voice(&mixer->threads[i], voice);
#endif
fluid_mixer_buffers_replace_voice(&mixer->buffers, voice);
int i;
if (mixer->active_voices < mixer->polyphony) {
mixer->rvoices[mixer->active_voices++] = voice;
return FLUID_OK;
}
if (mixer->active_voices >= mixer->polyphony) {
FLUID_LOG(FLUID_WARN, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
return FLUID_FAILED;
/* See if any voices just finished, if so, take its place.
This can happen in voice overflow conditions. */
for (i=0; i < mixer->active_voices; i++) {
if (mixer->rvoices[i] == voice) {
FLUID_LOG(FLUID_ERR, "Internal error: Trying to replace an existing rvoice in fluid_rvoice_mixer_add_voice?!");
return FLUID_FAILED;
}
if (mixer->rvoices[i]->envlfo.volenv.section == FLUID_VOICE_ENVFINISHED) {
fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]);
mixer->rvoices[i] = voice;
return FLUID_OK;
}
}
mixer->rvoices[mixer->active_voices++] = voice;
return FLUID_OK;
/* This should never happen */
FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
return FLUID_FAILED;
}
static int

View file

@ -2734,11 +2734,17 @@ fluid_synth_check_finished_voices(fluid_synth_t* synth)
fluid_rvoice_t* fv;
while (NULL != (fv = fluid_rvoice_eventhandler_get_finished_voice(synth->eventhandler))) {
for (j=0; j < synth->polyphony; j++)
for (j=0; j < synth->polyphony; j++) {
if (synth->voice[j]->rvoice == fv) {
fluid_voice_unlock_rvoice(synth->voice[j]);
fluid_voice_off(synth->voice[j]);
break;
}
else if (synth->voice[j]->overflow_rvoice == fv) {
fluid_voice_overflow_rvoice_finished(synth->voice[j]);
break;
}
}
}
}
@ -2821,7 +2827,7 @@ static fluid_voice_t*
fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth)
{
int i;
fluid_real_t best_prio = 999999.;
fluid_real_t best_prio = OVERFLOW_PRIO_CANNOT_KILL-1;
fluid_real_t this_voice_prio;
fluid_voice_t* voice;
int best_voice_index=-1;

View file

@ -134,6 +134,14 @@ fluid_voice_update_modenv(fluid_voice_t* voice,
coeff, increment, min, max);
}
static inline void fluid_sample_null_ptr(fluid_sample_t** sample)
{
if (*sample != NULL) {
fluid_sample_decr_ref(*sample);
*sample = NULL;
}
}
/*
* new_fluid_voice
*/
@ -147,13 +155,17 @@ new_fluid_voice(fluid_real_t output_rate)
return NULL;
}
voice->rvoice = FLUID_NEW(fluid_rvoice_t);
if (voice->rvoice == NULL) {
voice->overflow_rvoice = FLUID_NEW(fluid_rvoice_t);
if (voice->rvoice == NULL || voice->overflow_rvoice == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
FLUID_FREE(voice->rvoice);
FLUID_FREE(voice);
return NULL;
}
FLUID_MEMSET(voice->rvoice, 0, sizeof(fluid_rvoice_t));
FLUID_MEMSET(voice->overflow_rvoice, 0, sizeof(fluid_rvoice_t));
voice->can_access_rvoice = 1;
voice->can_access_overflow_rvoice = 1;
voice->status = FLUID_VOICE_CLEAN;
voice->chan = NO_CHANNEL;
@ -161,8 +173,7 @@ new_fluid_voice(fluid_real_t output_rate)
voice->vel = 0;
voice->channel = NULL;
voice->sample = NULL;
voice->output_rate = output_rate;
UPDATE_RVOICE_R1(fluid_rvoice_set_output_rate, output_rate);
fluid_voice_set_output_rate(voice, output_rate);
/* The 'sustain' and 'finished' segments of the volume / modulation
* envelope are constant. They are never affected by any modulator
@ -190,15 +201,29 @@ delete_fluid_voice(fluid_voice_t* voice)
if (voice == NULL) {
return FLUID_OK;
}
if (!voice->can_access_rvoice) {
if (!voice->can_access_rvoice || !voice->can_access_overflow_rvoice) {
/* stop rvoice before deleting voice! */
return FLUID_FAILED;
}
FLUID_FREE(voice->overflow_rvoice);
FLUID_FREE(voice->rvoice);
FLUID_FREE(voice);
return FLUID_OK;
}
/*
* Swaps the current rvoice with the current overflow_rvoice
*/
static void fluid_voice_swap_rvoice(fluid_voice_t* voice)
{
fluid_rvoice_t* rtemp = voice->rvoice;
int ctemp = voice->can_access_rvoice;
voice->rvoice = voice->overflow_rvoice;
voice->can_access_rvoice = voice->can_access_overflow_rvoice;
voice->overflow_rvoice = rtemp;
voice->can_access_overflow_rvoice = ctemp;
}
/* fluid_voice_init
*
* Initialize the synthesis process
@ -214,6 +239,16 @@ fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
* of IIR filters, position in sample etc) is initialized. */
int i;
if (!voice->can_access_rvoice) {
if (voice->can_access_overflow_rvoice)
fluid_voice_swap_rvoice(voice);
else {
FLUID_LOG(FLUID_ERR, "Internal error: Cannot access an rvoice in fluid_voice_init!");
return FLUID_FAILED;
}
}
/* We are now guaranteed to have access to the rvoice */
if (voice->sample)
fluid_voice_off(voice);
@ -223,12 +258,18 @@ fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
voice->vel = (unsigned char) vel;
voice->channel = channel;
voice->mod_count = 0;
voice->sample = sample;
voice->start_time = start_time;
voice->debug = 0;
voice->has_noteoff = 0;
UPDATE_RVOICE0(fluid_rvoice_reset);
UPDATE_RVOICE_PTR(fluid_rvoice_set_sample, sample);
/* Increment the reference count of the sample to prevent the
unloading of the soundfont while this voice is playing,
once for us and once for the rvoice. */
fluid_sample_incr_ref(sample);
UPDATE_RVOICE_PTR(fluid_rvoice_set_sample, sample);
fluid_sample_incr_ref(sample);
voice->sample = sample;
i = fluid_channel_get_interp_method(channel);
UPDATE_RVOICE_I1(fluid_rvoice_set_interp_method, i);
@ -257,10 +298,6 @@ fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_mapping, 0, i);
UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_mapping, 1, i+1);
/* Increment the reference count of the sample to prevent the
unloading of the soundfont while this voice is playing. */
fluid_sample_incr_ref(voice->sample);
return FLUID_OK;
}
@ -277,6 +314,11 @@ fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value)
voice->output_rate = value;
UPDATE_RVOICE_R1(fluid_rvoice_set_output_rate, value);
/* Update the other rvoice as well */
fluid_voice_swap_rvoice(voice);
UPDATE_RVOICE_R1(fluid_rvoice_set_output_rate, value);
fluid_voice_swap_rvoice(voice);
return FLUID_FAILED;
}
@ -1191,6 +1233,16 @@ fluid_voice_kill_excl(fluid_voice_t* voice){
return FLUID_OK;
}
/*
* Called by fluid_synth when the overflow rvoice can be reclaimed.
*/
void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice)
{
voice->can_access_overflow_rvoice = 1;
fluid_sample_null_ptr(&voice->overflow_rvoice->dsp.sample);
}
/*
* fluid_voice_off
*
@ -1205,15 +1257,15 @@ fluid_voice_off(fluid_voice_t* voice)
voice->chan = NO_CHANNEL;
UPDATE_RVOICE0(fluid_rvoice_voiceoff);
if (voice->can_access_rvoice)
fluid_sample_null_ptr(&voice->rvoice->dsp.sample);
voice->status = FLUID_VOICE_OFF;
voice->has_noteoff = 1;
/* Decrement the reference count of the sample. */
if (voice->sample) {
fluid_sample_decr_ref(voice->sample);
voice->sample = NULL;
}
fluid_sample_null_ptr(&voice->sample);
/* Decrement voice count */
voice->channel->synth->active_voice_count--;
@ -1489,6 +1541,11 @@ fluid_voice_get_overflow_prio(fluid_voice_t* voice,
{
fluid_real_t this_voice_prio = 0;
/* Are we already overflowing? */
if (!voice->can_access_overflow_rvoice) {
return OVERFLOW_PRIO_CANNOT_KILL;
}
/* Is this voice on the drum channel?
* Then it is very important.
* Also skip the released and sustained scores.

View file

@ -101,7 +101,9 @@ struct _fluid_voice_t
/* rvoice control */
fluid_rvoice_t* rvoice;
fluid_rvoice_t* overflow_rvoice; /* Used temporarily and only in overflow situations */
int can_access_rvoice; /* False if rvoice is being rendered in separate thread */
int can_access_overflow_rvoice; /* False if overflow_rvoice is being rendered in separate thread */
/* for debugging */
int debug;
@ -142,6 +144,7 @@ void fluid_voice_update_param(fluid_voice_t* voice, int gen);
int fluid_voice_noteoff(fluid_voice_t* voice);
int fluid_voice_off(fluid_voice_t* voice);
void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice);
void fluid_voice_mix (fluid_voice_t *voice, int count, fluid_real_t* dsp_buf,
fluid_real_t* left_buf, fluid_real_t* right_buf,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
@ -151,6 +154,8 @@ fluid_real_t fluid_voice_get_overflow_prio(fluid_voice_t* voice,
fluid_overflow_prio_t* score,
unsigned int cur_time);
#define OVERFLOW_PRIO_CANNOT_KILL 999999.
/**
* Locks the rvoice for rendering, so it can't be modified directly
*/