SoundFonts cannot be unloaded if polyphony is ever exceeded

If polyphony is exceeded and FluidSynth has to allocate a voice by
calling fluid_synth_free_voice_by_kill_LOCAL(), two problems occur:

 1)The value returned by fluid_synth_get_active_voice_count() never
   returns back to 0.
 2)SoundFont samples are not unref'd properly, and therefore if an attempt is
   made to unload the SoundFont, the deferred unload timer is started, and
   fluid_synth_sfunload_callback() unsuccessfully tries	to unload the SoundFont forever.

These 2 issues are fixed by this commit.
This commit is contained in:
jjceresa 2020-12-30 07:24:40 +01:00 committed by Tom M
parent 5c1cfe6a5f
commit 0d38823527
2 changed files with 39 additions and 8 deletions

View file

@ -1067,6 +1067,12 @@ delete_fluid_synth(fluid_synth_t *synth)
continue; continue;
} }
/* WARNING: A this point we must ensure that the reference counter
of any soundfont sample owned by any rvoice belonging to the voice
are correctly decremented. This is the contrary part to
to fluid_voice_init() where the sample's reference counter is
incremented.
*/
fluid_voice_unlock_rvoice(voice); fluid_voice_unlock_rvoice(voice);
fluid_voice_overflow_rvoice_finished(voice); fluid_voice_overflow_rvoice_finished(voice);
@ -4289,7 +4295,21 @@ fluid_synth_check_finished_voices(fluid_synth_t *synth)
} }
else if(synth->voice[j]->overflow_rvoice == fv) else if(synth->voice[j]->overflow_rvoice == fv)
{ {
/* Unlock the overflow_rvoice of the voice.
Decrement the reference count of the sample owned by this
rvoice.
*/
fluid_voice_overflow_rvoice_finished(synth->voice[j]); fluid_voice_overflow_rvoice_finished(synth->voice[j]);
/* Decrement synth active voice count. Must not be incorporated
in fluid_voice_overflow_rvoice_finished() because
fluid_voice_overflow_rvoice_finished() is called also
at synth destruction and in this case the variable should be
accessed via voice->channel->synth->active_voice_count.
And for certain voices which are not playing, the field
voice->channel is NULL.
*/
synth->active_voice_count--;
break; break;
} }
} }

View file

@ -321,12 +321,13 @@ fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
voice->has_noteoff = 0; voice->has_noteoff = 0;
UPDATE_RVOICE0(fluid_rvoice_reset); UPDATE_RVOICE0(fluid_rvoice_reset);
/* Increment the reference count of the sample to prevent the /*
unloading of the soundfont while this voice is playing, We increment the reference count of the sample to indicate that this
once for us and once for the rvoice. */ sample is about to be owned by the rvoice. This will prevent the
unloading of the soundfont while this rvoice is playing.
*/
fluid_sample_incr_ref(sample); fluid_sample_incr_ref(sample);
fluid_rvoice_eventhandler_push_ptr(voice->eventhandler, fluid_rvoice_set_sample, voice->rvoice, sample); fluid_rvoice_eventhandler_push_ptr(voice->eventhandler, fluid_rvoice_set_sample, voice->rvoice, sample);
fluid_sample_incr_ref(sample);
voice->sample = sample; voice->sample = sample;
i = fluid_channel_get_interp_method(channel); i = fluid_channel_get_interp_method(channel);
@ -1406,11 +1407,19 @@ fluid_voice_kill_excl(fluid_voice_t *voice)
} }
/* /*
* Called by fluid_synth when the overflow rvoice can be reclaimed. * Unlock the overflow rvoice of the voice.
* Decrement the reference count of the sample owned by this rvoice.
*
* Called by fluid_synth when the overflow rvoice has finished by itself.
* Must be called also explicitly at synth destruction to ensure that
* the soundfont be unloaded successfully.
*/ */
void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice) void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice)
{ {
voice->can_access_overflow_rvoice = 1; voice->can_access_overflow_rvoice = 1;
/* Decrement the reference count of the sample to indicate
that this sample isn't owned by the rvoice anymore */
fluid_voice_sample_unref(&voice->overflow_rvoice->dsp.sample); fluid_voice_sample_unref(&voice->overflow_rvoice->dsp.sample);
} }
@ -1439,17 +1448,19 @@ fluid_voice_stop(fluid_voice_t *voice)
voice->chan = NO_CHANNEL; voice->chan = NO_CHANNEL;
/* Decrement the reference count of the sample, to indicate
that this sample isn't owned by the rvoice anymore.
*/
if(voice->can_access_rvoice) if(voice->can_access_rvoice)
{ {
fluid_voice_sample_unref(&voice->rvoice->dsp.sample); fluid_voice_sample_unref(&voice->rvoice->dsp.sample);
} }
voice->sample = NULL;
voice->status = FLUID_VOICE_OFF; voice->status = FLUID_VOICE_OFF;
voice->has_noteoff = 1; voice->has_noteoff = 1;
/* Decrement the reference count of the sample. */
fluid_voice_sample_unref(&voice->sample);
/* Decrement voice count */ /* Decrement voice count */
voice->channel->synth->active_voice_count--; voice->channel->synth->active_voice_count--;
} }