Added public API functions: fluid_synth_sysex, fluid_synth_activate_key_tuning, fluid_synth_activate_octave_tuning, fluid_synth_tune_notes, fluid_synth_activate_tuning and fluid_synth_deactivate_tuning.

Added audio.realtime, audio.realtime-prio, midi.realtime and midi.realtime-prio (only ALSA updated to use them at this point).
Fixed bug in new_fluid_channel() where tuning field was not initialized.
fluid_settings.h had wrong field order in prototypes for fluid_settings_register_num and fluid_settings_register_int.
Added multi core support: "synth.cpu-cores" setting, fluid_synth_core_thread_func() and many core_ variables to fluid_synth_t.
Switched fluid_mutex_t back to a normal non-recursive mutex and added fluid_rec_mutex_t.
Added fluid_cond_t thread synchronization stuff.
Added fluid_cond_mutex_t which is a dynamically allocated regular mutex for use with fluid_cond_t.
fluid_settings_t and fluid_synth_t are now using fluid_rec_mutex_t (same as before, just name change).
Added platform specific fluid_thread_self_set_prio() functions to fluid_sys.c for activating high priority for the calling thread.
Modified new_fluid_thread() to take a prio and prio_level parameters.
Added missing fluid_atomic_pointer_set().
fluid_voice_write() changed to only take a voice audio buffer to render to, mixing is done separately with new fluid_voice_mix().
fluid_voice_write() now returns the count of samples rendered.
fluid_voice_effects() split into fluid_voice_filter() and fluid_voice_mix().
Added dsp_buf_count field to fluid_voice_t to keep track of last count of samples rendered to dsp_buf.
fluid_voice_get_channel() converted to a macro.
Added FLUID_DEFAULT_AUDIO_RT_PRIO and FLUID_DEFAULT_MIDI_RT_PRIO in fluidsynth_priv.h, set to 90 and 80 respectively which get used for audio.realtime-prio and midi.realtime-prio (was 90 and 90 before).
This commit is contained in:
Josh Green 2009-09-29 21:40:28 +00:00
parent 012f627017
commit 43a9923dff
16 changed files with 727 additions and 331 deletions

View file

@ -56,6 +56,8 @@ FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, i
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key);
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t* synth, int chan, int ctrl, int val);
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t* synth, int chan, int ctrl, int* pval);
FLUIDSYNTH_API int fluid_synth_sysex(fluid_synth_t *synth, char *data, int len,
char *response, int *response_len, int *handled, int dryrun);
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend);
FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val);
@ -187,22 +189,33 @@ FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int par
/* Tuning */
FLUIDSYNTH_API
int fluid_synth_create_key_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
char* name, double* pitch);
int fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
char* name, double* pitch);
FLUIDSYNTH_API
int fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
char* name, double* pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
char* name, double* pitch);
int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
char* name, double* pitch);
FLUIDSYNTH_API
int fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
char* name, double* pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_tune_notes(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
int len, int *keys, double* pitch, int apply);
int fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
int len, int *keys, double* pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int tuning_bank, int tuning_prog);
int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog);
FLUIDSYNTH_API
int fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
int apply);
FLUIDSYNTH_API int fluid_synth_reset_tuning(fluid_synth_t* synth, int chan);
FLUIDSYNTH_API
int fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply);
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t* synth);
FLUIDSYNTH_API
int fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog);
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
char* name, int len, double* pitch);
char* name, int len, double* pitch);
/* Misc */

View file

@ -221,6 +221,12 @@ void fluid_audio_driver_settings(fluid_settings_t* settings)
fluid_settings_register_int(settings, "audio.periods", 16, 2, 64, 0, NULL, NULL);
#endif
fluid_settings_register_str (settings, "audio.realtime", "yes", 0, NULL, NULL);
fluid_settings_add_option (settings, "audio.realtime", "yes");
fluid_settings_add_option (settings, "audio.realtime", "no");
fluid_settings_register_int (settings, "audio.realtime-prio",
FLUID_DEFAULT_AUDIO_RT_PRIO, 1, 99, 0, NULL, NULL);
/* Set the default driver */
#if JACK_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "jack", 0, NULL, NULL);

View file

@ -49,11 +49,6 @@
#define BUFFER_LENGTH 512
/* SCHED_FIFO priorities for ALSA threads (see pthread_attr_setschedparam) */
#define ALSA_PCM_SCHED_PRIORITY 90
#define ALSA_RAWMIDI_SCHED_PRIORITY 90
#define ALSA_SEQ_SCHED_PRIORITY 90
/** fluid_alsa_audio_driver_t
*
* This structure should not be accessed directly. Use audio port
@ -174,8 +169,9 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
int periods, period_size;
char* device = NULL;
pthread_attr_t attr;
int sched = SCHED_FIFO;
int sched;
struct sched_param priority;
int realtime_prio = 0;
int i, err, dir = 0;
snd_pcm_hw_params_t* hwparams;
snd_pcm_sw_params_t* swparams = NULL;
@ -192,7 +188,12 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
fluid_settings_getint(settings, "audio.periods", &periods);
fluid_settings_getint(settings, "audio.period-size", &period_size);
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
fluid_settings_dupstr(settings, "audio.alsa.device", &device); /* ++ dup device name */
fluid_settings_dupstr(settings, "audio.alsa.device", &device); /* ++ dup device name */
fluid_settings_getint (settings, "audio.realtime-prio", &realtime_prio);
if (fluid_settings_str_equal (settings, "audio.realtime", "yes"))
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
dev->data = data;
dev->callback = func;
@ -297,22 +298,6 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
FLUID_LOG(FLUID_ERR, "Failed to set start threshold.");
}
/* FIXME - Any of these calls important? One of them was causing massive
ALSA CPU consumption! */
// if (snd_pcm_sw_params_set_stop_threshold(dev->pcm, swparams, ~0u) != 0) {
// FLUID_LOG(FLUID_ERR, "Cannot turn off stop threshold.");
// }
// if (snd_pcm_sw_params_set_silence_threshold(dev->pcm, swparams, 0) != 0) {
// FLUID_LOG(FLUID_ERR, "Cannot set 0 silence threshold.");
// }
// if (snd_pcm_sw_params_set_silence_size(dev->pcm, swparams, 0) != 0) {
// FLUID_LOG(FLUID_ERR, "Cannot set 0 silence size.");
// }
// if (snd_pcm_sw_params_set_avail_min(dev->pcm, swparams, period_size / 2) != 0) {
if (snd_pcm_sw_params_set_avail_min(dev->pcm, swparams, period_size) != 0) {
FLUID_LOG(FLUID_ERR, "Software setup for minimum available frames failed.");
}
@ -348,7 +333,7 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_PCM_SCHED_PRIORITY : 0;
priority.sched_priority = (sched == SCHED_FIFO) ? realtime_prio : 0;
pthread_attr_setschedparam(&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_alsa_formats[i].run, (void*) dev);
@ -636,8 +621,9 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
int i, err;
fluid_alsa_rawmidi_driver_t* dev;
pthread_attr_t attr;
int sched = SCHED_FIFO;
int sched;
struct sched_param priority;
int realtime_prio = 0;
int count;
struct pollfd *pfd = NULL;
char* device = NULL;
@ -666,6 +652,12 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
goto error_recovery;
}
fluid_settings_getint (settings, "midi.realtime-prio", &realtime_prio);
if (fluid_settings_str_equal (settings, "midi.realtime", "yes"))
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
/* get the device name. if none is specified, use the default device. */
fluid_settings_dupstr(settings, "midi.alsa.device", &device); /* ++ alloc device name */
@ -734,7 +726,7 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_RAWMIDI_SCHED_PRIORITY : 0;
priority.sched_priority = (sched == SCHED_FIFO) ? realtime_prio : 0;
pthread_attr_setschedparam (&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_alsa_midi_run, (void*) dev);
@ -901,8 +893,9 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
int i, err;
fluid_alsa_seq_driver_t* dev;
pthread_attr_t attr;
int sched = SCHED_FIFO;
int sched;
struct sched_param priority;
int realtime_prio = 0;
int count;
struct pollfd *pfd = NULL;
char *device = NULL;
@ -929,6 +922,11 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
dev->driver.data = data;
dev->driver.handler = handler;
fluid_settings_getint (settings, "midi.realtime-prio", &realtime_prio);
if (fluid_settings_str_equal (settings, "midi.realtime", "yes"))
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
/* get the device name. if none is specified, use the default device. */
if (fluid_settings_dupstr(settings, "midi.alsa_seq.device", &device) == 0) /* ++ alloc device name */
@ -1056,7 +1054,7 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_SEQ_SCHED_PRIORITY : 0;
priority.sched_priority = (sched == SCHED_FIFO) ? realtime_prio : 0;
pthread_attr_setschedparam (&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_alsa_seq_run, (void*) dev);

View file

@ -55,6 +55,7 @@ new_fluid_channel(fluid_synth_t* synth, int num)
chan->synth = synth;
chan->channum = num;
chan->preset = NULL;
chan->tuning = NULL;
fluid_channel_init(chan);
fluid_channel_init_ctrl(chan, 0);

View file

@ -223,7 +223,8 @@ fluid_shell_t* new_fluid_shell(fluid_settings_t* settings, fluid_cmd_handler_t*
fluid_shell_init(shell, settings, handler, in, out);
if (thread) {
shell->thread = new_fluid_thread((fluid_thread_func_t) fluid_shell_run, shell, 1);
shell->thread = new_fluid_thread((fluid_thread_func_t) fluid_shell_run, shell,
FLUID_THREAD_PRIO_NORMAL, 0, TRUE);
if (shell->thread == NULL) {
delete_fluid_shell(shell);
return NULL;
@ -1813,7 +1814,8 @@ new_fluid_client(fluid_server_t* server, fluid_settings_t* settings,
client->settings = settings;
client->handler = handler;
client->thread = new_fluid_thread((fluid_thread_func_t) fluid_client_run, client, 0);
client->thread = new_fluid_thread((fluid_thread_func_t) fluid_client_run, client,
FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
if (client->thread == NULL) {
fluid_socket_close(sock);

View file

@ -68,7 +68,7 @@ struct _fluid_hashtable_t
volatile int ref_count;
fluid_destroy_notify_t key_destroy_func;
fluid_destroy_notify_t value_destroy_func;
fluid_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
fluid_rec_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
};
struct _fluid_hashtable_iter_t

View file

@ -145,6 +145,12 @@ void fluid_midi_driver_settings(fluid_settings_t* settings)
{
int i;
fluid_settings_register_str (settings, "midi.realtime", "yes", 0, NULL, NULL);
fluid_settings_add_option (settings, "midi.realtime", "yes");
fluid_settings_add_option (settings, "midi.realtime", "no");
fluid_settings_register_int (settings, "midi.realtime-prio",
FLUID_DEFAULT_MIDI_RT_PRIO, 1, 99, 0, NULL, NULL);
/* Set the default driver */
#if ALSA_SUPPORT
fluid_settings_register_str(settings, "midi.driver", "alsa_seq", 0, NULL, NULL);

View file

@ -238,7 +238,7 @@ new_fluid_settings(void)
fluid_settings_value_destroy_func);
if (settings == NULL) return NULL;
fluid_mutex_init (settings->mutex);
fluid_rec_mutex_init (settings->mutex);
fluid_settings_init(settings);
return settings;
}
@ -252,7 +252,7 @@ delete_fluid_settings(fluid_settings_t* settings)
{
fluid_return_if_fail (settings != NULL);
fluid_mutex_destroy (settings->mutex);
fluid_rec_mutex_destroy (settings->mutex);
delete_fluid_hashtable(settings);
}
@ -342,7 +342,7 @@ fluid_settings_get(fluid_settings_t* settings, char** name, int len,
fluid_setting_node_t **value)
{
fluid_hashtable_t* table = settings;
fluid_setting_node_t *node;
fluid_setting_node_t *node = NULL;
int n;
for (n = 0; n < len; n++) {
@ -445,7 +445,7 @@ fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, i
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (!fluid_settings_get(settings, tokens, ntokens, &node)) {
setting = new_fluid_str_setting(def, def, hints, fun, data);
@ -466,7 +466,7 @@ fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, i
}
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -489,7 +489,7 @@ fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (!fluid_settings_get(settings, tokens, ntokens, &node)) {
/* insert a new setting */
@ -515,7 +515,7 @@ fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
}
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -538,7 +538,7 @@ fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (!fluid_settings_get(settings, tokens, ntokens, &node)) {
/* insert a new setting */
@ -564,7 +564,7 @@ fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
}
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -590,9 +590,9 @@ fluid_settings_get_type(fluid_settings_t* settings, char* name)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
type = fluid_settings_get (settings, tokens, ntokens, &node) ? node->type : FLUID_NO_TYPE;
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return (type);
}
@ -618,7 +618,7 @@ fluid_settings_get_hints(fluid_settings_t* settings, char* name)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)) {
if (node->type == FLUID_NUM_TYPE) {
@ -630,7 +630,7 @@ fluid_settings_get_hints(fluid_settings_t* settings, char* name)
}
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return hints;
}
@ -656,7 +656,7 @@ fluid_settings_is_realtime(fluid_settings_t* settings, char* name)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)) {
if (node->type == FLUID_NUM_TYPE) {
@ -668,7 +668,7 @@ fluid_settings_is_realtime(fluid_settings_t* settings, char* name)
}
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return isrealtime;
}
@ -696,7 +696,7 @@ fluid_settings_setstr(fluid_settings_t* settings, char* name, char* str)
ntokens = fluid_settings_tokenize (name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get (settings, tokens, ntokens, &node)) {
if (node->type == FLUID_STR_TYPE) {
@ -717,7 +717,7 @@ fluid_settings_setstr(fluid_settings_t* settings, char* name, char* str)
if (retval != 1) delete_fluid_str_setting (setting);
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -753,7 +753,7 @@ fluid_settings_copystr(fluid_settings_t* settings, char* name, char* str, int le
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -768,7 +768,7 @@ fluid_settings_copystr(fluid_settings_t* settings, char* name, char* str, int le
retval = 1;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -799,7 +799,7 @@ fluid_settings_dupstr(fluid_settings_t* settings, char* name, char** str)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -814,7 +814,7 @@ fluid_settings_dupstr(fluid_settings_t* settings, char* name, char** str)
if (!setting->value || *str) retval = 1; /* Don't set to 1 if out of memory */
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -850,7 +850,7 @@ fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -860,7 +860,7 @@ fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str)
}
else *str = NULL;
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -888,7 +888,7 @@ fluid_settings_str_equal(fluid_settings_t* settings, char* name, char* s)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -896,7 +896,7 @@ fluid_settings_str_equal(fluid_settings_t* settings, char* name, char* s)
if (setting->value) retval = FLUID_STRCMP (setting->value, s) == 0;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -923,7 +923,7 @@ fluid_settings_getstr_default(fluid_settings_t* settings, char* name)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -931,7 +931,7 @@ fluid_settings_getstr_default(fluid_settings_t* settings, char* name)
retval = setting->def;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -958,7 +958,7 @@ fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -968,7 +968,7 @@ fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s)
retval = 1;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -995,7 +995,7 @@ fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -1015,7 +1015,7 @@ fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s)
}
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -1043,7 +1043,7 @@ fluid_settings_setnum(fluid_settings_t* settings, char* name, double val)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)) {
if (node->type == FLUID_NUM_TYPE) {
@ -1067,7 +1067,7 @@ fluid_settings_setnum(fluid_settings_t* settings, char* name, double val)
if (retval != 1) delete_fluid_num_setting (setting);
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -1095,7 +1095,7 @@ fluid_settings_getnum(fluid_settings_t* settings, char* name, double* val)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_NUM_TYPE)) {
@ -1104,7 +1104,7 @@ fluid_settings_getnum(fluid_settings_t* settings, char* name, double* val)
retval = 1;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -1132,7 +1132,7 @@ fluid_settings_getnum_range(fluid_settings_t* settings, char* name, double* min,
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_NUM_TYPE)) {
@ -1141,7 +1141,7 @@ fluid_settings_getnum_range(fluid_settings_t* settings, char* name, double* min,
*max = setting->max;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
}
/**
@ -1165,7 +1165,7 @@ fluid_settings_getnum_default(fluid_settings_t* settings, char* name)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_NUM_TYPE)) {
@ -1173,7 +1173,7 @@ fluid_settings_getnum_default(fluid_settings_t* settings, char* name)
retval = setting->def;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -1201,7 +1201,7 @@ fluid_settings_setint(fluid_settings_t* settings, char* name, int val)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)) {
if (node->type == FLUID_INT_TYPE) {
@ -1225,7 +1225,7 @@ fluid_settings_setint(fluid_settings_t* settings, char* name, int val)
if (retval != 1) delete_fluid_int_setting (setting);
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -1253,7 +1253,7 @@ fluid_settings_getint(fluid_settings_t* settings, char* name, int* val)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_INT_TYPE)) {
@ -1262,7 +1262,7 @@ fluid_settings_getint(fluid_settings_t* settings, char* name, int* val)
retval = 1;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -1289,7 +1289,7 @@ fluid_settings_getint_range(fluid_settings_t* settings, char* name, int* min, in
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_INT_TYPE)) {
@ -1298,7 +1298,7 @@ fluid_settings_getint_range(fluid_settings_t* settings, char* name, int* min, in
*max = setting->max;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
}
/**
@ -1322,7 +1322,7 @@ fluid_settings_getint_default(fluid_settings_t* settings, char* name)
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_INT_TYPE)) {
@ -1330,7 +1330,7 @@ fluid_settings_getint_default(fluid_settings_t* settings, char* name)
retval = setting->def;
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
return retval;
}
@ -1359,7 +1359,7 @@ fluid_settings_foreach_option (fluid_settings_t* settings, char* name, void* dat
ntokens = fluid_settings_tokenize(name, buf, tokens);
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
if (fluid_settings_get(settings, tokens, ntokens, &node)
&& (node->type == FLUID_STR_TYPE)) {
@ -1374,7 +1374,7 @@ fluid_settings_foreach_option (fluid_settings_t* settings, char* name, void* dat
}
}
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
}
/* Structure passed to fluid_settings_foreach_iter recursive function */
@ -1440,7 +1440,7 @@ fluid_settings_foreach(fluid_settings_t* settings, void* data, fluid_settings_fo
bag.data = data;
bag.path[0] = 0;
fluid_mutex_lock (settings->mutex);
fluid_rec_mutex_lock (settings->mutex);
fluid_hashtable_foreach(settings, fluid_settings_foreach_iter, &bag);
fluid_mutex_unlock (settings->mutex);
fluid_rec_mutex_unlock (settings->mutex);
}

View file

@ -42,14 +42,15 @@ int fluid_settings_register_str(fluid_settings_t* settings, char* name, char* de
/** returns 0 if the value has been registered correctly, non-zero
otherwise */
int fluid_settings_register_num(fluid_settings_t* settings, char* name, double min, double max,
double def, int hints, fluid_num_update_t fun, void* data);
int fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
double min, double max, int hints,
fluid_num_update_t fun, void* data);
/** returns 0 if the value has been registered correctly, non-zero
otherwise */
int fluid_settings_register_int(fluid_settings_t* settings, char* name, int min, int max,
int def, int hints, fluid_int_update_t fun, void* data);
int fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
int min, int max, int hints,
fluid_int_update_t fun, void* data);
#endif /* _FLUID_SETTINGS_H */

View file

@ -93,6 +93,7 @@ static int fluid_synth_set_polyphony_LOCAL(fluid_synth_t* synth, int polyphony);
static void init_dither(void);
static inline int roundi (float x);
static int fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out);
static void fluid_synth_core_thread_func (void* data);
static FLUID_INLINE void fluid_synth_process_event_queue_LOCAL
(fluid_synth_t *synth, fluid_event_queue_t *queue);
static fluid_voice_t* fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth);
@ -222,6 +223,7 @@ void fluid_synth_settings(fluid_settings_t* settings)
0, NULL, NULL);
fluid_settings_register_int(settings, "synth.device-id",
0, 126, 0, 0, NULL, NULL);
fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 256, 0, NULL, NULL);
}
/*
@ -517,7 +519,7 @@ new_fluid_synth(fluid_settings_t *settings)
}
FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
fluid_mutex_init(synth->mutex);
fluid_rec_mutex_init(synth->mutex);
fluid_private_init(synth->thread_queues);
synth->return_queue = fluid_event_queue_new (FLUID_MAX_RETURN_EVENTS);
@ -542,6 +544,7 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
fluid_settings_getnum(settings, "synth.gain", &synth->gain);
fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
/* register the callbacks */
fluid_settings_register_num(settings, "synth.gain",
@ -729,6 +732,57 @@ new_fluid_synth(fluid_settings_t *settings)
goto error_recovery;
}
/* Initialize multi-core variables if multiple cores enabled */
if (synth->cores > 1)
{
int prio, prio_level;
synth->core_mutex = new_fluid_cond_mutex ();
synth->core_cond = new_fluid_cond ();
synth->core_wait_last_cond = new_fluid_cond ();
synth->core_threads = FLUID_ARRAY (fluid_thread_t *, synth->cores - 1);
synth->core_voice_processed = FLUID_ARRAY (fluid_voice_t *, synth->polyphony);
synth->core_bufs = FLUID_MALLOC (synth->polyphony * FLUID_BUFSIZE * sizeof (fluid_real_t));
if (!synth->core_mutex || !synth->core_cond || !synth->core_wait_last_cond
|| !synth->core_threads || !synth->core_voice_processed
|| !synth->core_bufs)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery;
}
synth->cores_active = TRUE;
synth->core_work = FALSE;
synth->core_inprogress = 0;
synth->core_waiting_for_last = FALSE;
for (i = 0; i < synth->polyphony; i++)
synth->core_voice_processed[i] = NULL;
prio = fluid_settings_str_equal (synth->settings, "audio.realtime", "yes");
if (prio)
{
prio = FLUID_THREAD_PRIO_HIGH;
fluid_settings_getint (synth->settings, "audio.realtime-prio", &prio_level);
}
else
{
prio = FLUID_THREAD_PRIO_NORMAL;
prio_level = 0;
}
for (i = 0; i < synth->cores - 1; i++)
{
synth->core_threads[i] = new_fluid_thread (fluid_synth_core_thread_func,
synth, prio, prio_level, FALSE);
if (!synth->core_threads[i])
FLUID_LOG(FLUID_ERR, "Failed to create a synthesis core thread");
}
}
/* FIXME */
synth->start = fluid_curtime();
@ -755,26 +809,26 @@ fluid_synth_return_event_process_callback (void* data, unsigned int msec)
switch (event->type)
{
case FLUID_EVENT_QUEUE_ELEM_GAIN: /* Sync gain variable */
fluid_mutex_lock (synth->mutex); /* ++ Lock gain variable */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock gain variable */
synth->gain = event->dval;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
break;
case FLUID_EVENT_QUEUE_ELEM_REVERB: /* Sync reverb shadow variables */
fluid_mutex_lock (synth->mutex); /* ++ Lock reverb shadow variables */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock reverb shadow variables */
synth->reverb_roomsize = event->reverb.roomsize;
synth->reverb_damping = event->reverb.damping;
synth->reverb_width = event->reverb.width;
synth->reverb_level = event->reverb.level;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
break;
case FLUID_EVENT_QUEUE_ELEM_CHORUS: /* Sync chorus shadow variables */
fluid_mutex_lock (synth->mutex); /* ++ Lock chorus shadow variables */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock chorus shadow variables */
synth->chorus_nr = event->chorus.nr;
synth->chorus_level = event->chorus.level;
synth->chorus_speed = event->chorus.speed;
synth->chorus_depth = event->chorus.depth;
synth->chorus_type = event->chorus.type;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
break;
case FLUID_EVENT_QUEUE_ELEM_FREE_PRESET: /* Preset free event */
preset = (fluid_preset_t *)(event->pval);
@ -823,6 +877,26 @@ delete_fluid_synth(fluid_synth_t* synth)
fluid_event_queue_free(synth->return_queue);
}
/* Free multi-core resources (if multi-core enabled) */
if (synth->cores > 1)
{
/* Signal slave core threads to exit and wait for them to finish */
fluid_cond_mutex_lock (synth->core_mutex); /* ++ Lock */
synth->cores_active = FALSE;
fluid_cond_broadcast (synth->core_cond);
fluid_cond_mutex_unlock (synth->core_mutex); /* -- Unlock */
for (i = 0; i < synth->cores - 1; i++)
if (synth->core_threads[i])
fluid_thread_join (synth->core_threads[i]);
delete_fluid_cond_mutex (synth->core_mutex);
delete_fluid_cond (synth->core_cond);
delete_fluid_cond (synth->core_wait_last_cond);
FLUID_FREE (synth->core_voice_processed);
FLUID_FREE (synth->core_bufs);
}
/* turn off all voices, needed to unload SoundFont data */
if (synth->voice != NULL) {
for (i = 0; i < synth->nvoice; i++) {
@ -959,7 +1033,7 @@ delete_fluid_synth(fluid_synth_t* synth)
delete_fluid_list (synth->queue_pool);
fluid_private_free (synth->thread_queues);
fluid_mutex_destroy(synth->mutex);
fluid_rec_mutex_destroy(synth->mutex);
FLUID_FREE(synth);
@ -992,7 +1066,7 @@ fluid_synth_get_event_queue (fluid_synth_t* synth)
if (!queue) /* This thread has no queue yet? */
{
fluid_mutex_lock (synth->mutex); /* ++ lock queue_pool */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock queue_pool */
/* Use an unclaimed queue, if any (it will already be in synth->queues[] in that case) */
if (synth->queue_pool)
@ -1007,7 +1081,7 @@ fluid_synth_get_event_queue (fluid_synth_t* synth)
delete1_fluid_list (p);
}
fluid_mutex_unlock (synth->mutex); /* -- unlock queue_pool */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock queue_pool */
if (!queue) /* Create event queue, if one wasn't re-claimed */
{
@ -1180,9 +1254,9 @@ fluid_synth_thread_queue_destroy_notify (void *data)
/* Queues are not freed (can't be thread safe without locking in synth thread),
* added to pool for potential future use */
fluid_mutex_lock (synth->mutex); /* ++ lock queue_pool */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock queue_pool */
synth->queue_pool = fluid_list_prepend (synth->queue_pool, queue);
fluid_mutex_unlock (synth->mutex); /* -- unlock queue_pool */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock queue_pool */
}
/**
@ -2101,7 +2175,7 @@ fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
fluid_sfont_info_t *sfont_info;
fluid_list_t *list;
fluid_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
@ -2115,7 +2189,7 @@ fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
return preset;
}
@ -2134,7 +2208,7 @@ fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname
fluid_sfont_info_t *sfont_info;
fluid_list_t *list;
fluid_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
@ -2148,7 +2222,7 @@ fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
return preset;
}
@ -2167,7 +2241,7 @@ fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
fluid_list_t *list;
int ofs;
fluid_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
@ -2181,7 +2255,7 @@ fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
return preset;
}
@ -2483,9 +2557,9 @@ fluid_synth_get_gain(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex);
fluid_rec_mutex_lock (synth->mutex);
gain = synth->gain;
fluid_mutex_unlock (synth->mutex);
fluid_rec_mutex_unlock (synth->mutex);
return (gain);
}
@ -2511,7 +2585,7 @@ int
fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony)
{
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (polyphony >= 1 && polyphony <= synth->nvoice, FLUID_FAILED);
fluid_return_val_if_fail (polyphony >= 16 && polyphony <= synth->nvoice, FLUID_FAILED);
if (fluid_synth_should_queue (synth))
return fluid_synth_queue_int_event (synth, FLUID_EVENT_QUEUE_ELEM_POLYPHONY,
@ -2923,7 +2997,8 @@ fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
static int
fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
{
int i, auchan;
fluid_real_t local_voice_buf[FLUID_BUFSIZE];
int i, auchan, start_index, voice_index;
fluid_voice_t* voice;
fluid_real_t* left_buf;
fluid_real_t* right_buf;
@ -2931,6 +3006,8 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
fluid_real_t* chorus_buf;
int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
double prof_ref = fluid_profile_ref();
double prof_ref_voice;
int count;
/* Assign ID of synthesis thread, if not already set */
if (synth->synth_thread_id == FLUID_THREAD_ID_NULL)
@ -2970,12 +3047,99 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref);
/* call all playing synthesis processes */
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (synth->cores > 1)
{
/* Look for first active voice to process */
for (voice_index = 0; voice_index < synth->polyphony; voice_index++)
{
voice = synth->voice[voice_index];
if (_PLAYING (voice)) break;
}
if (_PLAYING(voice)) {
double prof_ref_voice = fluid_profile_ref();
/* Was there a voice to process? */
if (voice_index < synth->polyphony)
{
fluid_cond_mutex_lock (synth->core_mutex); /* ++ Lock core variables */
synth->core_voice_index = voice_index + 1; /* Set the next core_voice_index */
/* Tell the other core threads that there is work to do */
synth->core_work = TRUE;
synth->core_waiting_for_last = FALSE;
fluid_cond_broadcast (synth->core_cond);
fluid_cond_mutex_unlock (synth->core_mutex); /* -- Unlock core variables */
while (TRUE)
{
got_voice: /* We got a voice to process */
count = fluid_voice_write (voice, &synth->core_bufs[voice_index * FLUID_BUFSIZE]);
if (count > 0) synth->core_voice_processed[voice_index] = voice;
/* Look for next active voice to process (in a lock free manner) */
do
{
voice_index = fluid_atomic_int_get (&synth->core_voice_index);
for (start_index = voice_index; voice_index < synth->polyphony; voice_index++)
{
voice = synth->voice[voice_index];
if (_PLAYING (voice))
{
if (fluid_atomic_int_compare_and_exchange (&synth->core_voice_index,
start_index, voice_index + 1))
goto got_voice;
break; /* compare and exchange failed (another thread grabbed the voice first) */
}
}
}
while (voice_index < synth->polyphony);
/* No more voices to process */
fluid_cond_mutex_lock (synth->core_mutex); /* ++ Lock core variables */
synth->core_work = FALSE;
/* If there are still other core threads in progress, wait for last one */
if (synth->core_inprogress > 0)
{
synth->core_waiting_for_last = TRUE;
while (synth->core_inprogress > 0)
fluid_cond_wait (synth->core_wait_last_cond, synth->core_mutex);
}
fluid_cond_mutex_unlock (synth->core_mutex); /* -- Unlock core variables */
break; /* We're done */
} /* while (TRUE) - Process voices loop */
/* Mix all voices */
for (i = 0; i < synth->polyphony; i++)
{
voice = synth->core_voice_processed[i];
if (!voice) continue;
synth->core_voice_processed[i] = NULL;
auchan = fluid_channel_get_num (fluid_voice_get_channel (voice));
auchan %= synth->audio_groups;
left_buf = synth->left_buf[auchan];
right_buf = synth->right_buf[auchan];
fluid_voice_mix (voice, left_buf, right_buf, reverb_buf, chorus_buf);
} /* while (TRUE) - Mix processed voices loop */
} /* if (i < synth->polyphony) - Are there any voices to process? */
}
else /* synth->cores < 1 - Not multi-core enabled */
{
/* call all playing synthesis processes */
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (!_PLAYING(voice)) continue;
prof_ref_voice = fluid_profile_ref();
/* The output associated with a MIDI channel is wrapped around
* using the number of audio groups as modulo divider. This is
@ -2994,7 +3158,8 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
left_buf = synth->left_buf[auchan];
right_buf = synth->right_buf[auchan];
fluid_voice_write(voice, left_buf, right_buf, reverb_buf, chorus_buf);
fluid_voice_write (voice, local_voice_buf);
fluid_voice_mix (voice, left_buf, right_buf, reverb_buf, chorus_buf);
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref_voice);
}
@ -3066,6 +3231,84 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
return 0;
}
/* Core thread function (processes voices in parallel to primary synthesis thread) */
static void
fluid_synth_core_thread_func (void* data)
{
fluid_synth_t *synth = data;
fluid_voice_t *voice;
int i, count, start_index;
/* We do this, rather than adding an "if (first_run)" statement to the while loop */
fluid_cond_mutex_lock (synth->core_mutex); /* ++ Lock core variables */
synth->core_inprogress++;
fluid_cond_mutex_unlock (synth->core_mutex); /* -- Unlock core variables */
/* Loop until delete_fluid_synth() kills off core threads */
while (synth->cores_active)
{
fluid_cond_mutex_lock (synth->core_mutex); /* ++ Lock core variables */
synth->core_inprogress--;
/* Wakeup primary synthesis thread if it is waiting for last and we are it */
if (synth->core_waiting_for_last && synth->core_inprogress == 0)
fluid_cond_signal (synth->core_wait_last_cond);
/* Wait until there is core work */
while (!synth->core_work && synth->cores_active)
fluid_cond_wait (synth->core_cond, synth->core_mutex);
if (!synth->cores_active)
{
fluid_cond_mutex_unlock (synth->core_mutex); /* -- Unlock core variables */
break;
}
synth->core_inprogress++;
fluid_cond_mutex_unlock (synth->core_mutex); /* -- Unlock core variables */
/* Voice processing loop (lock free) */
while (TRUE)
{
/* Look for next active voice to process (in a lock free manner) */
do
{
i = fluid_atomic_int_get (&synth->core_voice_index);
for (start_index = i; i < synth->polyphony; i++)
{
voice = synth->voice[i];
if (_PLAYING (voice))
{
if (fluid_atomic_int_compare_and_exchange (&synth->core_voice_index,
start_index, i + 1))
goto got_voice;
break; /* compare and exchange failed (another thread grabbed the voice first) */
}
}
}
while (i < synth->polyphony);
/* No more voices to process */
fluid_atomic_int_set (&synth->core_voice_index, synth->polyphony);
fluid_atomic_int_set (&synth->core_work, FALSE);
break;
got_voice:
/* Synthesize the voice */
count = fluid_voice_write (voice, &synth->core_bufs[i * FLUID_BUFSIZE]);
/* Assign the processed voice to the same voicebuf index (if there was any audio) */
if (count > 0) synth->core_voice_processed[i] = voice;
} /* while (TRUE) - Lock free voice processing loop */
} /* while (synth->cores_active) */
}
/* Process events in an event queue */
static FLUID_INLINE void
fluid_synth_process_event_queue_LOCAL (fluid_synth_t *synth,
@ -3401,9 +3644,9 @@ fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader)
sfont_already_loaded = synth->sfont_info != NULL;
fluid_return_if_fail (!sfont_already_loaded);
fluid_mutex_lock (synth->mutex);
fluid_rec_mutex_lock (synth->mutex);
synth->loaders = fluid_list_prepend(synth->loaders, loader);
fluid_mutex_unlock (synth->mutex);
fluid_rec_mutex_unlock (synth->mutex);
}
/**
@ -3445,11 +3688,11 @@ fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets
return FLUID_FAILED;
}
fluid_mutex_lock (synth->mutex); /* ++ Lock sfont_id and sfont list */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock sfont_id and sfont list */
sfont->id = sfont_id = ++synth->sfont_id;
synth->sfont_info = fluid_list_prepend(synth->sfont_info, sfont_info); /* prepend to list */
fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
/* reset the presets for all channels if requested */
if (reset_presets) fluid_synth_program_reset(synth);
@ -3500,7 +3743,7 @@ fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets)
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
/* remove the SoundFont from the list */
fluid_mutex_lock (synth->mutex); /* ++ Lock sfont list */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock sfont list */
for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
sfont_info = (fluid_sfont_info_t*) fluid_list_get(list);
@ -3512,7 +3755,7 @@ fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets)
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
if (!list) {
FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
@ -3536,7 +3779,7 @@ fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont)
fluid_sfont_info_t *sfont_info;
int refcount = 0;
fluid_mutex_lock (synth->mutex); /* ++ Lock sfont_hash */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock sfont_hash */
sfont_info = fluid_hashtable_lookup (synth->sfont_hash, sfont);
@ -3549,7 +3792,7 @@ fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont)
fluid_hashtable_remove (synth->sfont_hash, sfont_info->sfont);
}
fluid_mutex_unlock (synth->mutex); /* -- Unlock sfont_hash */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock sfont_hash */
fluid_return_if_fail (sfont_info != NULL); /* Shouldn't happen, programming error if so */
@ -3598,7 +3841,7 @@ fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id)
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_mutex_lock (synth->mutex); /* ++ lock sfont list */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list */
/* Search for SoundFont and get its index */
for (list = synth->sfont_info, index = 0; list; list = fluid_list_next (list), index++) {
@ -3607,7 +3850,7 @@ fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id)
}
if (!list) {
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
return FLUID_FAILED;
}
@ -3615,7 +3858,7 @@ fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id)
/* keep a copy of the SoundFont's filename */
FLUID_STRCPY (filename, fluid_sfont_get_name (old_sfont_info->sfont));
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
if (fluid_synth_sfunload (synth, id, FALSE) != FLUID_OK)
return FLUID_FAILED;
@ -3638,10 +3881,10 @@ fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id)
return FLUID_FAILED;
}
fluid_mutex_lock (synth->mutex); /* ++ Lock sfont list */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock sfont list */
synth->sfont_info = fluid_list_insert_at(synth->sfont_info, index, sfont_info); /* insert the sfont at the same index */
fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
/* reset the presets for all channels */
fluid_synth_update_presets(synth);
@ -3672,11 +3915,11 @@ fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
sfont_info = new_fluid_sfont_info (synth, sfont);
if (!sfont_info) return (FLUID_FAILED);
fluid_mutex_lock (synth->mutex); /* ++ lock sfont_id and sfont_info list */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont_id and sfont_info list */
sfont->id = sfont_id = ++synth->sfont_id;
synth->sfont_info = fluid_list_prepend (synth->sfont_info, sfont_info); /* prepend to list */
fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
/* reset the presets for all channels */
fluid_synth_program_reset (synth);
@ -3705,7 +3948,7 @@ fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
fluid_return_if_fail (sfont != NULL);
/* remove the SoundFont from the list */
fluid_mutex_lock (synth->mutex); /* ++ Lock sfont_info list */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock sfont_info list */
for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
sfont_info = (fluid_sfont_info_t*) fluid_list_get(list);
@ -3720,7 +3963,7 @@ fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
/* reset the presets for all channels */
fluid_synth_program_reset (synth);
@ -3738,9 +3981,9 @@ fluid_synth_sfcount(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0);
fluid_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
count = fluid_list_size (synth->sfont_info);
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
return count;
}
@ -3762,10 +4005,10 @@ fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num)
fluid_return_val_if_fail (synth != NULL, NULL);
fluid_mutex_lock (synth->mutex); /* ++ lock sfont list */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list */
list = fluid_list_nth (synth->sfont_info, num);
if (list) sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
return sfont;
}
@ -3787,7 +4030,7 @@ fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id)
fluid_return_val_if_fail (synth != NULL, NULL);
fluid_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
@ -3795,7 +4038,7 @@ fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id)
break;
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
return list ? sfont : NULL;
}
@ -3818,7 +4061,7 @@ fluid_synth_get_sfont_by_name(fluid_synth_t* synth, char *name)
fluid_return_val_if_fail (synth != NULL, NULL);
fluid_return_val_if_fail (name != NULL, NULL);
fluid_mutex_lock (synth->mutex); /* ++ lock */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock */
for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
@ -3826,7 +4069,7 @@ fluid_synth_get_sfont_by_name(fluid_synth_t* synth, char *name)
break;
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
return list ? sfont : NULL;
}
@ -4015,9 +4258,9 @@ fluid_synth_get_reverb_roomsize(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock reverb value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock reverb value */
value = synth->reverb_roomsize;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4034,9 +4277,9 @@ fluid_synth_get_reverb_damp(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock reverb value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock reverb value */
value = synth->reverb_damping;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4053,9 +4296,9 @@ fluid_synth_get_reverb_level(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock reverb value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock reverb value */
value = synth->reverb_level;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4072,9 +4315,9 @@ fluid_synth_get_reverb_width(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock reverb value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock reverb value */
value = synth->reverb_width;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4197,9 +4440,9 @@ fluid_synth_get_chorus_nr(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock chorus value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock chorus value */
value = synth->chorus_nr;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4216,9 +4459,9 @@ fluid_synth_get_chorus_level(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock chorus value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock chorus value */
value = synth->chorus_level;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4235,9 +4478,9 @@ fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock chorus value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock chorus value */
value = synth->chorus_speed;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4254,9 +4497,9 @@ fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock chorus value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock chorus value */
value = synth->chorus_depth;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4273,9 +4516,9 @@ fluid_synth_get_chorus_type(fluid_synth_t* synth)
fluid_return_val_if_fail (synth != NULL, 0.0);
fluid_mutex_lock (synth->mutex); /* ++ Lock chorus value */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock chorus value */
value = synth->chorus_type;
fluid_mutex_unlock (synth->mutex); /* -- Unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock */
return value;
}
@ -4599,7 +4842,7 @@ fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock tunings */
tuning = new_fluid_tuning (name, bank, prog);
@ -4611,7 +4854,7 @@ fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
}
else retval = FLUID_FAILED;
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock tunings */
return retval;
}
@ -4665,7 +4908,7 @@ fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock tunings */
tuning = new_fluid_tuning (name, bank, prog);
@ -4677,7 +4920,7 @@ fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
}
else retval = FLUID_FAILED;
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock tunings */
return retval;
}
@ -4714,7 +4957,7 @@ fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
fluid_return_val_if_fail (key != NULL, FLUID_FAILED);
fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock tunings */
old_tuning = fluid_synth_get_tuning (synth, bank, prog);
@ -4732,7 +4975,7 @@ fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
}
else retval = FLUID_FAILED;
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock tunings */
return retval;
}
@ -4786,7 +5029,7 @@ fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
fluid_rec_mutex_lock (synth->mutex); /* ++ Lock tunings */
tuning = fluid_synth_get_tuning (synth, bank, prog);
@ -4800,7 +5043,7 @@ fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
if (tuning) fluid_tuning_ref (tuning); /* ++ ref for outside of lock */
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* -- Unlock tunings */
if (!tuning) return (FLUID_FAILED);
@ -4957,11 +5200,11 @@ fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog)
b = (p >> 8) & 0xFF;
p &= 0xFF;
fluid_mutex_lock (synth->mutex); /* ++ lock tunings */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock tunings */
if (!synth->tuning)
{
fluid_mutex_unlock (synth->mutex); /* -- unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock tunings */
return 0;
}
@ -4981,12 +5224,12 @@ fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog)
else fluid_private_set (synth->tuning_iter,
FLUID_INT_TO_POINTER ((b + 1) << 8), NULL);
fluid_mutex_unlock (synth->mutex); /* -- unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock tunings */
return 1;
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock tunings */
return 0;
}
@ -5007,7 +5250,7 @@ fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
{
fluid_tuning_t* tuning;
fluid_mutex_lock (synth->mutex); /* ++ lock tunings */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock tunings */
tuning = fluid_synth_get_tuning (synth, bank, prog);
@ -5023,7 +5266,7 @@ fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
FLUID_MEMCPY (pitch, fluid_tuning_get_all (tuning), 128 * sizeof (double));
}
fluid_mutex_unlock (synth->mutex); /* unlock tunings */
fluid_rec_mutex_unlock (synth->mutex); /* unlock tunings */
return tuning ? FLUID_OK : FLUID_FAILED;
}
@ -5228,6 +5471,7 @@ fluid_synth_set_gen2(fluid_synth_t* synth, int chan, int param,
* @param param SoundFont generator ID (#fluid_gen_type)
* @return Current generator value assigned to MIDI channel
*/
/* FIXME - Not currently SMP multi-thread safe (need atomic set/get of gen) */
float
fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param)
{
@ -5379,7 +5623,7 @@ fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset)
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
@ -5391,7 +5635,7 @@ fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset)
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
if (!list)
{
@ -5417,7 +5661,7 @@ fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id)
fluid_return_val_if_fail (synth != NULL, 0);
fluid_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont_info list */
for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
@ -5429,7 +5673,7 @@ fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id)
}
}
fluid_mutex_unlock (synth->mutex); /* -- unlock */
fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
if (!list)
{

View file

@ -110,6 +110,8 @@ typedef struct _fluid_sfont_info_t {
* left_buf[], right_buf[] (Contents change)
* fx_left_buf[], fx_right_buf[] (Contents change)
* LADSPA_FxUnit (Contents change)
* cores
* core_threads[]
*
* Single thread use only (modify only prior to synthesis):
* loaders<>
@ -152,7 +154,7 @@ struct _fluid_synth_t
fluid_private_t thread_queues; /**< Thread private data for event queues for each non-synthesis thread queuing events */
fluid_event_queue_t *queues[FLUID_MAX_EVENT_QUEUES]; /**< Thread event queues (NULL for unused elements) */
fluid_mutex_t mutex; /**< Lock for multi-thread sensitive variables (not used by synthesis process) */
fluid_rec_mutex_t mutex; /**< Lock for multi-thread sensitive variables (not used by synthesis process) */
fluid_list_t *queue_pool; /**< List of event queues whose threads have been destroyed and which can be re-used */
fluid_event_queue_t *return_queue; /**< Event queue for events from synthesis thread to non-synthesis threads (memory frees, etc) */
fluid_timer_t *return_queue_timer; /**< Timer thread to process return event queue */
@ -219,6 +221,23 @@ struct _fluid_synth_t
fluid_midi_router_t* midi_router; /**< The midi router. Could be done nicer. */
fluid_sample_timer_t* sample_timers; /**< List of timers triggered after a block has been processed */
int cores; /**< Number of CPU cores (1 by default) */
fluid_thread_t **core_threads; /**< Array of core threads (cores - 1 in length) */
unsigned char cores_active; /**< TRUE if core slave threads should remain active, FALSE to terminate them */
/* Multi-core variables (protected by core_mutex) */
fluid_cond_mutex_t *core_mutex; /**< Mutex to protect all core_ variables and use with core_cond and core_wait_last_cond */
fluid_cond_t *core_cond; /**< Thread condition for signaling core slave threads */
int core_work; /**< Boolean: TRUE if there is work, FALSE otherwise */
/* Used in a lockless atomic fashion */
int core_voice_index; /**< Next voice index to process */
fluid_voice_t **core_voice_processed; /**< Array for processed voices */
fluid_real_t *core_bufs; /**< Block containing audio buffers for each voice (FLUID_BUFSIZE in length each) */
int core_inprogress; /**< Count of secondary core threads in progress */
int core_waiting_for_last; /**< Boolean: Set to TRUE if primary synthesis thread is waiting for last slave thread to finish */
fluid_cond_t *core_wait_last_cond; /**< Thread condition for signaling primary synthesis thread when last slave thread finishes */
#ifdef LADSPA
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Effects unit for LADSPA support */
#endif

View file

@ -364,6 +364,13 @@ fluid_utime (void)
/* */
/*=============================================================*/
void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
{
if (prio == FLUID_THREAD_PRIO_HIGH)
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
}
/***************************************************************
*
* Timer
@ -488,6 +495,13 @@ fluid_timer_join(fluid_timer_t* timer)
/* */
/*=============================================================*/
void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
{
if (prio == FLUID_THREAD_PRIO_HIGH)
DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
}
/***************************************************************
*
* Timer
@ -610,6 +624,19 @@ fluid_timer_join(fluid_timer_t* timer)
/* */
/*=============================================================*/
void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
{
struct sched_param priority;
if (prio == FLUID_THREAD_PRIO_HIGH)
{
priority.sched_priority = prio_level;
if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &priority) != 0)
FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
}
}
/***************************************************************
*
@ -871,16 +898,61 @@ void fluid_profiling_print(void)
*
*/
typedef struct
{
fluid_thread_func_t func;
void *data;
int prio_level;
} fluid_thread_info_t;
static gpointer
fluid_thread_high_prio (gpointer data)
{
fluid_thread_info_t *info = data;
fluid_thread_self_set_prio (FLUID_THREAD_PRIO_HIGH, info->prio_level);
info->func (info->data);
FLUID_FREE (info);
return NULL;
}
/**
* Create a new thread.
* @param func Function to execute in new thread context
* @param data User defined data to pass to func
* @param prio Priority class
* @param prio_level Priority level (used only for high priority on Posix currently, 1-99)
* @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
* @return New thread pointer or NULL on error
*/
fluid_thread_t *
new_fluid_thread (fluid_thread_func_t func, void *data, int detach)
new_fluid_thread (fluid_thread_func_t func, void *data,
fluid_thread_prio_t prio, int prio_level, int detach)
{
GThread *thread;
fluid_thread_info_t *info;
GError *err = NULL;
g_return_val_if_fail (func != NULL, NULL);
thread = g_thread_create ((GThreadFunc)func, data, detach == FALSE, &err);
if (prio == FLUID_THREAD_PRIO_HIGH)
{
info = FLUID_NEW (fluid_thread_info_t);
if (!info)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
info->func = func;
info->data = data;
info->prio_level = prio_level;
thread = g_thread_create (fluid_thread_high_prio, info, detach == FALSE, &err);
}
else thread = g_thread_create ((GThreadFunc)func, data, detach == FALSE, &err);
if (!thread)
{
@ -892,12 +964,23 @@ new_fluid_thread (fluid_thread_func_t func, void *data, int detach)
return thread;
}
int delete_fluid_thread(fluid_thread_t* thread)
/**
* Frees data associated with a thread (does not actually stop thread).
* @param thread Thread to free
*/
void
delete_fluid_thread(fluid_thread_t* thread)
{
return FLUID_OK;
/* Threads free themselves when they quit, nothing to do */
}
int fluid_thread_join(fluid_thread_t* thread)
/**
* Join a thread (wait for it to terminate).
* @param thread Thread to join
* @return FLUID_OK
*/
int
fluid_thread_join(fluid_thread_t* thread)
{
g_thread_join (thread);
@ -1136,7 +1219,8 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
server_socket->data = data;
server_socket->cont = 1;
server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket, 0);
server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket,
FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
if (server_socket->thread == NULL) {
FLUID_FREE(server_socket);
fluid_socket_close(sock);

View file

@ -122,18 +122,38 @@ int delete_fluid_timer(fluid_timer_t* timer);
int fluid_timer_join(fluid_timer_t* timer);
int fluid_timer_stop(fluid_timer_t* timer);
/**
/* Muteces */
Muteces
/* Regular mutex */
typedef GStaticMutex fluid_mutex_t;
#define fluid_mutex_init(_m) g_static_mutex_init(&(_m))
#define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m))
#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))
#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m))
*/
/* Recursive lock capable mutex */
typedef GStaticRecMutex fluid_rec_mutex_t;
#define fluid_rec_mutex_init(_m) g_static_rec_mutex_init(&(_m))
#define fluid_rec_mutex_destroy(_m) g_static_rec_mutex_free(&(_m))
#define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))
#define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))
/* Recursive locks allowed */
typedef GStaticRecMutex fluid_mutex_t;
#define fluid_mutex_init(_m) g_static_rec_mutex_init(&(_m))
#define fluid_mutex_destroy(_m) g_static_rec_mutex_free(&(_m))
#define fluid_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))
#define fluid_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))
/* Dynamically allocated mutex suitable for fluid_cond_t use */
typedef GMutex fluid_cond_mutex_t;
#define new_fluid_cond_mutex g_mutex_new
#define delete_fluid_cond_mutex g_mutex_free
#define fluid_cond_mutex_lock g_mutex_lock
#define fluid_cond_mutex_unlock g_mutex_unlock
/* Thread condition signaling */
typedef GCond fluid_cond_t;
#define new_fluid_cond g_cond_new
#define delete_fluid_cond g_cond_free
#define fluid_cond_signal g_cond_signal
#define fluid_cond_broadcast g_cond_broadcast
#define fluid_cond_wait g_cond_wait
/* Atomic operations */
@ -148,7 +168,8 @@ typedef GStaticRecMutex fluid_mutex_t;
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
g_atomic_int_exchange_and_add(_pi, _add)
#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp)
#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp)
#define fluid_atomic_pointer_set(_pp, val) g_atomic_pointer_set(_pp, val)
#define fluid_atomic_pointer_compare_and_exchange(_pp, _old, _new) \
g_atomic_pointer_compare_and_exchange(_pp, _old, _new)
@ -180,37 +201,40 @@ typedef GStaticPrivate fluid_private_t;
#define fluid_private_free(_priv) g_static_private_free(&(_priv))
/**
Threads
*/
/* Threads */
typedef GThread fluid_thread_t;
typedef void (*fluid_thread_func_t)(void* data);
/** When detached, 'join' does not work and the thread destroys itself
when finished. */
fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach);
int delete_fluid_thread(fluid_thread_t* thread);
int fluid_thread_join(fluid_thread_t* thread);
/**
* Thread priorities.
*/
typedef enum
{
FLUID_THREAD_PRIO_NORMAL, /**< Normal thread priority */
FLUID_THREAD_PRIO_HIGH /**< High priority thread */
} fluid_thread_prio_t;
#define FLUID_THREAD_ID_NULL NULL /* A NULL "ID" value */
#define fluid_thread_id_t GThread * /* Data type for a thread ID */
#define fluid_thread_get_id() g_thread_self() /* Get unique "ID" for current thread */
/**
Sockets and I/O
fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void *data,
fluid_thread_prio_t prio, int prio_level, int detach);
void delete_fluid_thread(fluid_thread_t* thread);
void fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level);
int fluid_thread_join(fluid_thread_t* thread);
*/
/* Sockets and I/O */
fluid_istream_t fluid_get_stdin (void);
fluid_ostream_t fluid_get_stdout (void);
int fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len);
int fluid_ostream_printf (fluid_ostream_t out, char* format, ...);
/** The function should return 0 if no error occured, non-zero
otherwise. If the function return non-zero, the socket will be
closed by the server. */
/* The function should return 0 if no error occured, non-zero
otherwise. If the function return non-zero, the socket will be
closed by the server. */
typedef int (*fluid_server_func_t)(void* data, fluid_socket_t client_socket, char* addr);
fluid_server_socket_t* new_fluid_server_socket(int port, fluid_server_func_t func, void* data);
@ -222,17 +246,14 @@ fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock);
/**
/* Profiling */
Profiling
/**
* Profile numbers. List all the pieces of code you want to profile
* here. Be sure to add an entry in the fluid_profile_data table in
* fluid_sys.c
*/
/**
Profile numbers. List all the pieces of code you want to profile
here. Be sure to add an entry in the fluid_profile_data table in
fluid_sys.c
*/
enum {
FLUID_PROF_WRITE_S16,
FLUID_PROF_ONE_BLOCK,

View file

@ -48,11 +48,7 @@
static int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice);
static int calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
int gen_key2base, int is_decay);
static inline void fluid_voice_effects (fluid_voice_t *voice, int count,
fluid_real_t* dsp_left_buf,
fluid_real_t* dsp_right_buf,
fluid_real_t* dsp_reverb_buf,
fluid_real_t* dsp_chorus_buf);
static inline void fluid_voice_filter (fluid_voice_t *voice);
static fluid_real_t
fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice);
static void fluid_voice_check_sample_sanity(fluid_voice_t* voice);
@ -236,44 +232,38 @@ fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num)
}
/*
* fluid_voice_write
/**
* Synthesize a voice to a buffer.
*
* This is where it all happens. This function is called by the
* synthesizer to generate the sound samples. The synthesizer passes
* four audio buffers: left, right, reverb out, and chorus out.
* @param voice Voice to synthesize
* @param dsp_buf Audio buffer to synthesize to (#FLUID_BUFSIZE in length)
* @return Count of samples written to dsp_buf (can be 0)
*
* The biggest part of this function sets the correct values for all
* the dsp parameters (all the control data boil down to only a few
* dsp parameters). The dsp routine is #included in several places (fluid_dsp_core.c).
* Panning, reverb and chorus are processed separately. The dsp interpolation
* routine is in (fluid_dsp_float.c).
*/
int
fluid_voice_write(fluid_voice_t* voice,
fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf,
fluid_real_t* dsp_reverb_buf, fluid_real_t* dsp_chorus_buf)
fluid_voice_write (fluid_voice_t* voice, fluid_real_t *dsp_buf)
{
unsigned int i;
fluid_real_t incr;
fluid_real_t fres;
fluid_real_t target_amp; /* target amplitude */
int count;
int dsp_interp_method = voice->interp_method;
fluid_real_t dsp_buf[FLUID_BUFSIZE];
fluid_env_data_t* env_data;
fluid_real_t x;
int count = 0;
/* make sure we're playing and that we have sample data */
if (!_PLAYING(voice)) return FLUID_OK;
/* Other routines (such as fluid_voice_effects) use the last dsp_buf assigned */
voice->dsp_buf = dsp_buf;
voice->dsp_buf_count = 0;
/******************* sample **********************/
if (voice->sample == NULL)
{
fluid_voice_off(voice);
return FLUID_OK;
return 0;
}
fluid_check_fpe ("voice_write startup");
@ -319,7 +309,7 @@ fluid_voice_write(fluid_voice_t* voice,
{
fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off (voice);
return FLUID_OK;
return 0;
}
fluid_check_fpe ("voice_write vol env");
@ -593,8 +583,6 @@ fluid_voice_write(fluid_voice_t* voice,
* Depending on the position in the loop and the loop size, this
* may require several runs. */
voice->dsp_buf = dsp_buf;
switch (voice->interp_method)
{
case FLUID_INTERP_NONE:
@ -614,9 +602,10 @@ fluid_voice_write(fluid_voice_t* voice,
fluid_check_fpe ("voice_write interpolation");
if (count > 0)
fluid_voice_effects (voice, count, dsp_left_buf, dsp_right_buf,
dsp_reverb_buf, dsp_chorus_buf);
voice->dsp_buf_count = count;
/* Apply filter */
if (count > 0) fluid_voice_filter (voice);
/* turn off voice if short count (sample ended and not looping) */
if (count < FLUID_BUFSIZE)
@ -628,27 +617,19 @@ fluid_voice_write(fluid_voice_t* voice,
post_process:
voice->ticks += FLUID_BUFSIZE;
fluid_check_fpe ("voice_write postprocess");
return FLUID_OK;
return count;
}
/* Purpose:
*
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
* - mixes the processed sample to left and right output using the pan setting
* - sends the processed sample to chorus and reverb
*
/**
* Applies a lowpass filter with variable cutoff frequency and quality factor.
* @param voice Voice to apply filter to
* @param count Count of samples in voice->dsp_buf
*/
/*
* Variable description:
* - dsp_data: Pointer to the original waveform data
* - dsp_left_buf: The generated signal goes here, left channel
* - dsp_right_buf: right channel
* - dsp_reverb_buf: Send to reverb unit
* - dsp_chorus_buf: Send to chorus unit
* - dsp_a1: Coefficient for the filter
* - dsp_a2: same
* - dsp_b0: same
* - dsp_b1: same
* - dsp_b2: same
* - dsp_buf: Pointer to the synthesized audio data
* - dsp_a1, dsp_a2, dsp_b0, dsp_b1, dsp_b2: Filter coefficients
* - voice holds the voice structure
*
* A couple of variables are used internally, their results are discarded:
@ -660,12 +641,9 @@ fluid_voice_write(fluid_voice_t* voice,
* - dsp_centernode: delay line for the IIR filter
* - dsp_hist1: same
* - dsp_hist2: same
*
*/
static inline void
fluid_voice_effects (fluid_voice_t *voice, int count,
fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf,
fluid_real_t* dsp_reverb_buf, fluid_real_t* dsp_chorus_buf)
fluid_voice_filter (fluid_voice_t *voice)
{
/* IIR filter sample history */
fluid_real_t dsp_hist1 = voice->hist1;
@ -685,6 +663,7 @@ fluid_voice_effects (fluid_voice_t *voice, int count,
fluid_real_t *dsp_buf = voice->dsp_buf;
fluid_real_t dsp_centernode;
int count = voice->dsp_buf_count;
int dsp_i;
float v;
@ -729,50 +708,6 @@ fluid_voice_effects (fluid_voice_t *voice, int count,
}
}
/* pan (Copy the signal to the left and right output buffer) The voice
* panning generator has a range of -500 .. 500. If it is centered,
* it's close to 0. voice->amp_left and voice->amp_right are then the
* same, and we can save one multiplication per voice and sample.
*/
if ((-0.5 < voice->pan) && (voice->pan < 0.5))
{
/* The voice is centered. Use voice->amp_left twice. */
for (dsp_i = 0; dsp_i < count; dsp_i++)
{
v = voice->amp_left * dsp_buf[dsp_i];
dsp_left_buf[dsp_i] += v;
dsp_right_buf[dsp_i] += v;
}
}
else /* The voice is not centered. Stereo samples have one side zero. */
{
if (voice->amp_left != 0.0)
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i];
}
if (voice->amp_right != 0.0)
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i];
}
}
/* reverb send. Buffer may be NULL. */
if ((dsp_reverb_buf != NULL) && (voice->amp_reverb != 0.0))
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i];
}
/* chorus send. Buffer may be NULL. */
if ((dsp_chorus_buf != NULL) && (voice->amp_chorus != 0))
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i];
}
voice->hist1 = dsp_hist1;
voice->hist2 = dsp_hist2;
voice->a1 = dsp_a1;
@ -781,16 +716,76 @@ fluid_voice_effects (fluid_voice_t *voice, int count,
voice->b1 = dsp_b1;
voice->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
fluid_check_fpe ("voice_effects");
fluid_check_fpe ("voice_filter");
}
/*
* fluid_voice_get_channel
/**
* Mix voice data to left/right (panning), reverb and chorus buffers.
* @param voice Voice to mix
* @param left_buf Left audio buffer
* @param right_buf Right audio buffer
* @param reverb_buf Reverb buffer
* @param chorus_buf Chorus buffer
*
* NOTE: Uses voice->dsp_buf and voice->dsp_buf_count which were assigned
* by fluid_voice_write(). This is therefore meant to be called only after
* that function.
*/
fluid_channel_t*
fluid_voice_get_channel(fluid_voice_t* voice)
void
fluid_voice_mix (fluid_voice_t *voice,
fluid_real_t* left_buf, fluid_real_t* right_buf,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf)
{
return voice->channel;
fluid_real_t *dsp_buf = voice->dsp_buf;
int count = voice->dsp_buf_count;
int dsp_i;
float v;
/* pan (Copy the signal to the left and right output buffer) The voice
* panning generator has a range of -500 .. 500. If it is centered,
* it's close to 0. voice->amp_left and voice->amp_right are then the
* same, and we can save one multiplication per voice and sample.
*/
if ((-0.5 < voice->pan) && (voice->pan < 0.5))
{
/* The voice is centered. Use voice->amp_left twice. */
for (dsp_i = 0; dsp_i < count; dsp_i++)
{
v = voice->amp_left * dsp_buf[dsp_i];
left_buf[dsp_i] += v;
right_buf[dsp_i] += v;
}
}
else /* The voice is not centered. Stereo samples have one side zero. */
{
if (voice->amp_left != 0.0)
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i];
}
if (voice->amp_right != 0.0)
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i];
}
}
/* reverb send. Buffer may be NULL. */
if ((reverb_buf != NULL) && (voice->amp_reverb != 0.0))
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i];
}
/* chorus send. Buffer may be NULL. */
if ((chorus_buf != NULL) && (voice->amp_chorus != 0))
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i];
}
fluid_check_fpe ("voice_mix");
}
/*

View file

@ -116,6 +116,7 @@ struct _fluid_voice_t
fluid_real_t phase_incr; /* the phase increment for the next 64 samples */
fluid_real_t amp_incr; /* amplitude increment value */
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
int dsp_buf_count; /* Number of audio samples in dsp_buf */
/* End temporary variables */
@ -219,9 +220,7 @@ int delete_fluid_voice(fluid_voice_t* voice);
void fluid_voice_start(fluid_voice_t* voice);
void fluid_voice_calculate_gen_pitch(fluid_voice_t* voice);
int fluid_voice_write(fluid_voice_t* voice,
fluid_real_t* left, fluid_real_t* right,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
int fluid_voice_write (fluid_voice_t* voice, fluid_real_t *dsp_buf);
int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
fluid_channel_t* channel, int key, int vel,
@ -246,9 +245,14 @@ 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);
fluid_channel_t* fluid_voice_get_channel(fluid_voice_t* voice);
void fluid_voice_mix (fluid_voice_t *voice,
fluid_real_t* left_buf, fluid_real_t* right_buf,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
int fluid_voice_kill_excl(fluid_voice_t* voice);
#define fluid_voice_get_channel(voice) ((voice)->channel)
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
#define fluid_voice_get_chan(_voice) (_voice)->chan
@ -265,7 +269,7 @@ int fluid_voice_kill_excl(fluid_voice_t* voice);
#define _SAMPLEMODE(voice) ((int)(voice)->gen[GEN_SAMPLEMODE].val)
/* FIXME - Josh Green - This doesn't seem to be used anywhere */
/* FIXME - This doesn't seem to be used anywhere - JG */
fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
#define _GEN(_voice, _n) \

View file

@ -202,6 +202,8 @@ typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
#define FLUID_MAX_EVENTS_PER_BUFSIZE 1024 /**< Maximum queued MIDI events per #FLUID_BUFSIZE */
#define FLUID_MAX_RETURN_EVENTS 1024 /**< Maximum queued synthesis thread return events */
#define FLUID_MAX_EVENT_QUEUES 16 /**< Maximum number of unique threads queuing events */
#define FLUID_DEFAULT_AUDIO_RT_PRIO 90 /**< Default setting for audio.realtime-prio */
#define FLUID_DEFAULT_MIDI_RT_PRIO 80 /**< Default setting for midi.realtime-prio */
#ifndef PI
#define PI 3.141592654