Tuning system should now be thread safe.

Added reference counting to fluid_tuning_t.
Added fluid_tuning_duplicate() to duplicate a tuning.
Added FLUID_EVENT_QUEUE_ELEM_(SET_TUNING/REPL_TUNING/UNREF_TUNING) events.
The tuning iterator functions now use a thread private variable to be thread safe.
Tuning changes can now be activated in realtime (existing voices updated).
Added fluid_synth_get_event_elem() helper function.
Added fluid_atomic_float_(get/set) which use automic integer functions and memcpy.
CPU load should now be thread safe (using atomic integer functions to get/set float value).
Added missing free of thread_queues private in delete_fluid_synth().
Added conversion macros to/from integers and pointers.
Some cleanup in fluid_voice_calculate_gen_pitch() and made it public to libfluidsynth, used to activate tuning changes in realtime.
This commit is contained in:
Josh Green 2009-09-25 00:56:48 +00:00
parent e5c832c587
commit ac93e45103
10 changed files with 663 additions and 263 deletions

View file

@ -55,21 +55,21 @@ struct _fluid_channel_t
{
fluid_mutex_t mutex; /* Lock for thread sensitive parameters */
fluid_synth_t* synth; /**> Parent synthesizer instance */
int channum; /**> MIDI channel number */
fluid_synth_t* synth; /**< Parent synthesizer instance */
int channum; /**< MIDI channel number */
int sfont_bank_prog; /**> SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
fluid_preset_t* preset; /**> Selected preset */
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
fluid_preset_t* preset; /**< Selected preset */
int key_pressure; /**> MIDI key pressure */
int channel_pressure; /**> MIDI channel pressure */
int pitch_bend; /**> Current pitch bend value */
int pitch_wheel_sensitivity; /**> Current pitch wheel sensitivity */
int key_pressure; /**< MIDI key pressure */
int channel_pressure; /**< MIDI channel pressure */
int pitch_bend; /**< Current pitch bend value */
int pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
int cc[128]; /**> MIDI controller values */
int cc[128]; /**< MIDI controller values */
int interp_method; /**> Interpolation method (enum fluid_interp) */
fluid_tuning_t* tuning; /**> Micro tuning */
int interp_method; /**< Interpolation method (enum fluid_interp) */
fluid_tuning_t* tuning; /**< Micro tuning */
/* NRPN system */
int nrpn_select; /* Generator ID of SoundFont NRPN message */
@ -87,7 +87,7 @@ struct _fluid_channel_t
* combined attack time of the sound font and the modulators.
*
* However, it is useful to be able to specify the generator value
* absolutely, completely ignoring the generators of the sound font
* absolutely, completely ignoring the generators of the SoundFont
* and the values of modulators. The gen_abs field, is a boolean
* flag indicating whether the NRPN value is absolute or not.
*/

View file

@ -37,7 +37,10 @@ enum fluid_event_queue_elem
FLUID_EVENT_QUEUE_ELEM_STOP_VOICES, /**< Stop voices event. Uses ival field of event value */
FLUID_EVENT_QUEUE_ELEM_REVERB, /**< Reverb set or return event. Uses reverb field of event value */
FLUID_EVENT_QUEUE_ELEM_CHORUS, /**< Chorus set or return event. Uses chorus field of event value */
FLUID_EVENT_QUEUE_ELEM_FREE_PRESET /**< Free a preset return event. Uses pval field of event value */
FLUID_EVENT_QUEUE_ELEM_FREE_PRESET, /**< Free preset return event. Uses pval field of event value */
FLUID_EVENT_QUEUE_ELEM_SET_TUNING, /**< Set tuning event. Uses set_tuning field of event value */
FLUID_EVENT_QUEUE_ELEM_REPL_TUNING, /**< Replace tuning event. Uses repl_tuning field of event value */
FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING, /**< Unref tuning return event. Uses unref_tuning field of event value */
};
/**
@ -85,6 +88,35 @@ typedef struct
float depth;
} fluid_event_chorus_t;
/**
* Tuning assignment event structure.
*/
typedef struct
{
char apply; /**< TRUE to set tuning in realtime */
int channel; /**< MIDI channel number */
fluid_tuning_t *tuning; /**< Tuning to assign */
} fluid_event_set_tuning_t;
/**
* Tuning replacement event structure.
*/
typedef struct
{
char apply; /**< TRUE if tuning change should be applied in realtime */
fluid_tuning_t *old_tuning; /**< Old tuning pointer to replace */
fluid_tuning_t *new_tuning; /**< New tuning to assign */
} fluid_event_repl_tuning_t;
/**
* Tuning unref event structure.
*/
typedef struct
{
fluid_tuning_t *tuning; /**< Tuning to unref */
int count; /**< Number of times to unref */
} fluid_event_unref_tuning_t;
/**
* Event queue element structure.
@ -100,6 +132,9 @@ typedef struct
fluid_event_preset_t preset; /**< If type == #FLUID_EVENT_QUEUE_ELEM_PRESET */
fluid_event_reverb_t reverb; /**< If type == #FLUID_EVENT_QUEUE_ELEM_REVERB */
fluid_event_chorus_t chorus; /**< If type == #FLUID_EVENT_QUEUE_ELEM_CHORUS */
fluid_event_set_tuning_t set_tuning; /**< If type == #FLUID_EVENT_QUEUE_ELEM_SET_TUNING */
fluid_event_repl_tuning_t repl_tuning; /**< If type == #FLUID_EVENT_QUEUE_ELEM_REPL_TUNING */
fluid_event_unref_tuning_t unref_tuning; /**< If type == #FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING */
double dval; /**< A floating point payload value */
int ival; /**< An integer payload value */
void *pval; /**< A pointer payload value */

View file

@ -39,7 +39,7 @@ static int fluid_settings_tokenize(char* s, char *buf, char** ptr);
/* Common structure to all settings nodes */
typedef struct {
int type; /**> fluid_types_enum */
int type; /**< fluid_types_enum */
} fluid_setting_node_t;
typedef struct {

View file

@ -108,8 +108,17 @@ static void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth,
int chan, int key);
static fluid_tuning_t* fluid_synth_get_tuning(fluid_synth_t* synth,
int bank, int prog);
static fluid_tuning_t* fluid_synth_create_tuning(fluid_synth_t* synth, int bank,
int prog, char* name);
static int fluid_synth_replace_tuning_LOCK (fluid_synth_t* synth,
fluid_tuning_t *tuning,
int bank, int prog, int apply);
static void fluid_synth_replace_tuning_LOCAL (fluid_synth_t *synth,
fluid_tuning_t *old_tuning,
fluid_tuning_t *new_tuning,
int apply, int unref_new);
static void fluid_synth_update_voice_tuning_LOCAL (fluid_synth_t *synth,
fluid_channel_t *channel);
static int fluid_synth_set_tuning_LOCAL (fluid_synth_t *synth, int chan,
fluid_tuning_t *tuning, int apply);
static void fluid_synth_set_gen_LOCAL (fluid_synth_t* synth, int chan,
int param, float value, int absolute);
static void fluid_synth_stop_LOCAL (fluid_synth_t *synth, unsigned int id);
@ -595,6 +604,7 @@ new_fluid_synth(fluid_settings_t *settings)
synth->noteid = 0;
synth->ticks = 0;
synth->tuning = NULL;
fluid_private_init(synth->tuning_iter);
/* allocate and add the default sfont loader */
loader = new_fluid_defsfloader();
@ -917,6 +927,8 @@ delete_fluid_synth(fluid_synth_t* synth)
FLUID_FREE(synth->tuning);
}
fluid_private_free (synth->tuning_iter);
#ifdef LADSPA
/* Release the LADSPA Fx unit */
fluid_LADSPA_shutdown(synth->LADSPA_FxUnit);
@ -936,8 +948,8 @@ delete_fluid_synth(fluid_synth_t* synth)
for (i = 0; i < FLUID_MAX_EVENT_QUEUES; i++)
if (synth->queues[i]) fluid_event_queue_free (synth->queues[i]);
delete_fluid_list (synth->queue_pool);
fluid_private_free (synth->thread_queues);
fluid_mutex_destroy(synth->mutex);
@ -1020,6 +1032,29 @@ fluid_synth_get_event_queue (fluid_synth_t* synth)
return queue;
}
/* Get available event for sending to synthesis thread. Returns NULL on error.
* queue is an output parameter. */
static fluid_event_queue_elem_t *
fluid_synth_get_event_elem (fluid_synth_t* synth, fluid_event_queue_t **queue)
{
fluid_event_queue_t *q;
fluid_event_queue_elem_t *event;
q = fluid_synth_get_event_queue (synth);
if (!q) return NULL;
event = fluid_event_queue_get_inptr (q);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return NULL;
}
*queue = q;
return event;
}
/**
* Queues a MIDI event to the FluidSynth synthesis thread.
* @param synth FluidSynth instance
@ -1036,15 +1071,8 @@ fluid_synth_queue_midi_event (fluid_synth_t* synth, int type, int chan,
fluid_event_queue_t *queue;
fluid_event_queue_elem_t *event;
queue = fluid_synth_get_event_queue (synth);
if (!queue) return FLUID_FAILED;
event = fluid_event_queue_get_inptr (queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return FLUID_FAILED;
}
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
event->type = FLUID_EVENT_QUEUE_ELEM_MIDI;
event->midi.type = type;
@ -1073,15 +1101,8 @@ fluid_synth_queue_gen_event (fluid_synth_t* synth, int chan,
fluid_event_queue_t *queue;
fluid_event_queue_elem_t *event;
queue = fluid_synth_get_event_queue (synth);
if (!queue) return FLUID_FAILED;
event = fluid_event_queue_get_inptr (queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return FLUID_FAILED;
}
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
event->type = FLUID_EVENT_QUEUE_ELEM_GEN;
event->gen.channel = chan;
@ -1107,15 +1128,8 @@ fluid_synth_queue_float_event (fluid_synth_t* synth, int type, float val)
fluid_event_queue_t *queue;
fluid_event_queue_elem_t *event;
queue = fluid_synth_get_event_queue (synth);
if (!queue) return FLUID_FAILED;
event = fluid_event_queue_get_inptr (queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return FLUID_FAILED;
}
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
event->type = type;
event->dval = val;
@ -1138,15 +1152,8 @@ fluid_synth_queue_int_event (fluid_synth_t* synth, int type, int val)
fluid_event_queue_t *queue;
fluid_event_queue_elem_t *event;
queue = fluid_synth_get_event_queue (synth);
if (!queue) return FLUID_FAILED;
event = fluid_event_queue_get_inptr (queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return FLUID_FAILED;
}
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
event->type = type;
event->ival = val;
@ -1749,15 +1756,8 @@ fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset)
if (fluid_synth_should_queue (synth))
{
queue = fluid_synth_get_event_queue (synth);
if (!queue) return FLUID_FAILED;
event = fluid_event_queue_get_inptr (queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return FLUID_FAILED;
}
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
event->type = FLUID_EVENT_QUEUE_ELEM_PRESET;
event->preset.channel = chan;
@ -2299,6 +2299,7 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
fluid_real_t** right_in = synth->right_buf;
double time = fluid_utime();
int i, num, available, count, bytes;
float cpu_load;
/* make sure we're playing */
if (synth->state != FLUID_SYNTH_PLAYING)
@ -2339,10 +2340,8 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
synth->cur = num;
time = fluid_utime() - time;
synth->cpu_load = 0.5 * (synth->cpu_load +
time * synth->sample_rate / len / 10000.0);
/* printf("CPU: %.2f\n", synth->cpu_load); */
cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
fluid_atomic_float_set (&synth->cpu_load, cpu_load);
return FLUID_OK;
}
@ -2414,6 +2413,7 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
fluid_real_t* left_in = synth->left_buf[0];
fluid_real_t* right_in = synth->right_buf[0];
double time = fluid_utime();
float cpu_load;
/* make sure we're playing */
if (synth->state != FLUID_SYNTH_PLAYING)
@ -2435,10 +2435,8 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
synth->cur = l;
time = fluid_utime() - time;
synth->cpu_load = 0.5 * (synth->cpu_load +
time * synth->sample_rate / len / 10000.0);
/* printf("CPU: %.2f\n", synth->cpu_load); */
cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
fluid_atomic_float_set (&synth->cpu_load, cpu_load);
return FLUID_OK;
}
@ -2511,6 +2509,7 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
double time = fluid_utime();
int di = synth->dither_index;
double prof_ref_on_block;
float cpu_load;
/* make sure we're playing */
if (synth->state != FLUID_SYNTH_PLAYING) {
@ -2552,12 +2551,9 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
fluid_profile(FLUID_PROF_WRITE_S16, prof_ref);
time = fluid_utime() - time;
synth->cpu_load = 0.5 * (synth->cpu_load +
time * synth->sample_rate / len / 10000.0);
/* printf("CPU: %.2f\n", synth->cpu_load); */
cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
fluid_atomic_float_set (&synth->cpu_load, cpu_load);
return 0;
}
@ -2773,8 +2769,9 @@ fluid_synth_process_event_queue_LOCAL (fluid_synth_t *synth,
while ((event = fluid_event_queue_get_outptr (queue)))
{
if (event->type == FLUID_EVENT_QUEUE_ELEM_MIDI)
switch (event->type)
{
case FLUID_EVENT_QUEUE_ELEM_MIDI:
switch (event->midi.type)
{
case NOTE_ON:
@ -2810,27 +2807,44 @@ fluid_synth_process_event_queue_LOCAL (fluid_synth_t *synth,
}
break;
}
}
else if (event->type == FLUID_EVENT_QUEUE_ELEM_GAIN)
break;
case FLUID_EVENT_QUEUE_ELEM_GAIN:
fluid_synth_set_gain_LOCAL (synth, event->dval);
else if (event->type == FLUID_EVENT_QUEUE_ELEM_POLYPHONY)
break;
case FLUID_EVENT_QUEUE_ELEM_POLYPHONY:
fluid_synth_set_polyphony_LOCAL (synth, event->ival);
else if (event->type == FLUID_EVENT_QUEUE_ELEM_GEN)
break;
case FLUID_EVENT_QUEUE_ELEM_GEN:
fluid_synth_set_gen_LOCAL (synth, event->gen.channel, event->gen.param,
event->gen.value, event->gen.absolute);
else if (event->type == FLUID_EVENT_QUEUE_ELEM_PRESET)
break;
case FLUID_EVENT_QUEUE_ELEM_PRESET:
fluid_synth_set_preset_LOCAL (synth, event->preset.channel,
event->preset.preset);
else if (event->type == FLUID_EVENT_QUEUE_ELEM_STOP_VOICES)
break;
case FLUID_EVENT_QUEUE_ELEM_STOP_VOICES:
fluid_synth_stop_LOCAL (synth, event->ival);
else if (event->type == FLUID_EVENT_QUEUE_ELEM_REVERB)
break;
case FLUID_EVENT_QUEUE_ELEM_REVERB:
fluid_synth_set_reverb_LOCAL (synth, event->reverb.set, event->reverb.roomsize,
event->reverb.damping, event->reverb.width,
event->reverb.level);
else if (event->type == FLUID_EVENT_QUEUE_ELEM_CHORUS)
break;
case FLUID_EVENT_QUEUE_ELEM_CHORUS:
fluid_synth_set_chorus_LOCAL (synth, event->chorus.set, event->chorus.nr,
event->chorus.type, event->chorus.level,
event->chorus.speed, event->chorus.depth);
break;
case FLUID_EVENT_QUEUE_ELEM_SET_TUNING:
fluid_synth_set_tuning_LOCAL (synth, event->set_tuning.channel,
event->set_tuning.tuning, event->set_tuning.apply);
break;
case FLUID_EVENT_QUEUE_ELEM_REPL_TUNING:
fluid_synth_replace_tuning_LOCAL (synth, event->repl_tuning.old_tuning,
event->repl_tuning.new_tuning,
event->repl_tuning.apply, TRUE);
break;
}
fluid_event_queue_next_outptr (queue);
}
@ -3636,15 +3650,8 @@ fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
if (fluid_synth_should_queue (synth))
{
queue = fluid_synth_get_event_queue (synth);
if (!queue) return FLUID_FAILED;
event = fluid_event_queue_get_inptr (queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return FLUID_FAILED;
}
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
event->type = FLUID_EVENT_QUEUE_ELEM_REVERB;
event->reverb.set = set;
@ -3823,15 +3830,8 @@ fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
if (fluid_synth_should_queue (synth))
{
queue = fluid_synth_get_event_queue (synth);
if (!queue) return FLUID_FAILED;
event = fluid_event_queue_get_inptr (queue);
if (!event)
{
FLUID_LOG (FLUID_ERR, "Synthesis event queue full");
return FLUID_FAILED;
}
event = fluid_synth_get_event_elem (synth, &queue);
if (!event) return FLUID_FAILED;
event->type = FLUID_EVENT_QUEUE_ELEM_CHORUS;
event->chorus.set = set;
@ -4091,40 +4091,36 @@ fluid_synth_get_cpu_load(fluid_synth_t* synth)
{
fluid_return_val_if_fail (synth != NULL, 0);
return synth->cpu_load;
return fluid_atomic_float_get (&synth->cpu_load);
}
/* Get tuning for a given bank:program */
static fluid_tuning_t *
fluid_synth_get_tuning(fluid_synth_t* synth, int bank, int prog)
{
fluid_return_val_if_fail (synth != NULL, NULL);
fluid_return_val_if_fail (bank >= 0 && bank < 128, NULL);
fluid_return_val_if_fail (prog >= 0 && prog < 128, NULL);
if ((synth->tuning == NULL) ||
(synth->tuning[bank] == NULL) ||
(synth->tuning[bank][prog] == NULL)) {
FLUID_LOG(FLUID_WARN, "No tuning at bank %d, prog %d", bank, prog);
(synth->tuning[bank][prog] == NULL))
return NULL;
}
return synth->tuning[bank][prog];
}
/* Create tuning for a given bank:program */
static fluid_tuning_t*
fluid_synth_create_tuning(fluid_synth_t* synth, int bank, int prog, char* name)
/* Replace tuning on a given bank:program (need not already exist).
* Synth mutex should already be locked by caller. */
static int
fluid_synth_replace_tuning_LOCK (fluid_synth_t* synth, fluid_tuning_t *tuning,
int bank, int prog, int apply)
{
fluid_return_val_if_fail (synth != NULL, NULL);
fluid_return_val_if_fail (bank >= 0 && bank < 128, NULL);
fluid_return_val_if_fail (prog >= 0 && prog < 128, NULL);
fluid_tuning_t *old_tuning;
fluid_event_queue_t *queue;
fluid_event_queue_elem_t *event;
if (synth->tuning == NULL) {
synth->tuning = FLUID_ARRAY(fluid_tuning_t**, 128);
if (synth->tuning == NULL) {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
return FLUID_FAILED;
}
FLUID_MEMSET(synth->tuning, 0, 128 * sizeof(fluid_tuning_t**));
}
@ -4133,31 +4129,126 @@ fluid_synth_create_tuning(fluid_synth_t* synth, int bank, int prog, char* name)
synth->tuning[bank] = FLUID_ARRAY(fluid_tuning_t*, 128);
if (synth->tuning[bank] == NULL) {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
return FLUID_FAILED;
}
FLUID_MEMSET(synth->tuning[bank], 0, 128 * sizeof(fluid_tuning_t*));
}
if (synth->tuning[bank][prog] == NULL) {
synth->tuning[bank][prog] = new_fluid_tuning(name, bank, prog);
if (synth->tuning[bank][prog] == NULL) {
return NULL;
old_tuning = synth->tuning[bank][prog];
synth->tuning[bank][prog] = tuning;
if (old_tuning) {
if (!fluid_tuning_unref (old_tuning, 1)) /* -- unref old tuning */
{ /* Replace old tuning if present */
if (fluid_synth_should_queue (synth))
{
event = fluid_synth_get_event_elem (synth, &queue);
if (event)
{
fluid_tuning_ref (tuning); /* ++ ref new tuning for event */
event->type = FLUID_EVENT_QUEUE_ELEM_REPL_TUNING;
event->repl_tuning.apply = apply;
event->repl_tuning.old_tuning = old_tuning;
event->repl_tuning.new_tuning = tuning;
fluid_event_queue_next_inptr (queue);
}
}
else fluid_synth_replace_tuning_LOCAL (synth, old_tuning, tuning, apply, FALSE);
}
}
if ((fluid_tuning_get_name(synth->tuning[bank][prog]) == NULL)
|| (FLUID_STRCMP(fluid_tuning_get_name(synth->tuning[bank][prog]), name) != 0)) {
fluid_tuning_set_name(synth->tuning[bank][prog], name);
return FLUID_OK;
}
/* Replace a tuning with a new one in all MIDI channels. new_tuning can be
* NULL, in which case channels are reset to default equal tempered scale. */
static void
fluid_synth_replace_tuning_LOCAL (fluid_synth_t *synth, fluid_tuning_t *old_tuning,
fluid_tuning_t *new_tuning, int apply, int unref_new)
{
fluid_event_queue_elem_t *event;
fluid_channel_t *channel;
int old_tuning_unref = 0;
int i;
for (i = 0; i < synth->midi_channels; i++)
{
channel = synth->channel[i];
if (fluid_channel_get_tuning (channel) == old_tuning)
{
old_tuning_unref++;
if (new_tuning) fluid_tuning_ref (new_tuning); /* ++ ref new tuning for channel */
fluid_channel_set_tuning (channel, new_tuning);
if (apply) fluid_synth_update_voice_tuning_LOCAL (synth, channel);
}
}
return synth->tuning[bank][prog];
/* Send unref old tuning event if any unrefs */
if (old_tuning_unref > 0)
{
event = fluid_event_queue_get_inptr (synth->return_queue);
if (event)
{
event->type = FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING;
event->unref_tuning.tuning = old_tuning;
event->unref_tuning.count = old_tuning_unref;
fluid_event_queue_next_inptr (synth->return_queue);
}
else
{ /* Just unref it in synthesis thread if queue is full */
fluid_tuning_unref (old_tuning, old_tuning_unref);
FLUID_LOG (FLUID_ERR, "Synth return event queue full");
}
}
if (!unref_new || !new_tuning) return;
/* Send new tuning unref if requested (for replace queue event for example) */
event = fluid_event_queue_get_inptr (synth->return_queue);
if (event)
{
event->type = FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING;
event->unref_tuning.tuning = new_tuning;
event->unref_tuning.count = 1;
fluid_event_queue_next_inptr (synth->return_queue);
}
else
{ /* Just unref it in synthesis thread if queue is full */
fluid_tuning_unref (new_tuning, 1);
FLUID_LOG (FLUID_ERR, "Synth return event queue full");
}
}
/* Update voice tunings in realtime */
static void
fluid_synth_update_voice_tuning_LOCAL (fluid_synth_t *synth, fluid_channel_t *channel)
{
fluid_voice_t *voice;
int i;
for (i = 0; i < synth->polyphony; i++)
{
voice = synth->voice[i];
if (_ON (voice) && (voice->channel == channel))
{
fluid_voice_calculate_gen_pitch (voice);
fluid_voice_update_param (voice, GEN_PITCH);
}
}
}
/**
* Set the tuning of the entire MIDI note scale.
* @param synth FluidSynth instance
* @param bank MIDI bank number for this tuning (0-16383)
* @param prog MIDI program number for this tuning (0-127)
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
* @param name Label name for this tuning
* @param pitch Array of pitch values (length of 128, each value is number of
* cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc).
@ -4168,19 +4259,36 @@ int
fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
char* name, double* pitch)
{
fluid_tuning_t* tuning = fluid_synth_create_tuning(synth, bank, prog, name);
fluid_tuning_t* tuning;
int retval = FLUID_OK;
if (tuning == NULL) return FLUID_FAILED;
if (pitch) fluid_tuning_set_all(tuning, pitch);
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
return FLUID_OK;
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
tuning = new_fluid_tuning (name, bank, prog);
if (tuning)
{
if (pitch) fluid_tuning_set_all (tuning, pitch);
retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, FALSE);
if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
}
else retval = FLUID_FAILED;
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
return retval;
}
/**
* Apply an octave tuning to every octave in the MIDI note scale.
* @param synth FluidSynth instance
* @param bank MIDI bank number for this tuning (0-16383)
* @param prog MIDI program number for this tuning (0-127)
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
* @param name Label name for this tuning
* @param pitch Array of pitch values (length of 12 for each note of an octave
* starting at note C, values are number of offset cents to add to the normal
@ -4191,19 +4299,37 @@ int
fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
char* name, double* pitch)
{
fluid_tuning_t* tuning = fluid_synth_create_tuning(synth, bank, prog, name);
fluid_tuning_t* tuning;
int retval = FLUID_OK;
if (tuning == NULL) return FLUID_FAILED;
fluid_tuning_set_octave(tuning, pitch);
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
return FLUID_OK;
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
tuning = new_fluid_tuning (name, bank, prog);
if (tuning)
{
fluid_tuning_set_octave (tuning, pitch);
retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, TRUE);
if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
}
else retval = FLUID_FAILED;
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
return retval;
}
/**
* Set tuning values for one or more MIDI notes for an existing tuning.
* @param synth FluidSynth instance
* @param bank MIDI bank number for this tuning (0-16383)
* @param prog MIDI program number for this tuning (0-127)
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
* @param len Number of MIDI notes to assign
* @param key Array of MIDI key numbers (length of 'len', values 0-127)
* @param pitch Array of pitch values (length of 'len', values are number of
@ -4211,40 +4337,155 @@ fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
* @param apply Not used currently, may be used in the future to apply tuning
* change in realtime.
* @return FLUID_OK on success, FLUID_FAILED otherwise
*
* NOTE: Prior to version 1.1.0 it was an error to specify a tuning that didn't
* already exist. Starting with 1.1.0, the default equal tempered scale will be
* used as a basis, if no tuning exists for the given bank and prog.
*/
int
fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
int len, int *key, double* pitch, int apply)
{
fluid_tuning_t* tuning = fluid_synth_get_tuning(synth, bank, prog);
fluid_tuning_t* old_tuning, *new_tuning;
int retval = FLUID_OK;
int i;
if (tuning == NULL) return FLUID_FAILED;
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
fluid_return_val_if_fail (len > 0, FLUID_FAILED);
fluid_return_val_if_fail (key != NULL, FLUID_FAILED);
fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
for (i = 0; i < len; i++)
fluid_tuning_set_pitch(tuning, key[i], pitch[i]);
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
return FLUID_OK;
old_tuning = fluid_synth_get_tuning (synth, bank, prog);
if (old_tuning)
new_tuning = fluid_tuning_duplicate (old_tuning);
else new_tuning = new_fluid_tuning ("Unnamed", bank, prog);
if (new_tuning)
{
for (i = 0; i < len; i++)
fluid_tuning_set_pitch (new_tuning, key[i], pitch[i]);
retval = fluid_synth_replace_tuning_LOCK (synth, new_tuning, bank, prog, apply);
if (retval == FLUID_FAILED) fluid_tuning_unref (new_tuning, 1);
}
else retval = FLUID_FAILED;
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
return retval;
}
/**
* Activate an existing tuning scale on a MIDI channel.
* Activate a tuning scale on a MIDI channel.
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param bank MIDI bank number of tuning
* @param prog MIDI program number of tuning
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
* @return FLUID_OK on success, FLUID_FAILED otherwise
*
* NOTE: Prior to version 1.1.0 it was an error to select a tuning that didn't
* already exist. Starting with 1.1.0, the default equal tempered scale will be
* used, if no tuning exists for the given bank and prog.
*/
int
fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
{
fluid_tuning_t* tuning = fluid_synth_get_tuning(synth, bank, prog);
if (tuning == NULL) return FLUID_FAILED;
fluid_event_queue_elem_t *event;
fluid_event_queue_t *queue;
fluid_tuning_t* tuning;
int retval = FLUID_OK;
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
fluid_channel_set_tuning(synth->channel[chan], synth->tuning[bank][prog]);
fluid_mutex_lock (synth->mutex); /* ++ Lock tunings */
tuning = fluid_synth_get_tuning (synth, bank, prog);
/* If no tuning exists, create a new default tuning. We do this, so that
* it can be replaced later, if any changes are made. */
if (!tuning)
{
tuning = new_fluid_tuning ("Unnamed", bank, prog);
if (tuning) fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, FALSE);
}
if (tuning) fluid_tuning_ref (tuning); /* ++ ref for outside of lock */
fluid_mutex_unlock (synth->mutex); /* -- Unlock tunings */
if (!tuning) return (FLUID_FAILED);
/* NOTE: tuning can be NULL, to use default equal tempered scale */
if (fluid_synth_should_queue (synth))
{
event = fluid_synth_get_event_elem (synth, &queue);
if (event)
{
fluid_tuning_ref (tuning); /* ++ ref new tuning for event */
event->type = FLUID_EVENT_QUEUE_ELEM_SET_TUNING;
event->set_tuning.apply = TRUE;
event->set_tuning.channel = chan;
event->set_tuning.tuning = tuning;
fluid_event_queue_next_inptr (queue);
}
else retval = FLUID_FAILED;
}
else
{
fluid_tuning_ref (tuning); /* ++ ref new tuning for following function */
retval = fluid_synth_set_tuning_LOCAL (synth, chan, tuning, TRUE);
}
fluid_tuning_unref (tuning, 1); /* -- unref for outside of lock */
return retval;
}
/* Local synthesis thread set tuning function (takes over tuning reference) */
static int
fluid_synth_set_tuning_LOCAL (fluid_synth_t *synth, int chan,
fluid_tuning_t *tuning, int apply)
{
fluid_event_queue_elem_t *event;
fluid_tuning_t *old_tuning;
fluid_channel_t *channel;
channel = synth->channel[chan];
old_tuning = fluid_channel_get_tuning (channel);
fluid_channel_set_tuning (channel, tuning); /* !! Takes over callers reference */
if (apply) fluid_synth_update_voice_tuning_LOCAL (synth, channel);
/* Send unref old tuning event */
if (old_tuning)
{
event = fluid_event_queue_get_inptr (synth->return_queue);
if (event)
{
event->type = FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING;
event->unref_tuning.tuning = old_tuning;
event->unref_tuning.count = 1;
fluid_event_queue_next_inptr (synth->return_queue);
}
else
{ /* Just unref it in synthesis thread if queue is full */
fluid_tuning_unref (old_tuning, 1);
FLUID_LOG (FLUID_ERR, "Synth return event queue full");
}
}
return FLUID_OK;
}
@ -4258,12 +4499,30 @@ fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
int
fluid_synth_reset_tuning(fluid_synth_t* synth, int chan)
{
fluid_event_queue_elem_t *event;
fluid_event_queue_t *queue;
int retval = FLUID_OK;
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
fluid_channel_set_tuning(synth->channel[chan], NULL);
if (fluid_synth_should_queue (synth))
{
event = fluid_synth_get_event_elem (synth, &queue);
return FLUID_OK;
if (event)
{
event->type = FLUID_EVENT_QUEUE_ELEM_SET_TUNING;
event->set_tuning.apply = TRUE;
event->set_tuning.channel = chan;
event->set_tuning.tuning = NULL;
fluid_event_queue_next_inptr (queue);
}
else retval = FLUID_FAILED;
}
else retval = fluid_synth_set_tuning_LOCAL (synth, chan, NULL, TRUE);
return retval;
}
/**
@ -4275,7 +4534,7 @@ fluid_synth_tuning_iteration_start(fluid_synth_t* synth)
{
fluid_return_if_fail (synth != NULL);
synth->cur_tuning = NULL;
fluid_private_set (synth->tuning_iter, FLUID_INT_TO_POINTER (0), NULL);
}
/**
@ -4288,39 +4547,49 @@ fluid_synth_tuning_iteration_start(fluid_synth_t* synth)
int
fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog)
{
void *pval;
int b = 0, p = 0;
fluid_return_val_if_fail (synth != NULL, 0);
fluid_return_val_if_fail (bank != NULL, 0);
fluid_return_val_if_fail (prog != NULL, 0);
if (synth->tuning == NULL) return 0;
/* Current tuning iteration stored as: bank << 8 | program */
pval = fluid_private_get (synth->tuning_iter);
p = FLUID_POINTER_TO_INT (pval);
b = (p >> 8) & 0xFF;
p &= 0xFF;
if (synth->cur_tuning != NULL) {
/* get the next program number */
b = fluid_tuning_get_bank(synth->cur_tuning);
p = 1 + fluid_tuning_get_prog(synth->cur_tuning);
if (p >= 128) {
p = 0;
b++;
fluid_mutex_lock (synth->mutex); /* ++ lock tunings */
if (!synth->tuning)
{
fluid_mutex_unlock (synth->mutex); /* -- unlock tunings */
return 0;
}
for (; b < 128; b++, p = 0)
{
if (synth->tuning[b] == NULL) continue;
for (; p < 128; p++)
{
if (synth->tuning[b][p] == NULL) continue;
*bank = b;
*prog = p;
if (p < 127) fluid_private_set (synth->tuning_iter,
FLUID_INT_TO_POINTER (b << 8 | (p + 1)), NULL);
else fluid_private_set (synth->tuning_iter,
FLUID_INT_TO_POINTER ((b + 1) << 8), NULL);
fluid_mutex_unlock (synth->mutex); /* -- unlock tunings */
return 1;
}
}
while (b < 128) {
if (synth->tuning[b] != NULL) {
while (p < 128) {
if (synth->tuning[b][p] != NULL) {
synth->cur_tuning = synth->tuning[b][p];
*bank = b;
*prog = p;
return 1;
}
p++;
}
}
p = 0;
b++;
}
fluid_mutex_unlock (synth->mutex); /* -- unlock tunings */
return 0;
}
@ -4333,25 +4602,33 @@ fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog)
* @param name Location to store tuning name or NULL to ignore
* @param len Maximum number of chars to store to 'name' (including NULL byte)
* @param pitch Array to store tuning scale to or NULL to ignore (len of 128)
* @return FLUID_OK on success, FLUID_FAILED otherwise
* @return FLUID_OK if matching tuning was found, FLUID_FAILED otherwise
*/
int
fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
char* name, int len, double* pitch)
{
fluid_tuning_t* tuning = fluid_synth_get_tuning(synth, bank, prog);
fluid_tuning_t* tuning;
if (tuning == NULL) return FLUID_FAILED;
fluid_mutex_lock (synth->mutex); /* ++ lock tunings */
if (name) {
snprintf(name, len - 1, "%s", fluid_tuning_get_name(tuning));
name[len - 1] = 0; /* make sure the string is null terminated */
tuning = fluid_synth_get_tuning (synth, bank, prog);
if (tuning)
{
if (name)
{
snprintf (name, len - 1, "%s", fluid_tuning_get_name (tuning));
name[len - 1] = 0; /* make sure the string is null terminated */
}
if (pitch)
FLUID_MEMCPY (pitch, fluid_tuning_get_all (tuning), 128 * sizeof (double));
}
if (pitch)
FLUID_MEMCPY(pitch, fluid_tuning_get_all(tuning), 128 * sizeof(double));
fluid_mutex_unlock (synth->mutex); /* unlock tunings */
return FLUID_OK;
return tuning ? FLUID_OK : FLUID_FAILED;
}
/**
@ -4486,7 +4763,7 @@ fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value)
fluid_return_val_if_fail (param >= 0 && param < GEN_LAST, FLUID_FAILED);
if (fluid_synth_should_queue (synth))
return (fluid_synth_queue_gen_event (synth, chan, param, value, FALSE));
return fluid_synth_queue_gen_event (synth, chan, param, value, FALSE);
else fluid_synth_set_gen_LOCAL (synth, chan, param, value, FALSE);
return FLUID_OK;

View file

@ -82,10 +82,10 @@ enum fluid_synth_status
* SoundFont with the SoundFont instance and additional fields.
*/
typedef struct _fluid_sfont_info_t {
fluid_sfont_t *sfont; /**> Loaded SoundFont */
fluid_synth_t *synth; /**> Parent synth */
int refcount; /**> SoundFont reference count (0 if no presets referencing it) */
int bankofs; /**> Bank offset */
fluid_sfont_t *sfont; /**< Loaded SoundFont */
fluid_synth_t *synth; /**< Parent synth */
int refcount; /**< SoundFont reference count (0 if no presets referencing it) */
int bankofs; /**< Bank offset */
} fluid_sfont_info_t;
/*
@ -119,18 +119,17 @@ typedef struct _fluid_sfont_info_t {
* settings{} (has its own mutex)
* sfont_info<>
* tuning
* cur_tuning
* sfont_id
* gain
* reverb_roomsize, reverb_damping, reverb_width, reverb_level
* chorus_nr, chorus_level, chorus_speed, chorus_depth, chorus_type
*
* Atomic int operations:
* Atomic operations:
* ----------------------
* with_reverb
* with_chorus
* state
*
* cpu_load
* noteid
* storeid
* outbuf
@ -143,51 +142,50 @@ typedef struct _fluid_sfont_info_t {
* chorus{}
* cur
* dither_index
* cpu_load
* polyphony (atomic int get for non-synth threads)
* st_gain
*/
struct _fluid_synth_t
{
fluid_thread_id_t synth_thread_id; /**> ID of the synthesis thread or FLUID_THREAD_ID_NULL if not yet set */
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_thread_id_t synth_thread_id; /**< ID of the synthesis thread or FLUID_THREAD_ID_NULL if not yet set */
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_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 */
fluid_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 */
fluid_settings_t* settings; /**> the synthesizer settings */
int polyphony; /**> maximum polyphony */
char with_reverb; /**> Should the synth use the built-in reverb unit? */
char with_chorus; /**> Should the synth use the built-in chorus unit? */
char verbose; /**> Turn verbose mode on? */
char dump; /**> Dump events to stdout to hook up a user interface? */
double sample_rate; /**> The sample rate */
int midi_channels; /**> the number of MIDI channels (>= 16) */
int audio_channels; /**> the number of audio channels (1 channel=left+right) */
int audio_groups; /**> the number of (stereo) 'sub'groups from the synth.
fluid_settings_t* settings; /**< the synthesizer settings */
int polyphony; /**< maximum polyphony */
char with_reverb; /**< Should the synth use the built-in reverb unit? */
char with_chorus; /**< Should the synth use the built-in chorus unit? */
char verbose; /**< Turn verbose mode on? */
char dump; /**< Dump events to stdout to hook up a user interface? */
double sample_rate; /**< The sample rate */
int midi_channels; /**< the number of MIDI channels (>= 16) */
int audio_channels; /**< the number of audio channels (1 channel=left+right) */
int audio_groups; /**< the number of (stereo) 'sub'groups from the synth.
Typically equal to audio_channels. */
int effects_channels; /**> the number of effects channels (>= 2) */
int state; /**> the synthesizer state */
unsigned int ticks; /**> the number of audio samples since the start */
unsigned int start; /**> the start in msec, as returned by system clock */
int effects_channels; /**< the number of effects channels (>= 2) */
int state; /**< the synthesizer state */
unsigned int ticks; /**< the number of audio samples since the start */
unsigned int start; /**< the start in msec, as returned by system clock */
fluid_list_t *loaders; /**> the SoundFont loaders */
fluid_list_t *sfont_info; /**> List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
fluid_hashtable_t *sfont_hash; /**> Hash of fluid_sfont_t->fluid_sfont_info_t (remains until SoundFont is deleted) */
unsigned int sfont_id; /**> Incrementing ID assigned to each loaded SoundFont */
fluid_list_t *loaders; /**< the SoundFont loaders */
fluid_list_t *sfont_info; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
fluid_hashtable_t *sfont_hash; /**< Hash of fluid_sfont_t->fluid_sfont_info_t (remains until SoundFont is deleted) */
unsigned int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
double gain; /**> master gain */
double st_gain; /**> Synth thread gain shadow value */
fluid_channel_t** channel; /**> the channels */
int nvoice; /**> the length of the synthesis process array (max polyphony allowed) */
fluid_voice_t** voice; /**> the synthesis voices */
unsigned int noteid; /**> the id is incremented for every new note. it's used for noteoff's */
double gain; /**< master gain */
double st_gain; /**< Synth thread gain shadow value */
fluid_channel_t** channel; /**< the channels */
int nvoice; /**< the length of the synthesis process array (max polyphony allowed) */
fluid_voice_t** voice; /**< the synthesis 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_real_t** left_buf;
fluid_real_t** right_buf;
@ -197,31 +195,31 @@ 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 */
float reverb_level; /**> Shadow of reverb level */
float reverb_roomsize; /**< Shadow of reverb roomsize */
float reverb_damping; /**< Shadow of reverb damping */
float reverb_width; /**< Shadow of reverb width */
float reverb_level; /**< Shadow of reverb level */
int chorus_nr; /**> Shadow of chorus number */
float chorus_level; /**> Shadow of chorus level */
float chorus_speed; /**> Shadow of chorus speed */
float chorus_depth; /**> Shadow of chorus depth */
int chorus_type; /**> Shadow of chorus type */
int chorus_nr; /**< Shadow of chorus number */
float chorus_level; /**< Shadow of chorus level */
float chorus_speed; /**< Shadow of chorus speed */
float chorus_depth; /**< Shadow of chorus depth */
int chorus_type; /**< Shadow of chorus type */
int cur; /**> the current sample in the audio buffers to be output */
int dither_index; /**> current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
int cur; /**< the current sample in the audio buffers to be output */
int dither_index; /**< current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
char outbuf[256]; /**> buffer for message output */
double cpu_load;
char outbuf[256]; /**< buffer for message output */
float cpu_load; /**< CPU load in percent (CPU time required / audio synthesized time * 100) */
fluid_tuning_t*** tuning; /**> 128 banks of 128 programs for the tunings */
fluid_tuning_t* cur_tuning; /**> current tuning in the iteration */
fluid_tuning_t*** tuning; /**< 128 banks of 128 programs for the tunings */
fluid_private_t tuning_iter; /**< Tuning iterators per each thread */
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 */
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 */
#ifdef LADSPA
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**> Effects unit for LADSPA support */
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Effects unit for LADSPA support */
#endif
};

View file

@ -60,6 +60,9 @@ void fluid_time_config(void);
#define fluid_return_if_fail g_return_if_fail
#define FLUID_INLINE inline
#define FLUID_POINTER_TO_UINT GPOINTER_TO_UINT
#define FLUID_UINT_TO_POINTER GUINT_TO_POINTER
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
/*
@ -149,6 +152,24 @@ typedef GStaticRecMutex fluid_mutex_t;
#define fluid_atomic_pointer_compare_and_exchange(_pp, _old, _new) \
g_atomic_pointer_compare_and_exchange(_pp, _old, _new)
static FLUID_INLINE void
fluid_atomic_float_set(volatile float *fptr, float val)
{
sint32 ival;
memcpy (&ival, &val, 4);
fluid_atomic_int_set ((volatile int *)fptr, ival);
}
static FLUID_INLINE float
fluid_atomic_float_get(volatile float *fptr)
{
sint32 ival;
float fval;
ival = fluid_atomic_int_get ((volatile int *)fptr);
memcpy (&fval, &ival, 4);
return fval;
}
/* Thread private data */

View file

@ -21,6 +21,7 @@
#include "fluid_tuning.h"
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
fluid_tuning_t* new_fluid_tuning(char* name, int bank, int prog)
@ -47,18 +48,83 @@ fluid_tuning_t* new_fluid_tuning(char* name, int bank, int prog)
tuning->pitch[i] = i * 100.0;
}
tuning->refcount = 1; /* Start with a refcount of 1 */
return tuning;
}
void delete_fluid_tuning(fluid_tuning_t* tuning)
/* Duplicate a tuning */
fluid_tuning_t *
fluid_tuning_duplicate (fluid_tuning_t *tuning)
{
if (tuning == NULL) {
return;
fluid_tuning_t *new_tuning;
int i;
new_tuning = FLUID_NEW (fluid_tuning_t);
if (!new_tuning) {
FLUID_LOG (FLUID_PANIC, "Out of memory");
return NULL;
}
if (tuning->name != NULL) {
FLUID_FREE(tuning->name);
if (tuning->name)
{
new_tuning->name = FLUID_STRDUP (tuning->name);
if (!new_tuning->name)
{
FLUID_FREE (new_tuning);
FLUID_LOG (FLUID_PANIC, "Out of memory");
return NULL;
}
}
FLUID_FREE(tuning);
else new_tuning->name = NULL;
new_tuning->bank = tuning->bank;
new_tuning->prog = tuning->prog;
for (i = 0; i < 128; i++)
new_tuning->pitch[i] = tuning->pitch[i];
new_tuning->refcount = 1; /* Start with a refcount of 1 */
return new_tuning;
}
void
delete_fluid_tuning (fluid_tuning_t *tuning)
{
if (tuning->name) FLUID_FREE (tuning->name);
FLUID_FREE (tuning);
}
/* Add a reference to a tuning object */
void
fluid_tuning_ref (fluid_tuning_t *tuning)
{
fluid_return_if_fail (tuning != NULL);
fluid_atomic_int_inc (&tuning->refcount);
}
/* Unref a tuning object, when it reaches 0 it is deleted, returns TRUE if deleted */
int
fluid_tuning_unref (fluid_tuning_t *tuning, int count)
{
fluid_return_val_if_fail (tuning != NULL, FALSE);
/* Add and compare are separate, but that is OK, since refcount will only
* reach 0 when there are no references and therefore no possibility of
* another thread adding a reference in between */
fluid_atomic_int_add (&tuning->refcount, -count);
/* Delete when refcount reaches 0 */
if (!fluid_atomic_int_get (&tuning->refcount))
{
delete_fluid_tuning (tuning);
return TRUE;
}
else return FALSE;
}
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name)

View file

@ -39,10 +39,14 @@ struct _fluid_tuning_t {
int bank;
int prog;
double pitch[128]; /* the pitch of every key, in cents */
int refcount; /* Tuning reference count */
};
fluid_tuning_t* new_fluid_tuning(char* name, int bank, int prog);
void delete_fluid_tuning(fluid_tuning_t* tuning);
void delete_fluid_tuning (fluid_tuning_t *tuning);
fluid_tuning_t *fluid_tuning_duplicate (fluid_tuning_t *tuning);
void fluid_tuning_ref (fluid_tuning_t *tuning);
int fluid_tuning_unref (fluid_tuning_t *tuning, int count);
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name);
char* fluid_tuning_get_name(fluid_tuning_t* tuning);

View file

@ -813,9 +813,10 @@ void fluid_voice_start(fluid_voice_t* voice)
voice->status = FLUID_VOICE_ON;
}
static void
void
fluid_voice_calculate_gen_pitch(fluid_voice_t* voice)
{
fluid_tuning_t* tuning;
fluid_real_t x;
/* The GEN_PITCH is a hack to fit the pitch bend controller into the
@ -826,17 +827,14 @@ fluid_voice_calculate_gen_pitch(fluid_voice_t* voice)
* one key remains fixed. Here C3 (MIDI number 60) is used.
*/
if (fluid_channel_has_tuning(voice->channel)) {
/* pitch(scalekey) + scale * (pitch(key) - pitch(scalekey)) */
#define __pitch(_k) fluid_tuning_get_pitch(tuning, _k)
fluid_tuning_t* tuning = fluid_channel_get_tuning(voice->channel);
x = __pitch((int) (voice->root_pitch / 100.0f));
voice->gen[GEN_PITCH].val = (x + (voice->gen[GEN_SCALETUNE].val / 100.0f *
(__pitch(voice->key) - x)));
tuning = fluid_channel_get_tuning (voice->channel);
x = fluid_tuning_get_pitch (tuning, (int)(voice->root_pitch / 100.0f));
voice->gen[GEN_PITCH].val = voice->gen[GEN_SCALETUNE].val / 100.0f *
(fluid_tuning_get_pitch (tuning, voice->key) - x) + x;
} else {
voice->gen[GEN_PITCH].val = (voice->gen[GEN_SCALETUNE].val * (voice->key - voice->root_pitch / 100.0f)
+ voice->root_pitch);
voice->gen[GEN_PITCH].val = voice->gen[GEN_SCALETUNE].val
* (voice->key - voice->root_pitch / 100.0f) + voice->root_pitch;
}
}
/*

View file

@ -217,6 +217,7 @@ fluid_voice_t* new_fluid_voice(fluid_real_t output_rate);
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,