mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-01-19 07:50:49 +00:00
Refactor/fix mixer implementation, fix a few bugs
This commit is contained in:
parent
a26b5a6117
commit
41853f6f69
11 changed files with 786 additions and 64 deletions
|
@ -140,6 +140,8 @@ set ( libfluidsynth_SOURCES
|
|||
rvoice/fluid_rvoice_event.c
|
||||
rvoice/fluid_rvoice_handler.h
|
||||
rvoice/fluid_rvoice_handler.c
|
||||
rvoice/fluid_rvoice_mixer.h
|
||||
rvoice/fluid_rvoice_mixer.c
|
||||
rvoice/fluid_phase.h
|
||||
rvoice/fluid_rev.c
|
||||
rvoice/fluid_rev.h
|
||||
|
|
|
@ -729,6 +729,10 @@ int main(int argc, char** argv)
|
|||
|
||||
if (fast_render) {
|
||||
char *filename;
|
||||
if (player == NULL) {
|
||||
fprintf(stderr, "No midi file specified!\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fluid_settings_dupstr (settings, "audio.file.name", &filename);
|
||||
printf ("Rendering audio to file '%s'..\n", filename);
|
||||
|
|
|
@ -25,13 +25,13 @@ fluid_adsr_env_set_data(fluid_adsr_env_t* env,
|
|||
fluid_adsr_env_section_t section,
|
||||
unsigned int count,
|
||||
fluid_real_t coeff,
|
||||
fluid_real_t incr,
|
||||
fluid_real_t increment,
|
||||
fluid_real_t min,
|
||||
fluid_real_t max)
|
||||
{
|
||||
env->data[section].count = count;
|
||||
env->data[section].coeff = coeff;
|
||||
env->data[section].incr = incr;
|
||||
env->data[section].increment = increment;
|
||||
env->data[section].min = min;
|
||||
env->data[section].max = max;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
struct _fluid_env_data_t {
|
||||
unsigned int count;
|
||||
fluid_real_t coeff;
|
||||
fluid_real_t incr;
|
||||
fluid_real_t increment;
|
||||
fluid_real_t min;
|
||||
fluid_real_t max;
|
||||
};
|
||||
|
@ -81,7 +81,7 @@ fluid_adsr_env_calc(fluid_adsr_env_t* env, int is_volenv)
|
|||
}
|
||||
|
||||
/* calculate the envelope value and check for valid range */
|
||||
x = env_data->coeff * env->val + env_data->incr;
|
||||
x = env_data->coeff * env->val + env_data->increment;
|
||||
|
||||
if (x < env_data->min)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ fluid_adsr_env_set_data(fluid_adsr_env_t* env,
|
|||
fluid_adsr_env_section_t section,
|
||||
unsigned int count,
|
||||
fluid_real_t coeff,
|
||||
fluid_real_t incr,
|
||||
fluid_real_t increment,
|
||||
fluid_real_t min,
|
||||
fluid_real_t max);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef struct _fluid_lfo_t fluid_lfo_t;
|
|||
struct _fluid_lfo_t {
|
||||
fluid_real_t val; /* the current value of the LFO */
|
||||
unsigned int delay; /* the delay of the lfo in samples */
|
||||
fluid_real_t incr; /* the lfo frequency is converted to a per-buffer increment */
|
||||
fluid_real_t increment; /* the lfo frequency is converted to a per-buffer increment */
|
||||
};
|
||||
|
||||
static inline void
|
||||
|
@ -38,9 +38,9 @@ fluid_lfo_reset(fluid_lfo_t* lfo)
|
|||
}
|
||||
|
||||
static inline void
|
||||
fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t incr)
|
||||
fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t increment)
|
||||
{
|
||||
lfo->incr = incr;
|
||||
lfo->increment = increment;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -61,16 +61,16 @@ fluid_lfo_calc(fluid_lfo_t* lfo, unsigned int cur_delay)
|
|||
if (cur_delay < lfo->delay)
|
||||
return;
|
||||
|
||||
lfo->val += lfo->incr;
|
||||
lfo->val += lfo->increment;
|
||||
|
||||
if (lfo->val > (fluid_real_t) 1.0)
|
||||
{
|
||||
lfo->incr = -lfo->incr;
|
||||
lfo->increment = -lfo->increment;
|
||||
lfo->val = (fluid_real_t) 2.0 - lfo->val;
|
||||
}
|
||||
else if (lfo->val < (fluid_real_t) -1.0)
|
||||
{
|
||||
lfo->incr = -lfo->incr;
|
||||
lfo->increment = -lfo->increment;
|
||||
lfo->val = (fluid_real_t) -2.0 - lfo->val;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "fluid_rvoice_event.h"
|
||||
#include "fluid_rvoice.h"
|
||||
#include "fluid_rvoice_handler.h"
|
||||
#include "fluid_rvoice_mixer.h"
|
||||
#include "fluid_iir_filter.h"
|
||||
#include "fluid_lfo.h"
|
||||
#include "fluid_adsr_env.h"
|
||||
|
@ -57,10 +57,16 @@
|
|||
event->realparams[4]); \
|
||||
return; }
|
||||
|
||||
#define EVENTFUNC_R4(proc, type) \
|
||||
if (event->method == proc) { \
|
||||
proc((type) event->object, event->intparam, event->realparams[0], \
|
||||
event->realparams[1], event->realparams[2], event->realparams[3]); \
|
||||
return; }
|
||||
|
||||
void
|
||||
fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event)
|
||||
{
|
||||
EVENTFUNC_PTR(fluid_rvoice_handler_add_voice, fluid_rvoice_handler_t*, fluid_rvoice_t*);
|
||||
EVENTFUNC_PTR(fluid_rvoice_mixer_add_voice, fluid_rvoice_mixer_t*, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_noteoff, fluid_rvoice_t*);
|
||||
EVENTFUNC_0(fluid_rvoice_voiceoff, fluid_rvoice_t*);
|
||||
|
||||
|
@ -96,7 +102,15 @@ fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event)
|
|||
EVENTFUNC_I1(fluid_rvoice_set_samplemode, fluid_rvoice_t*);
|
||||
EVENTFUNC_PTR(fluid_rvoice_set_sample, fluid_rvoice_t*, fluid_sample_t*);
|
||||
|
||||
EVENTFUNC_R1(fluid_rvoice_handler_set_polyphony, fluid_rvoice_handler_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_mixer_set_samplerate, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_polyphony, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_reverb_enabled, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_chorus_enabled, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_mix_fx, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_0(fluid_rvoice_mixer_reset_fx, fluid_rvoice_mixer_t*);
|
||||
|
||||
EVENTFUNC_ALL(fluid_rvoice_mixer_set_chorus_params, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_R4(fluid_rvoice_mixer_set_reverb_params, fluid_rvoice_mixer_t*);
|
||||
|
||||
FLUID_LOG(FLUID_ERR, "fluid_rvoice_event_dispatch: Unknown method %p to dispatch!", event->method);
|
||||
}
|
||||
|
@ -196,14 +210,14 @@ finished_voice_callback(void* userdata, fluid_rvoice_t* rvoice)
|
|||
}
|
||||
|
||||
fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
|
||||
int is_threadsafe, int queuesize, int finished_voices_size)
|
||||
int is_threadsafe, int queuesize, int finished_voices_size, int bufs, int fx_bufs)
|
||||
{
|
||||
fluid_rvoice_eventhandler_t* eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
|
||||
if (eventhandler == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
eventhandler->handler = NULL;
|
||||
eventhandler->mixer = NULL;
|
||||
eventhandler->queue = NULL;
|
||||
eventhandler->finished_voices = NULL;
|
||||
eventhandler->is_threadsafe = is_threadsafe;
|
||||
|
@ -218,10 +232,10 @@ fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
|
|||
if (eventhandler->queue == NULL)
|
||||
goto error_recovery;
|
||||
|
||||
eventhandler->handler = new_fluid_rvoice_handler();
|
||||
if (eventhandler->handler == NULL)
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs);
|
||||
if (eventhandler->mixer == NULL)
|
||||
goto error_recovery;
|
||||
fluid_rvoice_handler_set_voice_callback(eventhandler->handler,
|
||||
fluid_rvoice_mixer_set_finished_voices_callback(eventhandler->mixer,
|
||||
finished_voice_callback, eventhandler);
|
||||
return eventhandler;
|
||||
|
||||
|
@ -249,6 +263,7 @@ void
|
|||
delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t* handler)
|
||||
{
|
||||
if (handler == NULL) return;
|
||||
delete_fluid_rvoice_mixer(handler->mixer);
|
||||
delete_fluid_ringbuffer(handler->queue);
|
||||
delete_fluid_ringbuffer(handler->finished_voices);
|
||||
FLUID_FREE(handler);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#define _FLUID_RVOICE_EVENT_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_rvoice_handler.h"
|
||||
#include "fluid_rvoice_mixer.h"
|
||||
#include "fluid_ringbuffer.h"
|
||||
|
||||
#define EVENT_REAL_PARAMS (5)
|
||||
|
@ -52,11 +52,11 @@ struct _fluid_rvoice_eventhandler_t {
|
|||
fluid_ringbuffer_t* queue; /**< List of fluid_rvoice_event_t */
|
||||
int queue_stored; /**< Extras pushed but not flushed */
|
||||
fluid_ringbuffer_t* finished_voices; /**< return queue from handler, list of fluid_rvoice_t* */
|
||||
fluid_rvoice_handler_t* handler;
|
||||
fluid_rvoice_mixer_t* mixer;
|
||||
};
|
||||
|
||||
fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
|
||||
int is_threadsafe, int queuesize, int finished_voices_size);
|
||||
int is_threadsafe, int queuesize, int finished_voices_size, int bufs, int fx_bufs);
|
||||
|
||||
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t*);
|
||||
|
||||
|
@ -102,10 +102,10 @@ fluid_rvoice_eventhandler_add_rvoice(fluid_rvoice_eventhandler_t* handler,
|
|||
fluid_rvoice_t* rvoice)
|
||||
{
|
||||
if (handler->is_threadsafe)
|
||||
fluid_rvoice_eventhandler_push_ptr(handler, fluid_rvoice_handler_add_voice,
|
||||
handler->handler, rvoice);
|
||||
fluid_rvoice_eventhandler_push_ptr(handler, fluid_rvoice_mixer_add_voice,
|
||||
handler->mixer, rvoice);
|
||||
else
|
||||
fluid_rvoice_handler_add_voice(handler->handler, rvoice);
|
||||
fluid_rvoice_mixer_add_voice(handler->mixer, rvoice);
|
||||
}
|
||||
|
||||
|
||||
|
|
587
fluidsynth/src/rvoice/fluid_rvoice_mixer.c
Normal file
587
fluidsynth/src/rvoice/fluid_rvoice_mixer.c
Normal file
|
@ -0,0 +1,587 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluid_rvoice_mixer.h"
|
||||
#include "fluid_rvoice.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_rev.h"
|
||||
#include "fluid_chorus.h"
|
||||
|
||||
#define SYNTH_REVERB_CHANNEL 0
|
||||
#define SYNTH_CHORUS_CHANNEL 1
|
||||
|
||||
typedef struct _fluid_mixer_buffers_t fluid_mixer_buffers_t;
|
||||
|
||||
struct _fluid_mixer_buffers_t {
|
||||
fluid_rvoice_mixer_t* mixer; /**< Owner of object */
|
||||
#ifdef ENABLE_MIXER_THREADS
|
||||
fluid_thread_t* thread; /**< Thread object */
|
||||
#endif
|
||||
|
||||
fluid_rvoice_t** finished_voices; /* List of voices who have finished */
|
||||
int finished_voice_count;
|
||||
|
||||
int ready; /**< Atomic: buffers are ready for mixing */
|
||||
|
||||
int buf_blocks; /**< Number of blocks allocated in the buffers */
|
||||
|
||||
int buf_count;
|
||||
fluid_real_t** left_buf;
|
||||
fluid_real_t** right_buf;
|
||||
|
||||
int fx_buf_count;
|
||||
fluid_real_t** fx_left_buf;
|
||||
fluid_real_t** fx_right_buf;
|
||||
};
|
||||
|
||||
typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t;
|
||||
|
||||
struct _fluid_mixer_fx_t {
|
||||
fluid_revmodel_t* reverb; /**< Reverb unit */
|
||||
fluid_chorus_t* chorus; /**< Chorus unit */
|
||||
int with_reverb; /**< Should the synth use the built-in reverb unit? */
|
||||
int with_chorus; /**< Should the synth use the built-in chorus unit? */
|
||||
int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
|
||||
};
|
||||
|
||||
struct _fluid_rvoice_mixer_t {
|
||||
fluid_mixer_fx_t fx;
|
||||
|
||||
fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
|
||||
void (*remove_voice_callback)(void*, fluid_rvoice_t*); /**< Used by mixer only: Receive this callback every time a voice is removed */
|
||||
void* remove_voice_callback_userdata;
|
||||
|
||||
fluid_rvoice_t** rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
|
||||
int polyphony; /**< Read-only: Length of voices array */
|
||||
int active_voices; /**< Read-only: Number of non-null voices */
|
||||
int current_blockcount; /**< Read-only: how many blocks to process this time */
|
||||
|
||||
#ifdef ENABLE_MIXER_THREADS
|
||||
// int sleeping_threads; /**< Atomic: number of threads currently asleep */
|
||||
// int active_threads; /**< Atomic: number of threads in the thread loop */
|
||||
int threads_should_terminate; /**< Atomic: Set to TRUE when threads should terminate */
|
||||
int current_rvoice; /**< Atomic: for the threads to know next voice to */
|
||||
fluid_cond_t* wakeup_threads; /**< Signalled when the threads should wake up */
|
||||
fluid_cond_mutex_t* wakeup_threads_m; /**< wakeup_threads mutex companion */
|
||||
fluid_cond_t* thread_ready; /**< Signalled from thread, when the thread has a buffer ready for mixing */
|
||||
fluid_cond_mutex_t* thread_ready_m; /**< thread_ready mutex companion */
|
||||
|
||||
int thread_count; /**< Number of extra mixer threads for multi-core rendering */
|
||||
fluid_mixer_buffers_t* threads; /**< Array of mixer threads (thread_count in length) */
|
||||
#endif
|
||||
};
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
int i;
|
||||
if (mixer->fx.with_reverb) {
|
||||
if (mixer->fx.mix_fx_to_out) {
|
||||
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
fluid_revmodel_processmix(mixer->fx.reverb,
|
||||
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
|
||||
&mixer->buffers.left_buf[0][i],
|
||||
&mixer->buffers.right_buf[0][i]);
|
||||
}
|
||||
else {
|
||||
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
fluid_revmodel_processreplace(mixer->fx.reverb,
|
||||
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
|
||||
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
|
||||
&mixer->buffers.fx_right_buf[SYNTH_REVERB_CHANNEL][i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (mixer->fx.with_chorus) {
|
||||
if (mixer->fx.mix_fx_to_out) {
|
||||
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
fluid_chorus_processmix(mixer->fx.chorus,
|
||||
&mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
|
||||
&mixer->buffers.left_buf[0][i],
|
||||
&mixer->buffers.right_buf[0][i]);
|
||||
}
|
||||
else {
|
||||
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
fluid_chorus_processreplace(mixer->fx.chorus,
|
||||
&mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
|
||||
&mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
|
||||
&mixer->buffers.fx_right_buf[SYNTH_CHORUS_CHANNEL][i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* During rendering, rvoices might be finished. Set this callback
|
||||
* for getting a callback any time the rvoice is finished.
|
||||
*/
|
||||
void fluid_rvoice_mixer_set_finished_voices_callback(
|
||||
fluid_rvoice_mixer_t* mixer,
|
||||
void (*func)(void*, fluid_rvoice_t*),
|
||||
void* userdata)
|
||||
{
|
||||
mixer->remove_voice_callback_userdata = userdata;
|
||||
mixer->remove_voice_callback = func;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Synthesize one voice and add to buffer.
|
||||
* NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
|
||||
* voice has been finished, removed and possibly replaced with another voice.
|
||||
* @return Number of samples written
|
||||
*/
|
||||
static int
|
||||
fluid_mix_one(fluid_rvoice_t* rvoice, fluid_real_t** bufs, unsigned int bufcount, int blockcount)
|
||||
{
|
||||
int i, result = 0;
|
||||
|
||||
fluid_real_t local_buf[FLUID_BUFSIZE*blockcount];
|
||||
|
||||
for (i=0; i < blockcount; i++) {
|
||||
int s = fluid_rvoice_write(rvoice, &local_buf[FLUID_BUFSIZE*i]);
|
||||
if (s == -1) {
|
||||
s = FLUID_BUFSIZE; /* Voice is quiet, TODO: optimize away memset/mix */
|
||||
FLUID_MEMSET(&local_buf[FLUID_BUFSIZE*i], 0, FLUID_BUFSIZE*sizeof(fluid_real_t*));
|
||||
}
|
||||
result += s;
|
||||
if (s < FLUID_BUFSIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fluid_rvoice_buffers_mix(&rvoice->buffers, local_buf, result, bufs, bufcount);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Glue to get fluid_rvoice_buffers_mix what it wants
|
||||
* Note: Make sure outbufs has buf_count + fx_buf_count elements before calling
|
||||
*/
|
||||
static FLUID_INLINE int
|
||||
fluid_mixer_buffers_prepare(fluid_mixer_buffers_t* buffers, fluid_real_t** outbufs)
|
||||
{
|
||||
fluid_real_t* reverb_buf, *chorus_buf;
|
||||
int i;
|
||||
|
||||
/* Set up the reverb / chorus buffers only, when the effect is
|
||||
* enabled on synth level. Nonexisting buffers are detected in the
|
||||
* DSP loop. Not sending the reverb / chorus signal saves some time
|
||||
* in that case. */
|
||||
reverb_buf = buffers->mixer->fx.with_reverb ? buffers->fx_left_buf[SYNTH_REVERB_CHANNEL] : NULL;
|
||||
chorus_buf = buffers->mixer->fx.with_chorus ? buffers->fx_left_buf[SYNTH_CHORUS_CHANNEL] : NULL;
|
||||
outbufs[buffers->buf_count*2 + SYNTH_REVERB_CHANNEL] = reverb_buf;
|
||||
outbufs[buffers->buf_count*2 + SYNTH_CHORUS_CHANNEL] = chorus_buf;
|
||||
|
||||
/* The output associated with a MIDI channel is wrapped around
|
||||
* using the number of audio groups as modulo divider. This is
|
||||
* typically the number of output channels on the 'sound card',
|
||||
* as long as the LADSPA Fx unit is not used. In case of LADSPA
|
||||
* unit, think of it as subgroups on a mixer.
|
||||
*
|
||||
* For example: Assume that the number of groups is set to 2.
|
||||
* Then MIDI channel 1, 3, 5, 7 etc. go to output 1, channels 2,
|
||||
* 4, 6, 8 etc to output 2. Or assume 3 groups: Then MIDI
|
||||
* channels 1, 4, 7, 10 etc go to output 1; 2, 5, 8, 11 etc to
|
||||
* output 2, 3, 6, 9, 12 etc to output 3.
|
||||
*/
|
||||
|
||||
for (i = 0; i < buffers->buf_count; i++) {
|
||||
outbufs[i*2] = buffers->left_buf[i];
|
||||
outbufs[i*2+1] = buffers->right_buf[i];
|
||||
}
|
||||
return buffers->buf_count*2 + 2;
|
||||
}
|
||||
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_finish_rvoice(fluid_mixer_buffers_t* buffers, fluid_rvoice_t* rvoice)
|
||||
{
|
||||
if (buffers->finished_voice_count < buffers->mixer->polyphony)
|
||||
buffers->finished_voices[buffers->finished_voice_count++] = rvoice;
|
||||
else
|
||||
FLUID_LOG(FLUID_ERR, "Exceeded finished voices array, try increasing polyphony");
|
||||
}
|
||||
|
||||
static void
|
||||
fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t* buffers)
|
||||
{
|
||||
int i,j;
|
||||
for (i=0; i < buffers->finished_voice_count; i++) {
|
||||
fluid_rvoice_t* v = buffers->finished_voices[i];
|
||||
int* av = &buffers->mixer->active_voices;
|
||||
for (j=0; j < *av; j++) {
|
||||
if (v == buffers->mixer->rvoices[j]) {
|
||||
(*av)--;
|
||||
/* Pack the array */
|
||||
if (j < *av)
|
||||
buffers->mixer->rvoices[j] = buffers->mixer->rvoices[*av];
|
||||
}
|
||||
}
|
||||
if (buffers->mixer->remove_voice_callback)
|
||||
buffers->mixer->remove_voice_callback(
|
||||
buffers->mixer->remove_voice_callback_userdata, v);
|
||||
}
|
||||
buffers->finished_voice_count = 0;
|
||||
}
|
||||
|
||||
static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
#ifdef ENABLE_MIXER_THREADS
|
||||
int i;
|
||||
for (i=0; i < thread_count; i++)
|
||||
fluid_mixer_buffer_process_finished_voices(&mixer->threads[i]);
|
||||
#endif
|
||||
fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
|
||||
}
|
||||
|
||||
int
|
||||
fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice)
|
||||
{
|
||||
if (mixer->active_voices >= mixer->polyphony) {
|
||||
FLUID_LOG(FLUID_WARN, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
mixer->rvoices[mixer->active_voices++] = voice;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update polyphony - max number of voices (NOTE: not hard real-time capable)
|
||||
* @return FLUID_OK or FLUID_FAILED
|
||||
*/
|
||||
int
|
||||
fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value)
|
||||
{
|
||||
void* newptr;
|
||||
if (handler->active_voices > value)
|
||||
return FLUID_FAILED;
|
||||
if (handler->buffers.finished_voice_count > value)
|
||||
return FLUID_FAILED;
|
||||
|
||||
newptr = FLUID_REALLOC(handler->rvoices, value * sizeof(fluid_rvoice_t*));
|
||||
if (newptr == NULL)
|
||||
return FLUID_FAILED;
|
||||
handler->rvoices = newptr;
|
||||
|
||||
newptr = FLUID_REALLOC(handler->buffers.finished_voices, value * sizeof(fluid_rvoice_t*));
|
||||
if (newptr == NULL)
|
||||
return FLUID_FAILED;
|
||||
handler->buffers.finished_voices = newptr;
|
||||
|
||||
handler->polyphony = value;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
static FLUID_INLINE void fluid_render_loop_singlethread(fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
int i;
|
||||
int scount = mixer->current_blockcount * FLUID_BUFSIZE;
|
||||
fluid_real_t* bufs[mixer->buffers.buf_count + mixer->buffers.fx_buf_count];
|
||||
int bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
|
||||
for (i=0; i < mixer->active_voices; i++) {
|
||||
int s = fluid_mix_one(mixer->rvoices[i], bufs, bufcount, mixer->current_blockcount);
|
||||
if (s < scount) {
|
||||
fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_mixer_buffers_zero(fluid_mixer_buffers_t* buffers)
|
||||
{
|
||||
int i;
|
||||
int size = buffers->mixer->current_blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t);
|
||||
/* TODO: Optimize by only zero out the buffers we actually use later on. */
|
||||
for (i=0; i < buffers->buf_count; i++) {
|
||||
FLUID_MEMSET(buffers->left_buf[i], 0, size);
|
||||
FLUID_MEMSET(buffers->right_buf[i], 0, size);
|
||||
}
|
||||
for (i=0; i < buffers->fx_buf_count; i++) {
|
||||
FLUID_MEMSET(buffers->fx_left_buf[i], 0, size);
|
||||
FLUID_MEMSET(buffers->fx_right_buf[i], 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Synthesize audio into buffers
|
||||
* @param blockcount number of blocks to render, each having FLUID_BUFSIZE samples
|
||||
* @return number of blocks rendered
|
||||
*/
|
||||
int
|
||||
fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
|
||||
{
|
||||
mixer->current_blockcount = blockcount > mixer->buffers.buf_blocks ?
|
||||
mixer->buffers.buf_blocks : blockcount;
|
||||
|
||||
// Zero buffers
|
||||
fluid_mixer_buffers_zero(&mixer->buffers);
|
||||
|
||||
// If no additional threads, just render all voices in a simple loop
|
||||
#ifdef ENABLE_MIXER_THREADS
|
||||
if (thread_count > 0)
|
||||
fluid_render_loop_multithread(mixer);
|
||||
else
|
||||
#endif
|
||||
fluid_render_loop_singlethread(mixer);
|
||||
|
||||
// If additional threads: Prepare voice list
|
||||
// Signal threads to wake up
|
||||
// while threads are running:
|
||||
// If thread is finished, mix it in
|
||||
// Otherwise get a voice and render it
|
||||
// If no voices, wait for mixes
|
||||
|
||||
// Process reverb & chorus
|
||||
fluid_rvoice_mixer_process_fx(mixer);
|
||||
|
||||
// Call the callback and pack active voice array
|
||||
fluid_rvoice_mixer_process_finished_voices(mixer);
|
||||
|
||||
return mixer->current_blockcount;
|
||||
}
|
||||
|
||||
static int
|
||||
fluid_mixer_buffers_init(fluid_mixer_buffers_t* buffers, fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
int i, samplecount;
|
||||
|
||||
buffers->mixer = mixer;
|
||||
buffers->buf_count = buffers->mixer->buffers.buf_count;
|
||||
buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
|
||||
buffers->buf_blocks = buffers->mixer->buffers.buf_blocks;
|
||||
samplecount = FLUID_BUFSIZE * buffers->buf_count;
|
||||
|
||||
|
||||
/* Left and right audio buffers */
|
||||
|
||||
buffers->left_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
|
||||
buffers->right_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
|
||||
|
||||
if ((buffers->left_buf == NULL) || (buffers->right_buf == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(buffers->left_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(buffers->right_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
|
||||
|
||||
for (i = 0; i < buffers->buf_count; i++) {
|
||||
|
||||
buffers->left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
|
||||
buffers->right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
|
||||
|
||||
if ((buffers->left_buf[i] == NULL) || (buffers->right_buf[i] == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Effects audio buffers */
|
||||
|
||||
buffers->fx_left_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
|
||||
buffers->fx_right_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
|
||||
|
||||
if ((buffers->fx_left_buf == NULL) || (buffers->fx_right_buf == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(buffers->fx_left_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(buffers->fx_right_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
|
||||
|
||||
for (i = 0; i < buffers->fx_buf_count; i++) {
|
||||
buffers->fx_left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
|
||||
buffers->fx_right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
|
||||
|
||||
if ((buffers->fx_left_buf[i] == NULL) || (buffers->fx_right_buf[i] == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Not hard real-time capable (calls malloc)
|
||||
*/
|
||||
void
|
||||
fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate)
|
||||
{
|
||||
int i;
|
||||
if (mixer->fx.chorus)
|
||||
delete_fluid_chorus(mixer->fx.chorus);
|
||||
mixer->fx.chorus = new_fluid_chorus(samplerate);
|
||||
for (i=0; i < mixer->active_voices; i++)
|
||||
fluid_rvoice_set_output_rate(mixer->rvoices[i], samplerate);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param buf_count number of primary stereo buffers
|
||||
* @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_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
|
||||
if (mixer == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
|
||||
mixer->buffers.buf_count = buf_count;
|
||||
mixer->buffers.fx_buf_count = fx_buf_count;
|
||||
mixer->buffers.buf_blocks = FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||
|
||||
/* allocate the reverb module */
|
||||
mixer->fx.reverb = new_fluid_revmodel();
|
||||
mixer->fx.chorus = new_fluid_chorus(44100); /* FIXME: Hardcoded sample rate */
|
||||
if (mixer->fx.reverb == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
delete_fluid_rvoice_mixer(mixer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (!fluid_mixer_buffers_init(&mixer->buffers, mixer)) {
|
||||
delete_fluid_rvoice_mixer(mixer);
|
||||
return NULL;
|
||||
}
|
||||
return mixer;
|
||||
}
|
||||
|
||||
static void
|
||||
fluid_mixer_buffers_free(fluid_mixer_buffers_t* buffers)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* free all the sample buffers */
|
||||
if (buffers->left_buf != NULL) {
|
||||
for (i = 0; i < buffers->buf_count; i++) {
|
||||
if (buffers->left_buf[i] != NULL) {
|
||||
FLUID_FREE(buffers->left_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(buffers->left_buf);
|
||||
}
|
||||
|
||||
if (buffers->right_buf != NULL) {
|
||||
for (i = 0; i < buffers->buf_count; i++) {
|
||||
if (buffers->right_buf[i] != NULL) {
|
||||
FLUID_FREE(buffers->right_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(buffers->right_buf);
|
||||
}
|
||||
|
||||
if (buffers->fx_left_buf != NULL) {
|
||||
for (i = 0; i < buffers->fx_buf_count; i++) {
|
||||
if (buffers->fx_left_buf[i] != NULL) {
|
||||
FLUID_FREE(buffers->fx_left_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(buffers->fx_left_buf);
|
||||
}
|
||||
|
||||
if (buffers->fx_right_buf != NULL) {
|
||||
for (i = 0; i < buffers->fx_buf_count; i++) {
|
||||
if (buffers->fx_right_buf[i] != NULL) {
|
||||
FLUID_FREE(buffers->fx_right_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(buffers->fx_right_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
if (!mixer)
|
||||
return;
|
||||
fluid_mixer_buffers_free(&mixer->buffers);
|
||||
if (mixer->fx.reverb)
|
||||
delete_fluid_revmodel(mixer->fx.reverb);
|
||||
if (mixer->fx.chorus)
|
||||
delete_fluid_chorus(mixer->fx.chorus);
|
||||
FLUID_FREE(mixer);
|
||||
}
|
||||
|
||||
|
||||
void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on)
|
||||
{
|
||||
mixer->fx.with_reverb = on;
|
||||
}
|
||||
|
||||
void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on)
|
||||
{
|
||||
mixer->fx.with_chorus = on;
|
||||
}
|
||||
|
||||
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on)
|
||||
{
|
||||
mixer->fx.mix_fx_to_out = on;
|
||||
}
|
||||
|
||||
void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
|
||||
int nr, double level, double speed,
|
||||
double depth_ms, int type)
|
||||
{
|
||||
fluid_chorus_set(mixer->fx.chorus, set, nr, level, speed, depth_ms, type);
|
||||
}
|
||||
void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
|
||||
double roomsize, double damping,
|
||||
double width, double level)
|
||||
{
|
||||
fluid_revmodel_set(mixer->fx.reverb, set, roomsize, damping, width, level);
|
||||
}
|
||||
|
||||
void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
fluid_revmodel_reset(mixer->fx.reverb);
|
||||
fluid_chorus_reset(mixer->fx.chorus);
|
||||
}
|
||||
|
||||
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_real_t*** left, fluid_real_t*** right)
|
||||
{
|
||||
*left = mixer->buffers.left_buf;
|
||||
*right = mixer->buffers.right_buf;
|
||||
return mixer->buffers.buf_count;
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_MIXER_THREADS
|
||||
/* Core thread function (processes voices in parallel to primary synthesis thread) */
|
||||
static void
|
||||
fluid_mixer_thread_func (void* data)
|
||||
{
|
||||
fluid_mixer_buffers_t* buffers = data;
|
||||
|
||||
// get a voice
|
||||
// if no voices: signal rendered buffers, sleep
|
||||
// else: if buffer is not zeroed, zero buffers
|
||||
// then render voice to buffers
|
||||
|
||||
}
|
||||
#endif
|
69
fluidsynth/src/rvoice/fluid_rvoice_mixer.h
Normal file
69
fluidsynth/src/rvoice/fluid_rvoice_mixer.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_RVOICE_MIXER_H
|
||||
#define _FLUID_RVOICE_MIXER_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_rvoice.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
|
||||
|
||||
#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE)
|
||||
|
||||
void fluid_rvoice_mixer_set_finished_voices_callback(
|
||||
fluid_rvoice_mixer_t* mixer,
|
||||
void (*func)(void*, fluid_rvoice_t*),
|
||||
void* userdata);
|
||||
|
||||
|
||||
int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount);
|
||||
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_real_t*** left, fluid_real_t*** right);
|
||||
|
||||
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count);
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
|
||||
|
||||
void fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate);
|
||||
void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on);
|
||||
void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on);
|
||||
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on);
|
||||
int fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value);
|
||||
int fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice);
|
||||
void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
|
||||
int nr, double level, double speed,
|
||||
double depth_ms, int type);
|
||||
void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
|
||||
double roomsize, double damping,
|
||||
double width, double level);
|
||||
void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer);
|
||||
|
||||
/**
|
||||
* Update amount of 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
|
||||
*/
|
||||
void fluid_rvoice_mixer_set_threads(int thread_count, int prio_level);
|
||||
|
||||
#endif
|
||||
|
|
@ -492,7 +492,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
fluid_synth_t* synth;
|
||||
fluid_sfloader_t* loader;
|
||||
double gain;
|
||||
int i;
|
||||
int i, nbuf;
|
||||
|
||||
/* initialize all the conversion tables and other stuff */
|
||||
if (fluid_synth_initialized == 0) {
|
||||
|
@ -593,9 +593,9 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
/* The number of buffers is determined by the higher number of nr
|
||||
* groups / nr audio channels. If LADSPA is unused, they should be
|
||||
* the same. */
|
||||
synth->nbuf = synth->audio_channels;
|
||||
if (synth->audio_groups > synth->nbuf) {
|
||||
synth->nbuf = synth->audio_groups;
|
||||
nbuf = synth->audio_channels;
|
||||
if (synth->audio_groups > nbuf) {
|
||||
nbuf = synth->audio_groups;
|
||||
}
|
||||
|
||||
#ifdef LADSPA
|
||||
|
@ -648,11 +648,18 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
}
|
||||
|
||||
/* Allocate handler */
|
||||
synth->eventhandler = new_fluid_rvoice_eventhandler(1, synth->polyphony*8, synth->polyphony);
|
||||
synth->eventhandler = new_fluid_rvoice_eventhandler(0, synth->polyphony*8,
|
||||
synth->polyphony,
|
||||
nbuf, synth->effects_channels);
|
||||
if (synth->eventhandler == NULL)
|
||||
goto error_recovery;
|
||||
fluid_rvoice_handler_set_polyphony(synth->eventhandler->handler, synth->polyphony);
|
||||
fluid_rvoice_eventhandler_push(synth->eventhandler,
|
||||
fluid_rvoice_mixer_set_polyphony,
|
||||
synth->eventhandler->mixer, synth->polyphony, 0.0f);
|
||||
fluid_synth_set_reverb_on(synth, synth->with_reverb);
|
||||
fluid_synth_set_chorus_on(synth, synth->with_chorus);
|
||||
|
||||
#if 0
|
||||
/* Allocate the sample buffers */
|
||||
synth->left_buf = NULL;
|
||||
synth->right_buf = NULL;
|
||||
|
@ -705,34 +712,39 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
goto error_recovery;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
synth->cur = FLUID_BUFSIZE;
|
||||
synth->dither_index = 0;
|
||||
|
||||
#if 0
|
||||
/* allocate the reverb module */
|
||||
synth->reverb = new_fluid_revmodel();
|
||||
if (synth->reverb == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
#endif
|
||||
synth->reverb_roomsize = FLUID_REVERB_DEFAULT_ROOMSIZE;
|
||||
synth->reverb_damping = FLUID_REVERB_DEFAULT_DAMP;
|
||||
synth->reverb_width = FLUID_REVERB_DEFAULT_WIDTH;
|
||||
synth->reverb_level = FLUID_REVERB_DEFAULT_LEVEL;
|
||||
|
||||
fluid_revmodel_set (synth->reverb, FLUID_REVMODEL_SET_ALL,
|
||||
synth->reverb_roomsize, synth->reverb_damping,
|
||||
synth->reverb_width, synth->reverb_level);
|
||||
fluid_rvoice_eventhandler_push5(synth->eventhandler,
|
||||
fluid_rvoice_mixer_set_reverb_params,
|
||||
synth->eventhandler->mixer,
|
||||
FLUID_REVMODEL_SET_ALL, synth->reverb_roomsize,
|
||||
synth->reverb_damping, synth->reverb_width,
|
||||
synth->reverb_level, 0.0f);
|
||||
|
||||
#if 0
|
||||
/* allocate the chorus module */
|
||||
synth->chorus = new_fluid_chorus(synth->sample_rate);
|
||||
if (synth->chorus == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Initialize multi-core variables if multiple cores enabled */
|
||||
if (synth->cores > 1)
|
||||
{
|
||||
|
@ -952,6 +964,7 @@ delete_fluid_synth(fluid_synth_t* synth)
|
|||
FLUID_FREE(synth->voice);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* free all the sample buffers */
|
||||
if (synth->left_buf != NULL) {
|
||||
for (i = 0; i < synth->nbuf; i++) {
|
||||
|
@ -998,6 +1011,7 @@ delete_fluid_synth(fluid_synth_t* synth)
|
|||
if (synth->chorus != NULL) {
|
||||
delete_fluid_chorus(synth->chorus);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* free the tunings, if any */
|
||||
if (synth->tuning != NULL) {
|
||||
|
@ -1273,6 +1287,8 @@ fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key, int vel)
|
|||
|
||||
channel = synth->channel[chan];
|
||||
|
||||
// if (chan != 11) return FLUID_OK; /* DEBUG */
|
||||
|
||||
/* make sure this channel has a preset */
|
||||
if (channel->preset == NULL) {
|
||||
if (synth->verbose) {
|
||||
|
@ -1903,8 +1919,11 @@ fluid_synth_system_reset_LOCAL(fluid_synth_t* synth)
|
|||
for (i = 0; i < synth->midi_channels; i++)
|
||||
fluid_channel_reset(synth->channel[i]);
|
||||
|
||||
fluid_chorus_reset(synth->chorus);
|
||||
fluid_revmodel_reset(synth->reverb);
|
||||
fluid_rvoice_eventhandler_push(synth->eventhandler,
|
||||
fluid_rvoice_mixer_reset_fx,
|
||||
synth->eventhandler->mixer, 0, 0.0f);
|
||||
// fluid_chorus_reset(synth->chorus);
|
||||
// fluid_revmodel_reset(synth->reverb);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
@ -2592,7 +2611,7 @@ fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth)
|
|||
}
|
||||
|
||||
fluid_rvoice_eventhandler_push(synth->eventhandler,
|
||||
fluid_rvoice_handler_set_polyphony, synth->eventhandler->handler,
|
||||
fluid_rvoice_mixer_set_polyphony, synth->eventhandler->mixer,
|
||||
synth->polyphony, 0.0f);
|
||||
|
||||
return FLUID_OK;
|
||||
|
@ -2678,8 +2697,8 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
|||
float** left, float** right,
|
||||
float** fx_left, float** fx_right)
|
||||
{
|
||||
fluid_real_t** left_in = synth->left_buf;
|
||||
fluid_real_t** right_in = synth->right_buf;
|
||||
fluid_real_t** left_in;
|
||||
fluid_real_t** right_in;
|
||||
double time = fluid_utime();
|
||||
int i, num, available, count, bytes;
|
||||
float cpu_load;
|
||||
|
@ -2689,6 +2708,7 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
|||
num = synth->cur;
|
||||
if (synth->cur < FLUID_BUFSIZE) {
|
||||
available = FLUID_BUFSIZE - synth->cur;
|
||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||
|
||||
num = (available > len)? len : available;
|
||||
bytes = num * sizeof(float);
|
||||
|
@ -2704,6 +2724,7 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
|||
/* Then, run one_block() and copy till we have 'len' samples */
|
||||
while (count < len) {
|
||||
fluid_synth_one_block(synth, 1);
|
||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||
|
||||
num = (FLUID_BUFSIZE > len - count)? len - count : FLUID_BUFSIZE;
|
||||
bytes = num * sizeof(float);
|
||||
|
@ -2789,8 +2810,8 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
|
|||
int i, j, k, l;
|
||||
float* left_out = (float*) lout;
|
||||
float* right_out = (float*) rout;
|
||||
fluid_real_t* left_in = synth->left_buf[0];
|
||||
fluid_real_t* right_in = synth->right_buf[0];
|
||||
fluid_real_t** left_in;
|
||||
fluid_real_t** right_in;
|
||||
double time = fluid_utime();
|
||||
float cpu_load;
|
||||
|
||||
|
@ -2800,11 +2821,13 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
|
|||
/* fill up the buffers as needed */
|
||||
if (l == FLUID_BUFSIZE) {
|
||||
fluid_synth_one_block(synth, 0);
|
||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||
|
||||
l = 0;
|
||||
}
|
||||
|
||||
left_out[j] = (float) left_in[l];
|
||||
right_out[k] = (float) right_in[l];
|
||||
left_out[j] = (float) left_in[0][l];
|
||||
right_out[k] = (float) right_in[0][l];
|
||||
}
|
||||
|
||||
synth->cur = l;
|
||||
|
@ -2876,8 +2899,8 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
|||
int i, j, k, cur;
|
||||
signed short* left_out = (signed short*) lout;
|
||||
signed short* right_out = (signed short*) rout;
|
||||
fluid_real_t* left_in = synth->left_buf[0];
|
||||
fluid_real_t* right_in = synth->right_buf[0];
|
||||
fluid_real_t** left_in;
|
||||
fluid_real_t** right_in;
|
||||
fluid_real_t left_sample;
|
||||
fluid_real_t right_sample;
|
||||
double time = fluid_utime();
|
||||
|
@ -2895,13 +2918,14 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
|||
prof_ref_on_block = fluid_profile_ref();
|
||||
|
||||
fluid_synth_one_block(synth, 0);
|
||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||
cur = 0;
|
||||
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref_on_block);
|
||||
}
|
||||
|
||||
left_sample = roundi (left_in[cur] * 32766.0f + rand_table[0][di]);
|
||||
right_sample = roundi (right_in[cur] * 32766.0f + rand_table[1][di]);
|
||||
left_sample = roundi (left_in[0][cur] * 32766.0f + rand_table[0][di]);
|
||||
right_sample = roundi (right_in[0][cur] * 32766.0f + rand_table[1][di]);
|
||||
|
||||
di++;
|
||||
if (di >= DITHER_SIZE) di = 0;
|
||||
|
@ -3008,9 +3032,9 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
|||
// fluid_voice_t* voice;
|
||||
// fluid_real_t* left_buf;
|
||||
// fluid_real_t* right_buf;
|
||||
fluid_real_t* reverb_buf;
|
||||
fluid_real_t* chorus_buf;
|
||||
fluid_real_t* bufs[synth->audio_groups*2 + synth->effects_channels*2];
|
||||
// fluid_real_t* reverb_buf;
|
||||
// fluid_real_t* chorus_buf;
|
||||
// fluid_real_t* bufs[synth->audio_groups*2 + synth->effects_channels*2];
|
||||
// int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
|
||||
// int count;
|
||||
fluid_profile_ref_var (prof_ref);
|
||||
|
@ -3032,7 +3056,12 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
|||
else break; /* First NULL ends the array (values are never set to NULL) */
|
||||
}
|
||||
|
||||
fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler);
|
||||
fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer,
|
||||
!do_not_mix_fx_to_out);
|
||||
fluid_rvoice_mixer_render(synth->eventhandler->mixer, 1);
|
||||
|
||||
#if 0
|
||||
/* Set up the reverb / chorus buffers only, when the effect is
|
||||
* enabled on synth level. Nonexisting buffers are detected in the
|
||||
* DSP loop. Not sending the reverb / chorus signal saves some time
|
||||
|
@ -3111,6 +3140,7 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
|||
}
|
||||
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref);
|
||||
#endif
|
||||
|
||||
#ifdef LADSPA
|
||||
/* Run the signal through the LADSPA Fx unit */
|
||||
|
@ -4097,6 +4127,10 @@ fluid_synth_set_reverb_on(fluid_synth_t* synth, int on)
|
|||
fluid_return_if_fail (synth != NULL);
|
||||
|
||||
fluid_atomic_int_set (&synth->with_reverb, on != 0);
|
||||
fluid_rvoice_eventhandler_push(synth->eventhandler,
|
||||
fluid_rvoice_mixer_set_reverb_enabled,
|
||||
synth->eventhandler->mixer,
|
||||
on != 0, 0.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4180,7 +4214,10 @@ fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
|
|||
if (set & FLUID_REVMODEL_SET_LEVEL)
|
||||
fluid_atomic_float_set (&synth->reverb_level, level);
|
||||
|
||||
fluid_revmodel_set (synth->reverb, set, roomsize, damping, width, level);
|
||||
fluid_rvoice_eventhandler_push5(synth->eventhandler,
|
||||
fluid_rvoice_mixer_set_reverb_params,
|
||||
synth->eventhandler->mixer, set,
|
||||
roomsize, damping, width, level, 0.0f);
|
||||
|
||||
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock reverb */
|
||||
|
||||
|
@ -4250,6 +4287,11 @@ fluid_synth_set_chorus_on(fluid_synth_t* synth, int on)
|
|||
fluid_return_if_fail (synth != NULL);
|
||||
|
||||
fluid_atomic_int_set (&synth->with_chorus, on != 0);
|
||||
|
||||
fluid_rvoice_eventhandler_push(synth->eventhandler,
|
||||
fluid_rvoice_mixer_set_chorus_enabled,
|
||||
synth->eventhandler->mixer,
|
||||
on != 0, 0.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4317,7 +4359,10 @@ fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
|
|||
if (set & FLUID_CHORUS_SET_TYPE)
|
||||
fluid_atomic_int_set (&synth->chorus_type, type);
|
||||
|
||||
fluid_chorus_set (synth->chorus, set, nr, level, speed, depth_ms, type);
|
||||
fluid_rvoice_eventhandler_push5(synth->eventhandler,
|
||||
fluid_rvoice_mixer_set_chorus_params,
|
||||
synth->eventhandler->mixer, set,
|
||||
nr, level, speed, depth_ms, type);
|
||||
|
||||
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock chorus */
|
||||
|
||||
|
|
|
@ -196,9 +196,9 @@ struct _fluid_synth_t
|
|||
int active_voice_count; /**< count of active voices */
|
||||
unsigned int noteid; /**< the id is incremented for every new note. it's used for noteoff's */
|
||||
unsigned int storeid;
|
||||
int nbuf; /**< How many audio buffers are used? (depends on nr of audio channels / groups)*/
|
||||
// int nbuf; /**< How many audio buffers are used? (depends on nr of audio channels / groups)*/
|
||||
fluid_rvoice_eventhandler_t* eventhandler;
|
||||
|
||||
/*
|
||||
fluid_real_t** left_buf;
|
||||
fluid_real_t** right_buf;
|
||||
fluid_real_t** fx_left_buf;
|
||||
|
@ -206,7 +206,7 @@ struct _fluid_synth_t
|
|||
|
||||
fluid_revmodel_t* reverb;
|
||||
fluid_chorus_t* chorus;
|
||||
|
||||
*/
|
||||
float reverb_roomsize; /**< Shadow of reverb roomsize */
|
||||
float reverb_damping; /**< Shadow of reverb damping */
|
||||
float reverb_width; /**< Shadow of reverb width */
|
||||
|
|
Loading…
Reference in a new issue