mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 15:01:40 +00:00
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:
parent
e5c832c587
commit
ac93e45103
10 changed files with 663 additions and 263 deletions
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue