mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-12-03 17:42:21 +00:00
Rewrite overflow so that an extra rvoice is used, and make sure samples are ref/dref under mutex.
This commit is contained in:
parent
cabb6ad315
commit
f7d87aa1a8
5 changed files with 108 additions and 49 deletions
|
@ -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;
|
||||
}
|
||||
if (value) {
|
||||
voice->dsp.sample = value;
|
||||
fluid_sample_incr_ref(voice->dsp.sample);
|
||||
if (value) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
int i;
|
||||
|
||||
if (mixer->active_voices < mixer->polyphony) {
|
||||
mixer->rvoices[mixer->active_voices++] = voice;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* This should never happen */
|
||||
FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -2734,10 +2734,16 @@ 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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* 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
|
||||
*
|
||||
|
@ -1206,14 +1258,14 @@ 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.
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue