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
|
void
|
||||||
fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value)
|
fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value)
|
||||||
{
|
{
|
||||||
if (voice->dsp.sample) {
|
voice->dsp.sample = value;
|
||||||
fluid_sample_decr_ref(voice->dsp.sample);
|
|
||||||
voice->dsp.sample = NULL;
|
|
||||||
}
|
|
||||||
if (value) {
|
if (value) {
|
||||||
voice->dsp.sample = value;
|
|
||||||
fluid_sample_incr_ref(voice->dsp.sample);
|
|
||||||
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
|
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.volenv, FLUID_VOICE_ENVFINISHED);
|
||||||
fluid_adsr_env_set_section(&voice->envlfo.modenv, 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);
|
fluid_finish_rvoice(buffers, voice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
|
static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
|
||||||
fluid_rvoice_t* voice)
|
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;
|
fvc = buffers->finished_voice_count;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice)
|
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;
|
||||||
int i, j=0;
|
|
||||||
for (i=0; i < mixer->active_voices; i++) {
|
if (mixer->active_voices < mixer->polyphony) {
|
||||||
if (mixer->rvoices[i] == voice)
|
mixer->rvoices[mixer->active_voices++] = 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;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See if any voices just finished, if so, take its place.
|
||||||
if (mixer->active_voices >= mixer->polyphony) {
|
This can happen in voice overflow conditions. */
|
||||||
FLUID_LOG(FLUID_WARN, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
|
for (i=0; i < mixer->active_voices; i++) {
|
||||||
return FLUID_FAILED;
|
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;
|
/* This should never happen */
|
||||||
return FLUID_OK;
|
FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
|
||||||
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -2734,11 +2734,17 @@ fluid_synth_check_finished_voices(fluid_synth_t* synth)
|
||||||
fluid_rvoice_t* fv;
|
fluid_rvoice_t* fv;
|
||||||
|
|
||||||
while (NULL != (fv = fluid_rvoice_eventhandler_get_finished_voice(synth->eventhandler))) {
|
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) {
|
if (synth->voice[j]->rvoice == fv) {
|
||||||
fluid_voice_unlock_rvoice(synth->voice[j]);
|
fluid_voice_unlock_rvoice(synth->voice[j]);
|
||||||
fluid_voice_off(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)
|
fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth)
|
||||||
{
|
{
|
||||||
int i;
|
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_real_t this_voice_prio;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
int best_voice_index=-1;
|
int best_voice_index=-1;
|
||||||
|
|
|
@ -134,6 +134,14 @@ fluid_voice_update_modenv(fluid_voice_t* voice,
|
||||||
coeff, increment, min, max);
|
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
|
* new_fluid_voice
|
||||||
*/
|
*/
|
||||||
|
@ -147,13 +155,17 @@ new_fluid_voice(fluid_real_t output_rate)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
voice->rvoice = FLUID_NEW(fluid_rvoice_t);
|
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_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
FLUID_FREE(voice->rvoice);
|
||||||
FLUID_FREE(voice);
|
FLUID_FREE(voice);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
FLUID_MEMSET(voice->rvoice, 0, sizeof(fluid_rvoice_t));
|
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_rvoice = 1;
|
||||||
|
voice->can_access_overflow_rvoice = 1;
|
||||||
|
|
||||||
voice->status = FLUID_VOICE_CLEAN;
|
voice->status = FLUID_VOICE_CLEAN;
|
||||||
voice->chan = NO_CHANNEL;
|
voice->chan = NO_CHANNEL;
|
||||||
|
@ -161,8 +173,7 @@ new_fluid_voice(fluid_real_t output_rate)
|
||||||
voice->vel = 0;
|
voice->vel = 0;
|
||||||
voice->channel = NULL;
|
voice->channel = NULL;
|
||||||
voice->sample = NULL;
|
voice->sample = NULL;
|
||||||
voice->output_rate = output_rate;
|
fluid_voice_set_output_rate(voice, output_rate);
|
||||||
UPDATE_RVOICE_R1(fluid_rvoice_set_output_rate, output_rate);
|
|
||||||
|
|
||||||
/* The 'sustain' and 'finished' segments of the volume / modulation
|
/* The 'sustain' and 'finished' segments of the volume / modulation
|
||||||
* envelope are constant. They are never affected by any modulator
|
* envelope are constant. They are never affected by any modulator
|
||||||
|
@ -190,15 +201,29 @@ delete_fluid_voice(fluid_voice_t* voice)
|
||||||
if (voice == NULL) {
|
if (voice == NULL) {
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
if (!voice->can_access_rvoice) {
|
if (!voice->can_access_rvoice || !voice->can_access_overflow_rvoice) {
|
||||||
/* stop rvoice before deleting voice! */
|
/* stop rvoice before deleting voice! */
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
FLUID_FREE(voice->overflow_rvoice);
|
||||||
FLUID_FREE(voice->rvoice);
|
FLUID_FREE(voice->rvoice);
|
||||||
FLUID_FREE(voice);
|
FLUID_FREE(voice);
|
||||||
return FLUID_OK;
|
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
|
/* fluid_voice_init
|
||||||
*
|
*
|
||||||
* Initialize the synthesis process
|
* 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. */
|
* of IIR filters, position in sample etc) is initialized. */
|
||||||
int i;
|
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)
|
if (voice->sample)
|
||||||
fluid_voice_off(voice);
|
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->vel = (unsigned char) vel;
|
||||||
voice->channel = channel;
|
voice->channel = channel;
|
||||||
voice->mod_count = 0;
|
voice->mod_count = 0;
|
||||||
voice->sample = sample;
|
|
||||||
voice->start_time = start_time;
|
voice->start_time = start_time;
|
||||||
voice->debug = 0;
|
voice->debug = 0;
|
||||||
voice->has_noteoff = 0;
|
voice->has_noteoff = 0;
|
||||||
UPDATE_RVOICE0(fluid_rvoice_reset);
|
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);
|
i = fluid_channel_get_interp_method(channel);
|
||||||
UPDATE_RVOICE_I1(fluid_rvoice_set_interp_method, i);
|
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, 0, i);
|
||||||
UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_mapping, 1, i+1);
|
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;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,6 +314,11 @@ fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value)
|
||||||
|
|
||||||
voice->output_rate = value;
|
voice->output_rate = value;
|
||||||
UPDATE_RVOICE_R1(fluid_rvoice_set_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;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1191,6 +1233,16 @@ fluid_voice_kill_excl(fluid_voice_t* voice){
|
||||||
return FLUID_OK;
|
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
|
* fluid_voice_off
|
||||||
*
|
*
|
||||||
|
@ -1205,15 +1257,15 @@ fluid_voice_off(fluid_voice_t* voice)
|
||||||
|
|
||||||
voice->chan = NO_CHANNEL;
|
voice->chan = NO_CHANNEL;
|
||||||
UPDATE_RVOICE0(fluid_rvoice_voiceoff);
|
UPDATE_RVOICE0(fluid_rvoice_voiceoff);
|
||||||
|
|
||||||
|
if (voice->can_access_rvoice)
|
||||||
|
fluid_sample_null_ptr(&voice->rvoice->dsp.sample);
|
||||||
|
|
||||||
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. */
|
/* Decrement the reference count of the sample. */
|
||||||
if (voice->sample) {
|
fluid_sample_null_ptr(&voice->sample);
|
||||||
fluid_sample_decr_ref(voice->sample);
|
|
||||||
voice->sample = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decrement voice count */
|
/* Decrement voice count */
|
||||||
voice->channel->synth->active_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;
|
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?
|
/* Is this voice on the drum channel?
|
||||||
* Then it is very important.
|
* Then it is very important.
|
||||||
* Also skip the released and sustained scores.
|
* Also skip the released and sustained scores.
|
||||||
|
|
|
@ -101,7 +101,9 @@ struct _fluid_voice_t
|
||||||
|
|
||||||
/* rvoice control */
|
/* rvoice control */
|
||||||
fluid_rvoice_t* rvoice;
|
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_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 */
|
/* for debugging */
|
||||||
int debug;
|
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_noteoff(fluid_voice_t* voice);
|
||||||
int fluid_voice_off(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,
|
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* left_buf, fluid_real_t* right_buf,
|
||||||
fluid_real_t* reverb_buf, fluid_real_t* chorus_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,
|
fluid_overflow_prio_t* score,
|
||||||
unsigned int cur_time);
|
unsigned int cur_time);
|
||||||
|
|
||||||
|
#define OVERFLOW_PRIO_CANNOT_KILL 999999.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the rvoice for rendering, so it can't be modified directly
|
* Locks the rvoice for rendering, so it can't be modified directly
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue