fluid_synth.c
上传用户:tjmskj2
上传日期:2020-08-17
资源大小:577k
文件大小:181k
- /* FluidSynth - A Software Synthesizer
- *
- * Copyright (C) 2003 Peter Hanappe and others.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307, USA
- */
- #include <math.h>
- #include "fluid_synth.h"
- #include "fluid_sys.h"
- #include "fluid_chan.h"
- #include "fluid_tuning.h"
- #include "fluid_settings.h"
- #include "fluid_sfont.h"
- #include "fluid_hash.h"
- #ifdef TRAP_ON_FPE
- #define _GNU_SOURCE
- #include <fenv.h>
- /* seems to not be declared in fenv.h */
- extern int feenableexcept (int excepts);
- #endif
- /* A descriptive alias for fluid_return_if_fail/fluid_return_val_if_fail */
- #define fluid_synth_is_synth_thread(_s) (fluid_thread_get_id() == (_s)->synth_thread_id)
- /* Macro used to check if an event should be queued or not (not in synthesis thread context?) */
- #define fluid_synth_should_queue(_s) (!fluid_synth_is_synth_thread(_s))
- static void fluid_synth_init(void);
- static void fluid_synth_return_event_process_thread (void* data);
- static fluid_event_queue_t *fluid_synth_get_event_queue (fluid_synth_t* synth);
- static int fluid_synth_queue_midi_event (fluid_synth_t* synth, int type, int chan,
- int param1, int param2);
- static int fluid_synth_queue_gen_event (fluid_synth_t* synth, int chan,
- int param, float value, int absolute);
- static int fluid_synth_queue_int_event (fluid_synth_t* synth, int type, int val);
- static void fluid_synth_thread_queue_destroy_notify (void *data);
- static int fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key,
- int vel);
- static int fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key);
- static int fluid_synth_damp_voices_LOCAL(fluid_synth_t* synth, int chan);
- static int fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num);
- static int fluid_synth_update_device_id (fluid_synth_t *synth, char *name,
- int value);
- static int fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, const char *data,
- int len, char *response,
- int *response_len, int avail_response,
- int *handled, int dryrun);
- static int fluid_synth_all_notes_off_LOCAL(fluid_synth_t* synth, int chan);
- static int fluid_synth_all_sounds_off_LOCAL(fluid_synth_t* synth, int chan);
- static int fluid_synth_system_reset_LOCAL(fluid_synth_t* synth);
- static int fluid_synth_modulate_voices_LOCAL(fluid_synth_t* synth, int chan,
- int is_cc, int ctrl);
- static int fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan);
- static int fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int channum);
- static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan);
- static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan);
- static int fluid_synth_set_preset (fluid_synth_t *synth, int chan,
- fluid_preset_t *preset);
- static fluid_preset_t*
- fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
- unsigned int banknum, unsigned int prognum);
- static fluid_preset_t*
- fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname,
- unsigned int banknum, unsigned int prognum);
- static void fluid_synth_update_presets(fluid_synth_t* synth);
- static int fluid_synth_update_gain(fluid_synth_t* synth,
- char* name, double value);
- static void fluid_synth_update_gain_LOCAL(fluid_synth_t* synth);
- static int fluid_synth_update_polyphony(fluid_synth_t* synth,
- char* name, int value);
- static int fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth);
- static void init_dither(void);
- static inline int roundi (float x);
- static int fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out);
- static void fluid_synth_core_thread_func (void* data);
- static FLUID_INLINE void fluid_synth_process_event_queue_LOCAL
- (fluid_synth_t *synth, fluid_event_queue_t *queue);
- static fluid_voice_t* fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth);
- static void fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t* synth,
- fluid_voice_t* new_voice);
- static fluid_sfont_info_t *new_fluid_sfont_info (fluid_synth_t *synth,
- fluid_sfont_t *sfont);
- static void fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont);
- static int fluid_synth_sfunload_callback(void* data, unsigned int msec);
- 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 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);
- fluid_sfloader_t* new_fluid_defsfloader(void);
- /***************************************************************
- *
- * GLOBAL
- */
- /* has the synth module been initialized? */
- static int fluid_synth_initialized = 0;
- static void fluid_synth_init(void);
- static void init_dither(void);
- /* default modulators
- * SF2.01 page 52 ff:
- *
- * There is a set of predefined default modulators. They have to be
- * explicitly overridden by the sound font in order to turn them off.
- */
- fluid_mod_t default_vel2att_mod; /* SF2.01 section 8.4.1 */
- fluid_mod_t default_vel2filter_mod; /* SF2.01 section 8.4.2 */
- fluid_mod_t default_at2viblfo_mod; /* SF2.01 section 8.4.3 */
- fluid_mod_t default_mod2viblfo_mod; /* SF2.01 section 8.4.4 */
- fluid_mod_t default_att_mod; /* SF2.01 section 8.4.5 */
- fluid_mod_t default_pan_mod; /* SF2.01 section 8.4.6 */
- fluid_mod_t default_expr_mod; /* SF2.01 section 8.4.7 */
- fluid_mod_t default_reverb_mod; /* SF2.01 section 8.4.8 */
- fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */
- fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */
- /* reverb presets */
- static fluid_revmodel_presets_t revmodel_preset[] = {
- /* name */ /* roomsize */ /* damp */ /* width */ /* level */
- { "Test 1", 0.2f, 0.0f, 0.5f, 0.9f },
- { "Test 2", 0.4f, 0.2f, 0.5f, 0.8f },
- { "Test 3", 0.6f, 0.4f, 0.5f, 0.7f },
- { "Test 4", 0.8f, 0.7f, 0.5f, 0.6f },
- { "Test 5", 0.8f, 1.0f, 0.5f, 0.5f },
- { NULL, 0.0f, 0.0f, 0.0f, 0.0f }
- };
- /***************************************************************
- *
- * INITIALIZATION & UTILITIES
- */
- void fluid_synth_settings(fluid_settings_t* settings)
- {
- fluid_settings_register_int(settings, "synth.verbose", 0, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.dump", 0, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.reverb.active", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.chorus.active", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.ladspa.active", 0, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_str(settings, "midi.portname", "", 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.polyphony",
- 256, 16, 4096, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.midi-channels",
- 16, 16, 256, 0, NULL, NULL);
- fluid_settings_register_num(settings, "synth.gain",
- 0.2f, 0.0f, 10.0f,
- 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.audio-channels",
- 1, 1, 128, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.audio-groups",
- 1, 1, 128, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.effects-channels",
- 2, 2, 2, 0, NULL, NULL);
- fluid_settings_register_num(settings, "synth.sample-rate",
- 44100.0f, 22050.0f, 96000.0f,
- 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.device-id",
- 0, 0, 126, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 256, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.min-note-length", 10, 0, 65535, 0, NULL, NULL);
- }
- /**
- * Get FluidSynth runtime version.
- * @param major Location to store major number
- * @param minor Location to store minor number
- * @param micro Location to store micro number
- */
- void fluid_version(int *major, int *minor, int *micro)
- {
- *major = FLUIDSYNTH_VERSION_MAJOR;
- *minor = FLUIDSYNTH_VERSION_MINOR;
- *micro = FLUIDSYNTH_VERSION_MICRO;
- }
- /**
- * Get FluidSynth runtime version as a string.
- * @return FluidSynth version string, which is internal and should not be
- * modified or freed.
- */
- char *
- fluid_version_str (void)
- {
- return FLUIDSYNTH_VERSION;
- }
- /*
- * void fluid_synth_init
- *
- * Does all the initialization for this module.
- */
- static void
- fluid_synth_init(void)
- {
- fluid_synth_initialized++;
- #ifdef TRAP_ON_FPE
- /* Turn on floating point exception traps */
- feenableexcept (FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID);
- #endif
- fluid_conversion_config();
- fluid_dsp_float_config();
- fluid_sys_config();
- init_dither();
- /* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
- fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */
- FLUID_MOD_VELOCITY, /* Source. VELOCITY corresponds to 'index=2'. */
- FLUID_MOD_GC /* Not a MIDI continuous controller */
- | FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */
- | FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */
- | FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */
- );
- fluid_mod_set_source2(&default_vel2att_mod, 0, 0); /* No 2nd source */
- fluid_mod_set_dest(&default_vel2att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
- fluid_mod_set_amount(&default_vel2att_mod, 960.0); /* Modulation amount: 960 */
- /* SF2.01 page 53 section 8.4.2: MIDI Note-On Velocity to Filter Cutoff
- * Have to make a design decision here. The specs don't make any sense this way or another.
- * One sound font, 'Kingston Piano', which has been praised for its quality, tries to
- * override this modulator with an amount of 0 and positive polarity (instead of what
- * the specs say, D=1) for the secondary source.
- * So if we change the polarity to 'positive', one of the best free sound fonts works...
- */
- fluid_mod_set_source1(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_NEGATIVE /* D=1 */
- );
- fluid_mod_set_source2(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_SWITCH /* type=3 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- // do not remove | FLUID_MOD_NEGATIVE /* D=1 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_dest(&default_vel2filter_mod, GEN_FILTERFC); /* Target: Initial filter cutoff */
- fluid_mod_set_amount(&default_vel2filter_mod, -2400);
- /* SF2.01 page 53 section 8.4.3: MIDI Channel pressure to Vibrato LFO pitch depth */
- fluid_mod_set_source1(&default_at2viblfo_mod, FLUID_MOD_CHANNELPRESSURE, /* Index=13 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_at2viblfo_mod, 0,0); /* no second source */
- fluid_mod_set_dest(&default_at2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
- fluid_mod_set_amount(&default_at2viblfo_mod, 50);
- /* SF2.01 page 53 section 8.4.4: Mod wheel (Controller 1) to Vibrato LFO pitch depth */
- fluid_mod_set_source1(&default_mod2viblfo_mod, 1, /* Index=1 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_mod2viblfo_mod, 0,0); /* no second source */
- fluid_mod_set_dest(&default_mod2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
- fluid_mod_set_amount(&default_mod2viblfo_mod, 50);
- /* SF2.01 page 55 section 8.4.5: MIDI continuous controller 7 to initial attenuation*/
- fluid_mod_set_source1(&default_att_mod, 7, /* index=7 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_CONCAVE /* type=1 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_NEGATIVE /* D=1 */
- );
- fluid_mod_set_source2(&default_att_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
- fluid_mod_set_amount(&default_att_mod, 960.0); /* Amount: 960 */
- /* SF2.01 page 55 section 8.4.6 MIDI continuous controller 10 to Pan Position */
- fluid_mod_set_source1(&default_pan_mod, 10, /* index=10 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_BIPOLAR /* P=1 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_pan_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_pan_mod, GEN_PAN); /* Target: pan */
- /* Amount: 500. The SF specs $8.4.6, p. 55 syas: "Amount = 1000
- tenths of a percent". The center value (64) corresponds to 50%,
- so it follows that amount = 50% x 1000/% = 500. */
- fluid_mod_set_amount(&default_pan_mod, 500.0);
- /* SF2.01 page 55 section 8.4.7: MIDI continuous controller 11 to initial attenuation*/
- fluid_mod_set_source1(&default_expr_mod, 11, /* index=11 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_CONCAVE /* type=1 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_NEGATIVE /* D=1 */
- );
- fluid_mod_set_source2(&default_expr_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_expr_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
- fluid_mod_set_amount(&default_expr_mod, 960.0); /* Amount: 960 */
- /* SF2.01 page 55 section 8.4.8: MIDI continuous controller 91 to Reverb send */
- fluid_mod_set_source1(&default_reverb_mod, 91, /* index=91 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_reverb_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_reverb_mod, GEN_REVERBSEND); /* Target: Reverb send */
- fluid_mod_set_amount(&default_reverb_mod, 200); /* Amount: 200 ('tenths of a percent') */
- /* SF2.01 page 55 section 8.4.9: MIDI continuous controller 93 to Chorus send */
- fluid_mod_set_source1(&default_chorus_mod, 93, /* index=93 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_chorus_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_chorus_mod, GEN_CHORUSSEND); /* Target: Chorus */
- fluid_mod_set_amount(&default_chorus_mod, 200); /* Amount: 200 ('tenths of a percent') */
- /* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */
- fluid_mod_set_source1(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEEL, /* Index=14 */
- FLUID_MOD_GC /* CC =0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_BIPOLAR /* P=1 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEELSENS, /* Index = 16 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_dest(&default_pitch_bend_mod, GEN_PITCH); /* Destination: Initial pitch */
- fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */
- }
- /***************************************************************
- * FLUID SAMPLE TIMERS
- * Timers that use written audio data as timing reference
- */
- struct _fluid_sample_timer_t
- {
- fluid_sample_timer_t* next; /* Single linked list of timers */
- unsigned long starttick;
- fluid_timer_callback_t callback;
- void* data;
- int isfinished;
- };
- /*
- * fluid_sample_timer_process - called when synth->ticks is updated
- */
- void fluid_sample_timer_process(fluid_synth_t* synth)
- {
- fluid_sample_timer_t* st;
- long msec;
- int cont;
- for (st=synth->sample_timers; st; st=st->next) {
- if (st->isfinished) {
- continue;
- }
- msec = (long) (1000.0*((double) (synth->ticks - st->starttick))/synth->sample_rate);
- cont = (*st->callback)(st->data, msec);
- if (cont == 0) {
- st->isfinished = 1;
- }
- }
- }
- fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data)
- {
- fluid_sample_timer_t* result = FLUID_NEW(fluid_sample_timer_t);
- if (result == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- result->starttick = synth->ticks;
- result->isfinished = 0;
- result->data = data;
- result->callback = callback;
- result->next = synth->sample_timers;
- synth->sample_timers = result;
- return result;
- }
- int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer)
- {
- fluid_sample_timer_t** ptr = &synth->sample_timers;
- while (*ptr) {
- if (*ptr == timer) {
- *ptr = timer->next;
- FLUID_FREE(timer);
- return FLUID_OK;
- }
- ptr = &((*ptr)->next);
- }
- FLUID_LOG(FLUID_ERR,"delete_fluid_sample_timer failed, no timer found");
- return FLUID_FAILED;
- }
- /***************************************************************
- *
- * FLUID SYNTH
- */
- /**
- * Create new FluidSynth instance.
- * @param settings Configuration parameters to use (used directly).
- * @return New FluidSynth instance or NULL on error
- *
- * NOTE: The settings parameter is used directly and should not be modified
- * or freed independently.
- */
- fluid_synth_t*
- new_fluid_synth(fluid_settings_t *settings)
- {
- fluid_synth_t* synth;
- fluid_sfloader_t* loader;
- double gain;
- int i;
- /* initialize all the conversion tables and other stuff */
- if (fluid_synth_initialized == 0) {
- fluid_synth_init();
- }
- /* allocate a new synthesizer object */
- synth = FLUID_NEW(fluid_synth_t);
- if (synth == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
- fluid_rec_mutex_init(synth->mutex);
- fluid_private_init(synth->thread_queues);
- synth->return_queue = fluid_event_queue_new (FLUID_MAX_RETURN_EVENTS);
- synth->return_queue_mutex = new_fluid_cond_mutex ();
- synth->return_queue_cond = new_fluid_cond ();
- if (synth->return_queue == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- synth->settings = settings;
- fluid_settings_getint(settings, "synth.reverb.active", &synth->with_reverb);
- fluid_settings_getint(settings, "synth.chorus.active", &synth->with_chorus);
- fluid_settings_getint(settings, "synth.verbose", &synth->verbose);
- fluid_settings_getint(settings, "synth.dump", &synth->dump);
- fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony);
- synth->shadow_polyphony = synth->polyphony;
- fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate);
- fluid_settings_getint(settings, "synth.midi-channels", &synth->midi_channels);
- fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels);
- fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
- fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
- fluid_settings_getnum(settings, "synth.gain", &gain);
- synth->gain = gain;
- fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
- fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
- fluid_settings_getint(settings, "synth.min-note-length", &i);
- synth->min_note_length_ticks = (unsigned int) (i*synth->sample_rate/1000.0f);
- /* register the callbacks */
- fluid_settings_register_num(settings, "synth.gain",
- 0.2f, 0.0f, 10.0f, 0,
- (fluid_num_update_t) fluid_synth_update_gain, synth);
- fluid_settings_register_int(settings, "synth.polyphony",
- synth->polyphony, 16, 4096, 0,
- (fluid_int_update_t) fluid_synth_update_polyphony,
- synth);
- fluid_settings_register_int(settings, "synth.device-id",
- synth->device_id, 126, 0, 0,
- (fluid_int_update_t) fluid_synth_update_device_id, synth);
- /* do some basic sanity checking on the settings */
- if (synth->midi_channels % 16 != 0) {
- int n = synth->midi_channels / 16;
- synth->midi_channels = (n + 1) * 16;
- fluid_settings_setint(settings, "synth.midi-channels", synth->midi_channels);
- FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is not a multiple of 16. "
- "I'll increase the number of channels to the next multiple.");
- }
- if (synth->audio_channels < 1) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio channels is smaller than 1. "
- "Changing this setting to 1.");
- synth->audio_channels = 1;
- } else if (synth->audio_channels > 128) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio channels is too big (%d). "
- "Limiting this setting to 128.", synth->audio_channels);
- synth->audio_channels = 128;
- }
- if (synth->audio_groups < 1) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio groups is smaller than 1. "
- "Changing this setting to 1.");
- synth->audio_groups = 1;
- } else if (synth->audio_groups > 128) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio groups is too big (%d). "
- "Limiting this setting to 128.", synth->audio_groups);
- synth->audio_groups = 128;
- }
- if (synth->effects_channels < 2) {
- FLUID_LOG(FLUID_WARN, "Invalid number of effects channels (%d)."
- "Setting effects channels to 2.", synth->effects_channels);
- synth->effects_channels = 2;
- }
- /* The number of buffers is determined by the higher number of nr
- * groups / nr audio channels. If LADSPA is unused, they should be
- * the same. */
- synth->nbuf = synth->audio_channels;
- if (synth->audio_groups > synth->nbuf) {
- synth->nbuf = synth->audio_groups;
- }
- #ifdef LADSPA
- /* Create and initialize the Fx unit.*/
- synth->LADSPA_FxUnit = new_fluid_LADSPA_FxUnit(synth);
- #endif
- /* as soon as the synth is created it starts playing. */
- synth->state = FLUID_SYNTH_PLAYING;
- synth->sfont_info = NULL;
- synth->sfont_hash = new_fluid_hashtable (NULL, NULL);
- 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();
- if (loader == NULL) {
- FLUID_LOG(FLUID_WARN, "Failed to create the default SoundFont loader");
- } else {
- fluid_synth_add_sfloader(synth, loader);
- }
- /* allocate all channel objects */
- synth->channel = FLUID_ARRAY(fluid_channel_t*, synth->midi_channels);
- if (synth->channel == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- for (i = 0; i < synth->midi_channels; i++) {
- synth->channel[i] = new_fluid_channel(synth, i);
- if (synth->channel[i] == NULL) {
- goto error_recovery;
- }
- }
- /* allocate all synthesis processes */
- synth->nvoice = synth->polyphony;
- synth->voice = FLUID_ARRAY(fluid_voice_t*, synth->nvoice);
- if (synth->voice == NULL) {
- goto error_recovery;
- }
- for (i = 0; i < synth->nvoice; i++) {
- synth->voice[i] = new_fluid_voice(synth->sample_rate);
- if (synth->voice[i] == NULL) {
- goto error_recovery;
- }
- }
- /* Allocate the sample buffers */
- synth->left_buf = NULL;
- synth->right_buf = NULL;
- synth->fx_left_buf = NULL;
- synth->fx_right_buf = NULL;
- /* Left and right audio buffers */
- synth->left_buf = FLUID_ARRAY(fluid_real_t*, synth->nbuf);
- synth->right_buf = FLUID_ARRAY(fluid_real_t*, synth->nbuf);
- if ((synth->left_buf == NULL) || (synth->right_buf == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- FLUID_MEMSET(synth->left_buf, 0, synth->nbuf * sizeof(fluid_real_t*));
- FLUID_MEMSET(synth->right_buf, 0, synth->nbuf * sizeof(fluid_real_t*));
- for (i = 0; i < synth->nbuf; i++) {
- synth->left_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
- synth->right_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
- if ((synth->left_buf[i] == NULL) || (synth->right_buf[i] == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- }
- /* Effects audio buffers */
- synth->fx_left_buf = FLUID_ARRAY(fluid_real_t*, synth->effects_channels);
- synth->fx_right_buf = FLUID_ARRAY(fluid_real_t*, synth->effects_channels);
- if ((synth->fx_left_buf == NULL) || (synth->fx_right_buf == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- FLUID_MEMSET(synth->fx_left_buf, 0, synth->effects_channels * sizeof(fluid_real_t*));
- FLUID_MEMSET(synth->fx_right_buf, 0, synth->effects_channels * sizeof(fluid_real_t*));
- for (i = 0; i < synth->effects_channels; i++) {
- synth->fx_left_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
- synth->fx_right_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
- if ((synth->fx_left_buf[i] == NULL) || (synth->fx_right_buf[i] == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- }
- synth->cur = FLUID_BUFSIZE;
- synth->dither_index = 0;
- /* allocate the reverb module */
- synth->reverb = new_fluid_revmodel();
- if (synth->reverb == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- synth->reverb_roomsize = FLUID_REVERB_DEFAULT_ROOMSIZE;
- synth->reverb_damping = FLUID_REVERB_DEFAULT_DAMP;
- synth->reverb_width = FLUID_REVERB_DEFAULT_WIDTH;
- synth->reverb_level = FLUID_REVERB_DEFAULT_LEVEL;
- fluid_revmodel_set (synth->reverb, FLUID_REVMODEL_SET_ALL,
- synth->reverb_roomsize, synth->reverb_damping,
- synth->reverb_width, synth->reverb_level);
- /* allocate the chorus module */
- synth->chorus = new_fluid_chorus(synth->sample_rate);
- if (synth->chorus == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- /* Initialize multi-core variables if multiple cores enabled */
- if (synth->cores > 1)
- {
- int prio_level = 0;
- synth->core_mutex = new_fluid_cond_mutex ();
- synth->core_cond = new_fluid_cond ();
- synth->core_wait_last_cond = new_fluid_cond ();
- synth->core_threads = FLUID_ARRAY (fluid_thread_t *, synth->cores - 1);
- synth->core_voice_processed = FLUID_ARRAY (fluid_voice_t *, synth->polyphony);
- synth->core_bufs = FLUID_MALLOC (synth->polyphony * FLUID_BUFSIZE * sizeof (fluid_real_t));
- if (!synth->core_mutex || !synth->core_cond || !synth->core_wait_last_cond
- || !synth->core_threads || !synth->core_voice_processed
- || !synth->core_bufs)
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- synth->cores_active = TRUE;
- synth->core_work = FALSE;
- synth->core_inprogress = 0;
- synth->core_waiting_for_last = FALSE;
- for (i = 0; i < synth->polyphony; i++)
- synth->core_voice_processed[i] = NULL;
- fluid_settings_getint (synth->settings, "audio.realtime-prio", &prio_level);
- for (i = 0; i < synth->cores - 1; i++)
- {
- synth->core_threads[i] = new_fluid_thread (fluid_synth_core_thread_func,
- synth, prio_level, FALSE);
- if (!synth->core_threads[i])
- FLUID_LOG(FLUID_ERR, "Failed to create a synthesis core thread");
- }
- }
- /* FIXME */
- synth->start = fluid_curtime();
- /* Spawn a thread to process synth thread return events */
- synth->return_queue_thread = new_fluid_thread (fluid_synth_return_event_process_thread,
- synth, 0, FALSE);
- return synth;
- error_recovery:
- delete_fluid_synth(synth);
- return NULL;
- }
- /* Callback to process synthesis thread return events */
- static void
- fluid_synth_return_event_process_thread (void* data)
- {
- fluid_synth_t *synth = data;
- fluid_event_queue_elem_t *event;
- fluid_preset_t *preset;
- fluid_sfont_t *sfont;
- /* Loop while synth is PLAYING */
- do
- { /* Block until we have some work to do or synth stops playing */
- fluid_cond_mutex_lock (synth->return_queue_mutex);
- while (!(event = fluid_event_queue_get_outptr (synth->return_queue))
- && fluid_atomic_int_get (&synth->state) == FLUID_SYNTH_PLAYING)
- fluid_cond_wait (synth->return_queue_cond, synth->return_queue_mutex);
- fluid_cond_mutex_unlock (synth->return_queue_mutex);
- if (!event) break; /* No event means synth stopped playing */
- /* Loop while there are return events */
- do
- {
- switch (event->type)
- {
- case FLUID_EVENT_QUEUE_ELEM_FREE_PRESET: /* Preset free event */
- preset = (fluid_preset_t *)(event->pval);
- sfont = preset->sfont;
- /* Delete presets under mutex lock, to protect chan->shadow_preset */
- fluid_rec_mutex_lock (synth->mutex);
- delete_fluid_preset (preset);
- fluid_rec_mutex_unlock (synth->mutex);
- fluid_synth_sfont_unref (synth, sfont); /* -- unref preset's SoundFont */
- break;
- }
- fluid_event_queue_next_outptr (synth->return_queue);
- }
- while ((event = fluid_event_queue_get_outptr (synth->return_queue)));
- }
- while (fluid_atomic_int_get (&synth->state) == FLUID_SYNTH_PLAYING);
- }
- /**
- * Delete a FluidSynth instance.
- * @param synth FluidSynth instance to delete
- * @return FLUID_OK
- *
- * NOTE: Other users of a synthesizer instance, such as audio and MIDI drivers,
- * should be deleted prior to freeing the FluidSynth instance.
- */
- int
- delete_fluid_synth(fluid_synth_t* synth)
- {
- int i, k;
- fluid_list_t *list;
- fluid_sfont_info_t* sfont_info;
- fluid_event_queue_t* queue;
- fluid_sfloader_t* loader;
- if (synth == NULL) {
- return FLUID_OK;
- }
- fluid_profiling_print();
- /* Stop return event queue thread, and process remaining events */
- if (synth->return_queue_thread)
- { /* Signal the return queue thread to cause it to exit */
- fluid_cond_mutex_lock (synth->return_queue_mutex);
- fluid_atomic_int_set (&synth->state, FLUID_SYNTH_STOPPED);
- fluid_cond_signal (synth->return_queue_cond);
- fluid_cond_mutex_unlock (synth->return_queue_mutex);
- fluid_thread_join (synth->return_queue_thread);
- delete_fluid_thread (synth->return_queue_thread);
- }
- else fluid_atomic_int_set (&synth->state, FLUID_SYNTH_STOPPED);
- if (synth->return_queue)
- fluid_event_queue_free(synth->return_queue);
- if (synth->return_queue_mutex)
- delete_fluid_cond_mutex (synth->return_queue_mutex);
- if (synth->return_queue_cond)
- delete_fluid_cond (synth->return_queue_cond);
- /* Free multi-core resources (if multi-core enabled) */
- if (synth->cores > 1)
- {
- /* Signal slave core threads to exit and wait for them to finish */
- fluid_cond_mutex_lock (synth->core_mutex); /* ++ Lock */
- synth->cores_active = FALSE;
- fluid_cond_broadcast (synth->core_cond);
- fluid_cond_mutex_unlock (synth->core_mutex); /* -- Unlock */
- for (i = 0; i < synth->cores - 1; i++)
- if (synth->core_threads[i])
- fluid_thread_join (synth->core_threads[i]);
- delete_fluid_cond_mutex (synth->core_mutex);
- delete_fluid_cond (synth->core_cond);
- delete_fluid_cond (synth->core_wait_last_cond);
- FLUID_FREE (synth->core_voice_processed);
- FLUID_FREE (synth->core_bufs);
- }
- /* turn off all voices, needed to unload SoundFont data */
- if (synth->voice != NULL) {
- for (i = 0; i < synth->nvoice; i++) {
- if (synth->voice[i] && fluid_voice_is_playing (synth->voice[i]))
- fluid_voice_off (synth->voice[i]);
- }
- }
- /* delete all the SoundFonts */
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
- delete_fluid_sfont (sfont_info->sfont);
- FLUID_FREE (sfont_info);
- }
- delete_fluid_list(synth->sfont_info);
- /* Delete the SoundFont info hash */
- if (synth->sfont_hash) delete_fluid_hashtable (synth->sfont_hash);
- /* delete all the SoundFont loaders */
- for (list = synth->loaders; list; list = fluid_list_next(list)) {
- loader = (fluid_sfloader_t*) fluid_list_get(list);
- fluid_sfloader_delete(loader);
- }
- delete_fluid_list(synth->loaders);
- if (synth->channel != NULL) {
- for (i = 0; i < synth->midi_channels; i++) {
- if (synth->channel[i] != NULL) {
- delete_fluid_channel(synth->channel[i]);
- }
- }
- FLUID_FREE(synth->channel);
- }
- if (synth->voice != NULL) {
- for (i = 0; i < synth->nvoice; i++) {
- if (synth->voice[i] != NULL) {
- delete_fluid_voice(synth->voice[i]);
- }
- }
- FLUID_FREE(synth->voice);
- }
- /* free all the sample buffers */
- if (synth->left_buf != NULL) {
- for (i = 0; i < synth->nbuf; i++) {
- if (synth->left_buf[i] != NULL) {
- FLUID_FREE(synth->left_buf[i]);
- }
- }
- FLUID_FREE(synth->left_buf);
- }
- if (synth->right_buf != NULL) {
- for (i = 0; i < synth->nbuf; i++) {
- if (synth->right_buf[i] != NULL) {
- FLUID_FREE(synth->right_buf[i]);
- }
- }
- FLUID_FREE(synth->right_buf);
- }
- if (synth->fx_left_buf != NULL) {
- for (i = 0; i < synth->effects_channels; i++) {
- if (synth->fx_left_buf[i] != NULL) {
- FLUID_FREE(synth->fx_left_buf[i]);
- }
- }
- FLUID_FREE(synth->fx_left_buf);
- }
- if (synth->fx_right_buf != NULL) {
- for (i = 0; i < synth->effects_channels; i++) {
- if (synth->fx_right_buf[i] != NULL) {
- FLUID_FREE(synth->fx_right_buf[i]);
- }
- }
- FLUID_FREE(synth->fx_right_buf);
- }
- /* release the reverb module */
- if (synth->reverb != NULL) {
- delete_fluid_revmodel(synth->reverb);
- }
- /* release the chorus module */
- if (synth->chorus != NULL) {
- delete_fluid_chorus(synth->chorus);
- }
- /* free the tunings, if any */
- if (synth->tuning != NULL) {
- for (i = 0; i < 128; i++) {
- if (synth->tuning[i] != NULL) {
- for (k = 0; k < 128; k++) {
- if (synth->tuning[i][k] != NULL) {
- delete_fluid_tuning(synth->tuning[i][k]);
- }
- }
- FLUID_FREE(synth->tuning[i]);
- }
- }
- FLUID_FREE(synth->tuning);
- }
- fluid_private_free (synth->tuning_iter);
- #ifdef LADSPA
- /* Release the LADSPA Fx unit */
- fluid_LADSPA_shutdown(synth->LADSPA_FxUnit);
- FLUID_FREE(synth->LADSPA_FxUnit);
- #endif
- fluid_private_free (synth->thread_queues);
- /* free any queues in pool */
- for (list = synth->queue_pool; list; list = list->next) {
- queue = (fluid_event_queue_t *)(list->data);
- /* Prevent double-free later */
- for (i = 0; i < FLUID_MAX_EVENT_QUEUES; i++)
- if (synth->queues[i] == queue) synth->queues[i] = NULL;
- fluid_event_queue_free (queue);
- }
- /* free remaining event queues, if any */
- 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_rec_mutex_destroy(synth->mutex);
- FLUID_FREE(synth);
- return FLUID_OK;
- }
- /**
- * Get a textual representation of the last error
- * @param synth FluidSynth instance
- * @return Pointer to string of last error message. Valid until the same
- * calling thread calls another FluidSynth function which fails. String is
- * internal and should not be modified or freed.
- */
- /* FIXME - The error messages are not thread-safe, yet. They are still stored
- * in a global message buffer (see fluid_sys.c). */
- char*
- fluid_synth_error(fluid_synth_t* synth)
- {
- return fluid_error();
- }
- /* Get event queue for the current thread (create if necessary) */
- static fluid_event_queue_t *
- fluid_synth_get_event_queue (fluid_synth_t* synth)
- {
- fluid_event_queue_t *queue;
- int i;
- queue = fluid_private_get (synth->thread_queues); /* Get event queue for this thread */
- if (!queue) /* This thread has no queue yet? */
- {
- fluid_rec_mutex_lock (synth->mutex); /* ++ lock queue_pool */
- /* Use an unclaimed queue, if any (it will already be in synth->queues[] in that case) */
- if (synth->queue_pool)
- {
- fluid_list_t *p;
- queue = synth->queue_pool->data;
- /* Remove from queue_pool list */
- p = synth->queue_pool;
- synth->queue_pool = fluid_list_remove_link (p, p);
- delete1_fluid_list (p);
- }
- fluid_rec_mutex_unlock (synth->mutex); /* -- unlock queue_pool */
- if (!queue) /* Create event queue, if one wasn't re-claimed */
- {
- queue = fluid_event_queue_new (FLUID_MAX_EVENTS_PER_BUFSIZE);
- if (!queue) return NULL; /* Error has already been logged */
- queue->synth = synth;
- /* Atomicly and in a lock free fashion, put queue pointer in queues[] array */
- for (i = 0; i < FLUID_MAX_EVENT_QUEUES; i++)
- {
- if (!fluid_atomic_pointer_get (&synth->queues[i]))
- {
- if (fluid_atomic_pointer_compare_and_exchange ((void **)&synth->queues[i],
- NULL, (void *)queue))
- break;
- }
- }
- if (i == FLUID_MAX_EVENT_QUEUES)
- {
- FLUID_LOG (FLUID_ERR, "Maximum thread event queues exceeded");
- return NULL;
- }
- }
- fluid_private_set (synth->thread_queues, queue, fluid_synth_thread_queue_destroy_notify);
- }
- 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
- * @param type MIDI event type (#fluid_midi_event_type)
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param param1 MIDI event first parameter (depends on type)
- * @param param2 MIDI event second parameter (depends on type)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- static int
- fluid_synth_queue_midi_event (fluid_synth_t* synth, int type, int chan,
- int param1, int param2)
- {
- fluid_event_queue_t *queue;
- fluid_event_queue_elem_t *event;
- event = fluid_synth_get_event_elem (synth, &queue);
- if (!event) return FLUID_FAILED;
- event->type = FLUID_EVENT_QUEUE_ELEM_MIDI;
- event->midi.type = type;
- event->midi.channel = chan;
- event->midi.param1 = param1;
- event->midi.param2 = param2;
- fluid_event_queue_next_inptr (queue);
- return FLUID_OK;
- }
- /**
- * Queues a generator assignment event to the FluidSynth synthesis thread.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param param Generator ID (#fluid_gen_type)
- * @param value Value to assign to generator
- * @param absolute TRUE if value is an absolute assignment, FALSE for relative
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- static int
- fluid_synth_queue_gen_event (fluid_synth_t* synth, int chan,
- int param, float value, int absolute)
- {
- fluid_event_queue_t *queue;
- fluid_event_queue_elem_t *event;
- event = fluid_synth_get_event_elem (synth, &queue);
- if (!event) return FLUID_FAILED;
- event->type = FLUID_EVENT_QUEUE_ELEM_GEN;
- event->gen.channel = chan;
- event->gen.param = param;
- event->gen.value = value;
- event->gen.absolute = absolute;
- fluid_event_queue_next_inptr (queue);
- return FLUID_OK;
- }
- /**
- * Queues an event with an integer value payload.
- * @param synth FluidSynth instance
- * @param type Event type (#fluid_event_queue_elem)
- * @param val Event value
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- static int
- fluid_synth_queue_int_event (fluid_synth_t* synth, int type, int val)
- {
- fluid_event_queue_t *queue;
- fluid_event_queue_elem_t *event;
- event = fluid_synth_get_event_elem (synth, &queue);
- if (!event) return FLUID_FAILED;
- event->type = type;
- event->ival = val;
- fluid_event_queue_next_inptr (queue);
- return FLUID_OK;
- }
- /* Gets called when a thread ends, which has been assigned a queue */
- static void
- fluid_synth_thread_queue_destroy_notify (void *data)
- {
- fluid_event_queue_t *queue = data;
- fluid_synth_t *synth = queue->synth;
- /* Queues are not freed (can't be thread safe without locking in synth thread),
- * added to pool for potential future use */
- fluid_rec_mutex_lock (synth->mutex); /* ++ lock queue_pool */
- synth->queue_pool = fluid_list_prepend (synth->queue_pool, queue);
- fluid_rec_mutex_unlock (synth->mutex); /* -- unlock queue_pool */
- }
- /**
- * Send a note-on event to a FluidSynth object.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param key MIDI note number (0-127)
- * @param vel MIDI velocity (0-127, 0=noteoff)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
- {
- 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 (key >= 0 && key <= 127, FLUID_FAILED);
- fluid_return_val_if_fail (vel >= 0 && vel <= 127, FLUID_FAILED);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, NOTE_ON, chan, key, vel);
- else return fluid_synth_noteon_LOCAL (synth, chan, key, vel);
- }
- /* Local synthesis thread variant of fluid_synth_noteon */
- static int
- fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key, int vel)
- {
- fluid_channel_t* channel;
- /* notes with velocity zero go to noteoff */
- if (vel == 0) return fluid_synth_noteoff_LOCAL(synth, chan, key);
- channel = synth->channel[chan];
- /* make sure this channel has a preset */
- if (channel->preset == NULL) {
- if (synth->verbose) {
- FLUID_LOG(FLUID_INFO, "noteont%dt%dt%dt%05dt%.3ft%.3ft%.3ft%dt%s",
- chan, key, vel, 0,
- (float) synth->ticks / 44100.0f,
- (fluid_curtime() - synth->start) / 1000.0f,
- 0.0f, 0, "channel has no preset");
- }
- return FLUID_FAILED;
- }
- /* If there is another voice process on the same channel and key,
- advance it to the release phase. */
- fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, key);
- synth->storeid = synth->noteid++;
- return fluid_preset_noteon(channel->preset, synth, chan, key, vel);
- }
- /**
- * Send a note-off event to a FluidSynth object.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param key MIDI note number (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise (may just mean that no
- * voices matched the note off event)
- */
- int
- fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
- {
- 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 (key >= 0 && key <= 127, FLUID_FAILED);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, NOTE_OFF, chan, key, 0);
- else return fluid_synth_noteoff_LOCAL (synth, chan, key);
- }
- /* Local synthesis thread variant of fluid_synth_noteoff */
- static int
- fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key)
- {
- fluid_voice_t* voice;
- int status = FLUID_FAILED;
- int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (_ON(voice) && (voice->chan == chan) && (voice->key == key)) {
- if (synth->verbose) {
- int used_voices = 0;
- int k;
- for (k = 0; k < synth->polyphony; k++) {
- if (!_AVAILABLE(synth->voice[k])) {
- used_voices++;
- }
- }
- FLUID_LOG(FLUID_INFO, "noteofft%dt%dt%dt%05dt%.3ft%.3ft%.3ft%d",
- voice->chan, voice->key, 0, voice->id,
- (float) (voice->start_time + voice->ticks) / 44100.0f,
- (fluid_curtime() - synth->start) / 1000.0f,
- (float) voice->ticks / 44100.0f,
- used_voices);
- } /* if verbose */
- fluid_voice_noteoff(voice);
- status = FLUID_OK;
- } /* if voice on */
- } /* for all voices */
- return status;
- }
- /* Damp all voices on a channel (turn notes off) */
- static int
- fluid_synth_damp_voices_LOCAL(fluid_synth_t* synth, int chan)
- {
- fluid_voice_t* voice;
- int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if ((voice->chan == chan) && _SUSTAINED(voice))
- fluid_voice_noteoff(voice);
- }
- return FLUID_OK;
- }
- /**
- * Send a MIDI controller event on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param num MIDI controller number (0-127)
- * @param val MIDI controller value (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
- {
- fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- fluid_return_val_if_fail (num >= 0 && num <= 127, FLUID_FAILED);
- fluid_return_val_if_fail (val >= 0 && val <= 127, FLUID_FAILED);
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "cct%dt%dt%d", chan, num, val);
- fluid_channel_set_cc (synth->channel[chan], num, val);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, CONTROL_CHANGE, chan, num, 0);
- else fluid_synth_cc_LOCAL (synth, chan, num);
- return FLUID_OK;
- }
- /* Local synthesis thread variant of MIDI CC set function. */
- static int
- fluid_synth_cc_LOCAL (fluid_synth_t* synth, int channum, int num)
- {
- fluid_channel_t* chan = synth->channel[channum];
- int nrpn_select;
- int value;
- value = fluid_channel_get_cc (chan, num);
- switch (num) {
- case SUSTAIN_SWITCH:
- if (value < 64) fluid_synth_damp_voices_LOCAL (synth, channum);
- break;
- case BANK_SELECT_MSB:
- fluid_channel_set_bank_msb (chan, value & 0x7F);
- break;
- case BANK_SELECT_LSB:
- fluid_channel_set_bank_lsb (chan, value & 0x7F);
- break;
- case ALL_NOTES_OFF:
- fluid_synth_all_notes_off_LOCAL (synth, channum);
- break;
- case ALL_SOUND_OFF:
- fluid_synth_all_sounds_off_LOCAL (synth, channum);
- break;
- case ALL_CTRL_OFF:
- fluid_channel_init_ctrl (chan, 1);
- fluid_synth_modulate_voices_all_LOCAL (synth, channum);
- break;
- case DATA_ENTRY_MSB:
- {
- int data = (value << 7) + fluid_channel_get_cc (chan, DATA_ENTRY_LSB);
- if (fluid_atomic_int_get (&chan->nrpn_active)) /* NRPN is active? */
- { /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
- if ((fluid_channel_get_cc (chan, NRPN_MSB) == 120)
- && (fluid_channel_get_cc (chan, NRPN_LSB) < 100))
- {
- nrpn_select = fluid_atomic_int_get (&chan->nrpn_select);
- if (nrpn_select < GEN_LAST)
- {
- float val = fluid_gen_scale_nrpn (nrpn_select, data);
- fluid_synth_set_gen_LOCAL (synth, channum, nrpn_select, val, FALSE);
- }
- fluid_atomic_int_set (&chan->nrpn_select, 0); /* Reset to 0 */
- }
- }
- else if (fluid_channel_get_cc (chan, RPN_MSB) == 0) /* RPN is active: MSB = 0? */
- {
- switch (fluid_channel_get_cc (chan, RPN_LSB))
- {
- case RPN_PITCH_BEND_RANGE: /* Set bend range in semitones */
- fluid_channel_set_pitch_wheel_sensitivity (synth->channel[channum], value);
- fluid_synth_update_pitch_wheel_sens_LOCAL (synth, channum); /* Update bend range */
- /* FIXME - Handle LSB? (Fine bend range in cents) */
- break;
- case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over 1 semitone (+/- 50 cents, 8192 = center) */
- fluid_synth_set_gen_LOCAL (synth, channum, GEN_FINETUNE,
- (data - 8192) / 8192.0 * 50.0, FALSE);
- break;
- case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */
- fluid_synth_set_gen_LOCAL (synth, channum, GEN_COARSETUNE,
- value - 64, FALSE);
- break;
- case RPN_TUNING_PROGRAM_CHANGE:
- fluid_channel_set_tuning_prog (chan, value);
- fluid_synth_activate_tuning (synth, channum,
- fluid_channel_get_tuning_bank (chan),
- value, TRUE);
- break;
- case RPN_TUNING_BANK_SELECT:
- fluid_channel_set_tuning_bank (chan, value);
- break;
- case RPN_MODULATION_DEPTH_RANGE:
- break;
- }
- }
- break;
- }
- case NRPN_MSB:
- fluid_channel_set_cc (chan, NRPN_LSB, 0);
- fluid_atomic_int_set (&chan->nrpn_select, 0);
- fluid_atomic_int_set (&chan->nrpn_active, 1);
- break;
- case NRPN_LSB:
- /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
- if (fluid_channel_get_cc (chan, NRPN_MSB) == 120) {
- if (value == 100) {
- fluid_atomic_int_add (&chan->nrpn_select, 100);
- } else if (value == 101) {
- fluid_atomic_int_add (&chan->nrpn_select, 1000);
- } else if (value == 102) {
- fluid_atomic_int_add (&chan->nrpn_select, 10000);
- } else if (value < 100) {
- fluid_atomic_int_add (&chan->nrpn_select, value);
- }
- }
- fluid_atomic_int_set (&chan->nrpn_active, 1);
- break;
- case RPN_MSB:
- case RPN_LSB:
- fluid_atomic_int_set (&chan->nrpn_active, 0);
- break;
- default:
- return fluid_synth_modulate_voices_LOCAL (synth, channum, 1, num);
- }
- return FLUID_OK;
- }
- /**
- * Get current MIDI controller value on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param num MIDI controller number (0-127)
- * @param pval Location to store MIDI controller value (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_get_cc(fluid_synth_t* synth, int chan, int num, int* pval)
- {
- 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 (num >= 0 && num < 128, FLUID_FAILED);
- fluid_return_val_if_fail (pval != NULL, FLUID_FAILED);
- *pval = fluid_channel_get_cc (synth->channel[chan], num);
- return FLUID_OK;
- }
- /*
- * Handler for synth.device-id setting.
- */
- static int
- fluid_synth_update_device_id (fluid_synth_t *synth, char *name, int value)
- {
- fluid_atomic_int_set (&synth->device_id, value);
- return 0;
- }
- /**
- * Process a MIDI SYSEX (system exclusive) message.
- * @param synth FluidSynth instance
- * @param data Buffer containing SYSEX data (not including 0xF0 and 0xF7)
- * @param len Length of data in buffer
- * @param response Buffer to store response to or NULL to ignore
- * @param response_len IN/OUT parameter, in: size of response buffer, out:
- * amount of data written to response buffer (if FLUID_FAILED is returned and
- * this value is non-zero, it indicates the response buffer is too small)
- * @param handled Optional location to store boolean value if message was
- * recognized and handled or not (set to TRUE if it was handled)
- * @param dryrun TRUE to just do a dry run but not actually execute the SYSEX
- * command (useful for checking if a SYSEX message would be handled)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- * @since 1.1.0
- */
- /* SYSEX format (0xF0 and 0xF7 not passed to this function):
- * Non-realtime: 0xF0 0x7E <DeviceId> [BODY] 0xF7
- * Realtime: 0xF0 0x7F <DeviceId> [BODY] 0xF7
- * Tuning messages: 0xF0 0x7E/0x7F <DeviceId> 0x08 <sub ID2> [BODY] <ChkSum> 0xF7
- */
- int
- fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
- char *response, int *response_len, int *handled, int dryrun)
- {
- int avail_response = 0;
- if (handled) *handled = FALSE;
- if (response_len)
- {
- avail_response = *response_len;
- *response_len = 0;
- }
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (data != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (len > 0, FLUID_FAILED);
- fluid_return_val_if_fail (!response || response_len, FLUID_FAILED);
- if (len < 4) return FLUID_OK;
- /* MIDI tuning SYSEX message? */
- if ((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME)
- && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL)
- && data[2] == MIDI_SYSEX_MIDI_TUNING_ID)
- return fluid_synth_sysex_midi_tuning (synth, data, len, response, response_len,
- avail_response, handled, dryrun);
- return FLUID_OK;
- }
- /* Handler for MIDI tuning SYSEX messages */
- static int
- fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, const char *data, int len,
- char *response, int *response_len, int avail_response,
- int *handled, int dryrun)
- {
- int realtime, msgid;
- int bank = 0, prog, channels;
- double tunedata[128];
- int keys[128];
- char name[17];
- int note, frac, frac2;
- uint8 chksum;
- int i, count, index;
- const char *dataptr;
- char *resptr;;
- realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME;
- msgid = data[3];
- switch (msgid)
- {
- case MIDI_SYSEX_TUNING_BULK_DUMP_REQ:
- case MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK:
- if (data[3] == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
- {
- if (len != 5 || data[4] & 0x80 || !response)
- return FLUID_OK;
- *response_len = 406;
- prog = data[4];
- }
- else
- {
- if (len != 6 || data[4] & 0x80 || data[5] & 0x80 || !response)
- return FLUID_OK;
- *response_len = 407;
- bank = data[4];
- prog = data[5];
- }
- if (dryrun)
- {
- if (handled) *handled = TRUE;
- return FLUID_OK;
- }
- if (avail_response < *response_len) return FLUID_FAILED;
- /* Get tuning data, return if tuning not found */
- if (fluid_synth_tuning_dump (synth, bank, prog, name, 17, tunedata) == FLUID_FAILED)
- {
- *response_len = 0;
- return FLUID_OK;
- }
- resptr = response;
- *resptr++ = MIDI_SYSEX_UNIV_NON_REALTIME;
- *resptr++ = synth->device_id;
- *resptr++ = MIDI_SYSEX_MIDI_TUNING_ID;
- *resptr++ = MIDI_SYSEX_TUNING_BULK_DUMP;
- if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK)
- *resptr++ = bank;
- *resptr++ = prog;
- FLUID_STRNCPY (resptr, name, 16);
- resptr += 16;
- for (i = 0; i < 128; i++)
- {
- note = tunedata[i] / 100.0;
- fluid_clip (note, 0, 127);
- frac = ((tunedata[i] - note * 100.0) * 16384.0 + 50.0) / 100.0;
- fluid_clip (frac, 0, 16383);
- *resptr++ = note;
- *resptr++ = frac >> 7;
- *resptr++ = frac & 0x7F;
- }
- if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
- { /* NOTE: Checksum is not as straight forward as the bank based messages */
- chksum = MIDI_SYSEX_UNIV_NON_REALTIME ^ MIDI_SYSEX_MIDI_TUNING_ID
- ^ MIDI_SYSEX_TUNING_BULK_DUMP ^ prog;
- for (i = 21; i < 128 * 3 + 21; i++)
- chksum ^= response[i];
- }
- else
- {
- for (i = 1, chksum = 0; i < 406; i++)
- chksum ^= response[i];
- }
- *resptr++ = chksum & 0x7F;
- if (handled) *handled = TRUE;
- break;
- case MIDI_SYSEX_TUNING_NOTE_TUNE:
- case MIDI_SYSEX_TUNING_NOTE_TUNE_BANK:
- dataptr = data + 4;
- if (msgid == MIDI_SYSEX_TUNING_NOTE_TUNE)
- {
- if (len < 10 || data[4] & 0x80 || data[5] & 0x80 || len != data[5] * 4 + 6)
- return FLUID_OK;
- }
- else
- {
- if (len < 11 || data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80
- || len != data[5] * 4 + 7)
- return FLUID_OK;
- bank = *dataptr++;
- }
- if (dryrun)
- {
- if (handled) *handled = TRUE;
- return FLUID_OK;
- }
- prog = *dataptr++;
- count = *dataptr++;
- for (i = 0, index = 0; i < count; i++)
- {
- note = *dataptr++;
- if (note & 0x80) return FLUID_OK;
- keys[index] = note;
- note = *dataptr++;
- frac = *dataptr++;
- frac2 = *dataptr++;
- if (note & 0x80 || frac & 0x80 || frac2 & 0x80)
- return FLUID_OK;
- frac = frac << 7 | frac2;
- /* No change pitch value? Doesn't really make sense to send that, but.. */
- if (note == 0x7F && frac == 16383) continue;
- tunedata[index] = note * 100.0 + (frac * 100.0 / 16384.0);
- index++;
- }
- if (index > 0)
- {
- if (fluid_synth_tune_notes (synth, bank, prog, index, keys, tunedata,
- realtime) == FLUID_FAILED)
- return FLUID_FAILED;
- }
- if (handled) *handled = TRUE;
- break;
- case MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE:
- case MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE:
- if ((msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE && len != 19)
- || (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE && len != 31))
- return FLUID_OK;
- if (data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80)
- return FLUID_OK;
- if (dryrun)
- {
- if (handled) *handled = TRUE;
- return FLUID_OK;
- }
- channels = (data[4] & 0x03) << 14 | data[5] << 7 | data[6];
- if (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE)
- {
- for (i = 0; i < 12; i++)
- {
- frac = data[i + 7];
- if (frac & 0x80) return FLUID_OK;
- tunedata[i] = (int)frac - 64;
- }
- }
- else
- {
- for (i = 0; i < 12; i++)
- {
- frac = data[i * 2 + 7];
- frac2 = data[i * 2 + 8];
- if (frac & 0x80 || frac2 & 0x80) return FLUID_OK;
- tunedata[i] = (((int)frac << 7 | (int)frac2) - 8192) * (200.0 / 16384.0);
- }
- }
- if (fluid_synth_activate_octave_tuning (synth, 0, 0, "SYSEX",
- tunedata, realtime) == FLUID_FAILED)
- return FLUID_FAILED;
- if (channels)
- {
- for (i = 0; i < 16; i++)
- {
- if (channels & (1 << i))
- fluid_synth_activate_tuning (synth, i, 0, 0, realtime);
- }
- }
- if (handled) *handled = TRUE;
- break;
- }
- return FLUID_OK;
- }
- /**
- * Turn off all notes on a MIDI channel (put them into release phase).
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_all_notes_off(fluid_synth_t* synth, int chan)
- {
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, CONTROL_CHANGE, chan,
- ALL_NOTES_OFF, 0);
- else return fluid_synth_all_notes_off_LOCAL (synth, chan);
- }
- /* Local synthesis thread variant of all notes off */
- static int
- fluid_synth_all_notes_off_LOCAL(fluid_synth_t* synth, int chan)
- {
- fluid_voice_t* voice;
- int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (_PLAYING(voice) && (voice->chan == chan))
- fluid_voice_noteoff(voice);
- }
- return FLUID_OK;
- }
- /**
- * Immediately stop all notes on a MIDI channel (skips release phase).
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan)
- {
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, CONTROL_CHANGE, chan,
- ALL_SOUND_OFF, 0);
- else return fluid_synth_all_sounds_off_LOCAL (synth, chan);
- }
- /* Local synthesis thread variant of all sounds off */
- static int
- fluid_synth_all_sounds_off_LOCAL(fluid_synth_t* synth, int chan)
- {
- fluid_voice_t* voice;
- int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (_PLAYING(voice) && (voice->chan == chan))
- fluid_voice_off(voice);
- }
- return FLUID_OK;
- }
- /**
- * Send MIDI system reset command (big red 'panic' button), turns off notes and
- * resets controllers.
- * @param synth FluidSynth instance
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_system_reset(fluid_synth_t* synth)
- {
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, MIDI_SYSTEM_RESET, 0, 0, 0);
- else return fluid_synth_system_reset_LOCAL (synth);
- }
- /* Local variant of the system reset command */
- static int
- fluid_synth_system_reset_LOCAL(fluid_synth_t* synth)
- {
- fluid_voice_t* voice;
- int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (_PLAYING(voice))
- fluid_voice_off(voice);
- }
- for (i = 0; i < synth->midi_channels; i++)
- fluid_channel_reset(synth->channel[i]);
- fluid_chorus_reset(synth->chorus);
- fluid_revmodel_reset(synth->reverb);
- return FLUID_OK;
- }
- /**
- * Update voices on a MIDI channel after a MIDI control change.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param is_cc Boolean value indicating if ctrl is a CC controller or not
- * @param ctrl MIDI controller value
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- static int
- fluid_synth_modulate_voices_LOCAL(fluid_synth_t* synth, int chan, int is_cc, int ctrl)
- {
- fluid_voice_t* voice;
- int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (voice->chan == chan)
- fluid_voice_modulate(voice, is_cc, ctrl);
- }
- return FLUID_OK;
- }
- /**
- * Update voices on a MIDI channel after all MIDI controllers have been changed.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- static int
- fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan)
- {
- fluid_voice_t* voice;
- int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (voice->chan == chan)
- fluid_voice_modulate_all(voice);
- }
- return FLUID_OK;
- }
- /**
- * Set the MIDI channel pressure controller value.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param val MIDI channel pressure value (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val)
- {
- 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 (val >= 0 && val <= 127, FLUID_FAILED);
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "channelpressuret%dt%d", chan, val);
- fluid_channel_set_channel_pressure (synth->channel[chan], val);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, CHANNEL_PRESSURE, chan, 0, 0);
- else return fluid_synth_update_channel_pressure_LOCAL (synth, chan);
- }
- /* Updates channel pressure from within synthesis thread */
- static int
- fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int chan)
- {
- return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_CHANNELPRESSURE);
- }
- /**
- * Set the MIDI pitch bend controller value on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param val MIDI pitch bend value (0-16383 with 8192 being center)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
- {
- 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 (val >= 0 && val <= 16383, FLUID_FAILED);
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "pitchbt%dt%d", chan, val);
- fluid_channel_set_pitch_bend (synth->channel[chan], val);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, PITCH_BEND, chan, 0, 0);
- else return fluid_synth_update_pitch_bend_LOCAL (synth, chan);
- }
- /* Local synthesis thread variant of pitch bend */
- static int
- fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan)
- {
- return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_PITCHWHEEL);
- }
- /**
- * Get the MIDI pitch bend controller value on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param ppitch_bend Location to store MIDI pitch bend value (0-16383 with
- * 8192 being center)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend)
- {
- 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 (ppitch_bend != NULL, FLUID_FAILED);
- *ppitch_bend = fluid_channel_get_pitch_bend (synth->channel[chan]);
- return FLUID_OK;
- }
- /**
- * Set MIDI pitch wheel sensitivity on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param val Pitch wheel sensitivity value in semitones
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val)
- {
- 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 (val >= 0 && val <= 72, FLUID_FAILED); /* 6 octaves!? Better than no limit.. */
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "pitchsenst%dt%d", chan, val);
- fluid_channel_set_pitch_wheel_sensitivity (synth->channel[chan], val);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_midi_event (synth, RPN_LSB, chan,
- RPN_PITCH_BEND_RANGE, val);
- else return fluid_synth_update_pitch_wheel_sens_LOCAL (synth, chan);
- }
- /* Local synthesis thread variant of set pitch wheel sensitivity */
- static int
- fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan)
- {
- return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_PITCHWHEELSENS);
- }
- /**
- * Get MIDI pitch wheel sensitivity on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param pval Location to store pitch wheel sensitivity value in semitones
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- * @since Sometime AFTER v1.0 API freeze.
- */
- int
- fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval)
- {
- 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 (pval != NULL, FLUID_FAILED);
- *pval = fluid_channel_get_pitch_wheel_sensitivity (synth->channel[chan]);
- return FLUID_OK;
- }
- /**
- * Assign a preset to a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param preset Preset to assign to channel or NULL to clear (ownership is taken over)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- static int
- fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset)
- {
- fluid_event_queue_t *queue;
- fluid_event_queue_elem_t *event;
- fluid_channel_t *channel;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- channel = synth->channel[chan];
- if (fluid_synth_should_queue (synth))
- {
- event = fluid_synth_get_event_elem (synth, &queue);
- if (!event) return FLUID_FAILED;
- fluid_atomic_pointer_set (&channel->shadow_preset, preset);
- event->type = FLUID_EVENT_QUEUE_ELEM_PRESET;
- event->preset.channel = chan;
- event->preset.preset = preset;
- fluid_event_queue_next_inptr (queue);
- return FLUID_OK;
- }
- else return fluid_channel_set_preset (channel, preset);
- }
- /* Get a preset by SoundFont, bank and program numbers.
- * Returns preset pointer or NULL.
- *
- * NOTE: The returned preset has been allocated, caller owns it and should
- * free it when finished using it.
- */
- static fluid_preset_t*
- fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
- unsigned int banknum, unsigned int prognum)
- {
- fluid_preset_t *preset = NULL;
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
- /* 128 indicates an "unset" operation" */
- if (prognum == FLUID_UNSET_PROGRAM) return NULL;
- fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
- if (fluid_sfont_get_id (sfont_info->sfont) == sfontnum)
- {
- preset = fluid_sfont_get_preset (sfont_info->sfont,
- banknum - sfont_info->bankofs, prognum);
- if (preset) sfont_info->refcount++; /* Add reference to SoundFont */
- break;
- }
- }
- fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
- return preset;
- }
- /* Get a preset by SoundFont name, bank and program.
- * Returns preset pointer or NULL.
- *
- * NOTE: The returned preset has been allocated, caller owns it and should
- * free it when finished using it.
- */
- static fluid_preset_t*
- fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname,
- unsigned int banknum, unsigned int prognum)
- {
- fluid_preset_t *preset = NULL;
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
- fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
- if (FLUID_STRCMP (fluid_sfont_get_name (sfont_info->sfont), sfontname) == 0)
- {
- preset = fluid_sfont_get_preset (sfont_info->sfont,
- banknum - sfont_info->bankofs, prognum);
- if (preset) sfont_info->refcount++; /* Add reference to SoundFont */
- break;
- }
- }
- fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
- return preset;
- }
- /* Find a preset by bank and program numbers.
- * Returns preset pointer or NULL.
- *
- * NOTE: The returned preset has been allocated, caller owns it and should
- * free it when finished using it. */
- fluid_preset_t*
- fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
- unsigned int prognum)
- {
- fluid_preset_t *preset = NULL;
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
- fluid_rec_mutex_lock (synth->mutex); /* ++ lock sfont list, bank offset list and sfont */
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
- preset = fluid_sfont_get_preset (sfont_info->sfont,
- banknum - sfont_info->bankofs, prognum);
- if (preset)
- {
- sfont_info->refcount++; /* Add reference to SoundFont */
- break;
- }
- }
- fluid_rec_mutex_unlock (synth->mutex); /* -- unlock */
- return preset;
- }
- /**
- * Send a program change event on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param prognum MIDI program number (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- /* FIXME - Currently not real-time safe, due to preset allocation and mutex lock,
- * and may be called from within synthesis context. */
- /* As of 1.1.1 prognum can be set to 128 to unset the preset. Not documented
- * since fluid_synth_unset_program() should be used instead. */
- int
- fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
- {
- fluid_preset_t* preset = NULL;
- fluid_channel_t* channel;
- int subst_bank, subst_prog, banknum;
- 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 (prognum >= 0 && prognum <= 128, FLUID_FAILED);
- channel = synth->channel[chan];
- fluid_channel_get_sfont_bank_prog(channel, NULL, &banknum, NULL);
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "progt%dt%dt%d", chan, banknum, prognum);
- /* Special handling of channel 10 (or 9 counting from 0). channel
- * 10 is the percussion channel.
- *
- * FIXME - Shouldn't hard code bank selection for channel 10. I think this
- * is a hack for MIDI files that do bank changes in GM mode. Proper way to
- * handle this would probably be to ignore bank changes when in GM mode. - JG
- */
- if (prognum != FLUID_UNSET_PROGRAM)
- {
- if (channel->channum == 9)
- preset = fluid_synth_find_preset(synth, DRUM_INST_BANK, prognum);
- else preset = fluid_synth_find_preset(synth, banknum, prognum);
- /* Fallback to another preset if not found */
- if (!preset)
- {
- subst_bank = banknum;
- subst_prog = prognum;
- /* Melodic instrument? */
- if (channel->channum != 9 && banknum != DRUM_INST_BANK)
- {
- subst_bank = 0;
- /* Fallback first to bank 0:prognum */
- preset = fluid_synth_find_preset(synth, 0, prognum);
- /* Fallback to first preset in bank 0 */
- if (!preset && prognum != 0)
- {
- preset = fluid_synth_find_preset(synth, 0, 0);
- subst_prog = 0;
- }
- }
- else /* Percussion: Fallback to preset 0 in percussion bank */
- {
- preset = fluid_synth_find_preset(synth, DRUM_INST_BANK, 0);
- subst_prog = 0;
- }
- if (preset)
- FLUID_LOG(FLUID_WARN, "Instrument not found on channel %d [bank=%d prog=%d], substituted [bank=%d prog=%d]",
- chan, banknum, prognum, subst_bank, subst_prog);
- }
- }
- /* Assign the SoundFont ID and program number to the channel */
- fluid_channel_set_sfont_bank_prog (channel, preset ? fluid_sfont_get_id (preset->sfont) : 0,
- -1, prognum);
- return fluid_synth_set_preset (synth, chan, preset);
- }
- /**
- * Set instrument bank number on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param bank MIDI bank number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank)
- {
- 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 <= 16383, FLUID_FAILED);
- fluid_channel_set_sfont_bank_prog (synth->channel[chan], -1, bank, -1);
- return FLUID_OK;
- }
- /**
- * Set SoundFont ID on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param sfont_id ID of a loaded SoundFont
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id)
- {
- 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_sfont_bank_prog(synth->channel[chan], sfont_id, -1, -1);
- return FLUID_OK;
- }
- /**
- * Set the preset of a MIDI channel to an unassigned state.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @return #FLUID_OK on success, #FLUID_FAILED otherwise
- * @since 1.1.1
- *
- * Note: Channel retains its SoundFont ID and bank numbers, while the program
- * number is set to an "unset" state. MIDI program changes may re-assign a
- * preset if one matches.
- */
- int
- fluid_synth_unset_program (fluid_synth_t *synth, int chan)
- {
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- return fluid_synth_program_change (synth, chan, FLUID_UNSET_PROGRAM);
- }
- /**
- * Get current SoundFont ID, bank number and program number for a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param sfont_id Location to store SoundFont ID
- * @param bank_num Location to store MIDI bank number
- * @param preset_num Location to store MIDI program number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_get_program(fluid_synth_t* synth, int chan, unsigned int* sfont_id,
- unsigned int* bank_num, unsigned int* preset_num)
- {
- fluid_channel_t* channel;
- 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 (sfont_id != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (bank_num != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (preset_num != NULL, FLUID_FAILED);
- channel = synth->channel[chan];
- fluid_channel_get_sfont_bank_prog(channel, (int *)sfont_id, (int *)bank_num,
- (int *)preset_num);
- /* 128 indicates that the preset is unset. Set to 0 to be backwards compatible. */
- if (*preset_num == FLUID_UNSET_PROGRAM) *preset_num = 0;
- return FLUID_OK;
- }
- /**
- * Select an instrument on a MIDI channel by SoundFont ID, bank and program numbers.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param sfont_id ID of a loaded SoundFont
- * @param bank_num MIDI bank number
- * @param preset_num MIDI program number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- */
- int
- fluid_synth_program_select(fluid_synth_t* synth, int chan, unsigned int sfont_id,
- unsigned int bank_num, unsigned int preset_num)
- {
- fluid_preset_t* preset = NULL;
- fluid_channel_t* channel;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- channel = synth->channel[chan];
- /* ++ Allocate preset */
- preset = fluid_synth_get_preset (synth, sfont_id, bank_num, preset_num);
- if (preset == NULL) {
- FLUID_LOG(FLUID_ERR,
- "There is no preset with bank number %d and preset number %d in SoundFont %d",
- bank_num, preset_num, sfont_id);
- return FLUID_FAILED;
- }
- /* Assign the new SoundFont ID, bank and program number to the channel */
- fluid_channel_set_sfont_bank_prog (channel, sfont_id, bank_num, preset_num);
- return fluid_synth_set_preset (synth, chan, preset);
- }
- /**
- * Select an instrument on a MIDI channel by SoundFont name, bank and program numbers.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param sfont_name Name of a loaded SoundFont
- * @param bank_num MIDI bank number
- * @param preset_num MIDI program number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- * @since 1.1.0
- */
- int
- fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
- const char *sfont_name, unsigned int bank_num,
- unsigned int preset_num)
- {
- fluid_preset_t* preset = NULL;
- fluid_channel_t* channel;
- 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 (sfont_name != NULL, FLUID_FAILED);
- channel = synth->channel[chan];
- /* ++ Allocate preset */
- preset = fluid_synth_get_preset_by_sfont_name (synth, sfont_name, bank_num,
- preset_num);
- if (preset == NULL) {
- FLUID_LOG(FLUID_ERR,
- "There is no preset with bank number %d and preset number %d in SoundFont %s",
- bank_num, preset_num, sfont_name);
- return FLUID_FAILED;
- }
- /* Assign the new SoundFont ID, bank and program number to the channel */
- fluid_channel_set_sfont_bank_prog (channel, fluid_sfont_get_id (preset->sfont),
- bank_num, preset_num);
- return fluid_synth_set_preset (synth, chan, preset);
- }
- /*
- * This function assures that every MIDI channel has a valid preset
- * (NULL is okay). This function is called after a SoundFont is
- * unloaded or reloaded.
- */
- static void
- fluid_synth_update_presets(fluid_synth_t* synth)
- {
- fluid_channel_t *channel;
- fluid_preset_t *preset;
- int sfont, bank, prog;
- int chan;
- for (chan = 0; chan < synth->midi_channels; chan++) {
- channel = synth->channel[chan];
- fluid_channel_get_sfont_bank_prog (channel, &sfont, &bank, &prog);
- preset = fluid_synth_get_preset (synth, sfont, bank, prog);
- fluid_synth_set_preset (synth, chan, preset);
- }
- }
- /* Handler for synth.gain setting. */
- static int
- fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value)
- {
- fluid_synth_set_gain(synth, (float) value);
- return 0;
- }
- /**
- * Set synth output gain value.
- * @param synth FluidSynth instance
- * @param gain Gain value (function clamps value to the range 0.0 to 10.0)
- */
- void
- fluid_synth_set_gain(fluid_synth_t* synth, float gain)
- {
- fluid_return_if_fail (synth != NULL);
- fluid_clip (gain, 0.0f, 10.0f);
- fluid_atomic_float_set (&synth->gain, gain);
- if (fluid_synth_should_queue (synth))
- fluid_synth_queue_int_event (synth, FLUID_EVENT_QUEUE_ELEM_UPDATE_GAIN, 0); /* Integer value not actually used */
- else fluid_synth_update_gain_LOCAL (synth);
- }
- /* Called by synthesis thread to update the gain in all voices */
- static void
- fluid_synth_update_gain_LOCAL(fluid_synth_t* synth)
- {
- fluid_voice_t *voice;
- float gain;
- int i;
- gain = fluid_atomic_float_get (&synth->gain);
- for (i = 0; i < synth->polyphony; i++)
- {
- voice = synth->voice[i];
- if (_PLAYING (voice)) fluid_voice_set_gain (voice, gain);
- }
- }
- /**
- * Get synth output gain value.
- * @param synth FluidSynth instance
- * @return Synth gain value (0.0 to 10.0)
- */
- float
- fluid_synth_get_gain(fluid_synth_t* synth)
- {
- fluid_return_val_if_fail (synth != NULL, 0.0);
- return fluid_atomic_float_get (&synth->gain);
- }
- /*
- * Handler for synth.polyphony setting.
- */
- static int
- fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value)
- {
- fluid_synth_set_polyphony(synth, value);
- return 0;
- }
- /**
- * Set synthesizer polyphony (max number of voices).
- * @param synth FluidSynth instance
- * @param polyphony Polyphony to assign
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- * @since 1.0.6
- */
- int
- fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony)
- {
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (polyphony >= 16 && polyphony <= synth->nvoice, FLUID_FAILED);
- fluid_atomic_int_set (&synth->shadow_polyphony, polyphony);
- if (fluid_synth_should_queue (synth))
- return fluid_synth_queue_int_event (synth, FLUID_EVENT_QUEUE_ELEM_POLYPHONY, 0);
- else return fluid_synth_update_polyphony_LOCAL (synth);
- }
- /* Called by synthesis thread to update the polyphony value */
- static int
- fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth)
- {
- fluid_voice_t *voice;
- int i;
- synth->polyphony = fluid_atomic_int_get (&synth->shadow_polyphony);
- /* turn off any voices above the new limit */
- for (i = synth->polyphony; i < synth->nvoice; i++)
- {
- voice = synth->voice[i];
- if (_PLAYING (voice)) fluid_voice_off (voice);
- }
- return FLUID_OK;
- }
- /**
- * Get current synthesizer polyphony (max number of voices).
- * @param synth FluidSynth instance
- * @return Synth polyphony value.
- * @since 1.0.6
- */
- int
- fluid_synth_get_polyphony(fluid_synth_t* synth)
- {
- return fluid_atomic_int_get (&synth->shadow_polyphony);
- }
- /**
- * Get current number of active voices.
- * @param synth FluidSynth instance
- * @return Number of currently active voices.
- * @since 1.1.0
- *
- * Note: To generate accurate continuous statistics of the voice count, caller
- * should ensure this function is called synchronously with the audio synthesis
- * process. This can be done in the new_fluid_audio_driver2() audio callback
- * function for example.
- */
- int
- fluid_synth_get_active_voice_count(fluid_synth_t* synth)
- {
- return fluid_atomic_int_get (&synth->active_voice_count);
- }
- /**
- * Get the internal synthesis buffer size value.
- * @param synth FluidSynth instance
- * @return Internal buffer size in audio frames.
- *
- * Audio is synthesized this number of frames at a time. Defaults to 64 frames.
- */
- int
- fluid_synth_get_internal_bufsize(fluid_synth_t* synth)
- {
- return FLUID_BUFSIZE;
- }
- /**
- * Resend a bank select and a program change for every channel.
- * @param synth FluidSynth instance
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- *
- * This function is called mainly after a SoundFont has been loaded,
- * unloaded or reloaded.
- */
- int
- fluid_synth_program_reset(fluid_synth_t* synth)
- {
- int i, prog;
- /* try to set the correct presets */
- for (i = 0; i < synth->midi_channels; i++){
- fluid_channel_get_sfont_bank_prog (synth->channel[i], NULL, NULL, &prog);
- fluid_synth_program_change(synth, i, prog);
- }
- return FLUID_OK;
- }
- /**
- * Synthesize a block of floating point audio to audio buffers.
- * @param synth FluidSynth instance
- * @param len Count of audio frames to synthesize
- * @param left Array of floats to store left channel of audio (len in size)
- * @param right Array of floats to store right channel of audio (len in size)
- * @param fx_left Not currently used
- * @param fx_right Not currently used
- * @return FLUID_OK on success, FLUID_FAIL otherwise
- *
- * NOTE: Should only be called from synthesis thread.
- */
- int
- fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
- float** left, float** right,
- float** fx_left, float** fx_right)
- {
- fluid_real_t** left_in = synth->left_buf;
- fluid_real_t** right_in = synth->right_buf;
- double time = fluid_utime();
- int i, num, available, count, bytes;
- float cpu_load;
- /* First, take what's still available in the buffer */
- count = 0;
- num = synth->cur;
- if (synth->cur < FLUID_BUFSIZE) {
- available = FLUID_BUFSIZE - synth->cur;
- num = (available > len)? len : available;
- bytes = num * sizeof(float);
- for (i = 0; i < synth->audio_channels; i++) {
- FLUID_MEMCPY(left[i], left_in[i] + synth->cur, bytes);
- FLUID_MEMCPY(right[i], right_in[i] + synth->cur, bytes);
- }
- count += num;
- num += synth->cur; /* if we're now done, num becomes the new synth->cur below */
- }
- /* Then, run one_block() and copy till we have 'len' samples */
- while (count < len) {
- fluid_synth_one_block(synth, 1);
- num = (FLUID_BUFSIZE > len - count)? len - count : FLUID_BUFSIZE;
- bytes = num * sizeof(float);
- for (i = 0; i < synth->audio_channels; i++) {
- FLUID_MEMCPY(left[i] + count, left_in[i], bytes);
- FLUID_MEMCPY(right[i] + count, right_in[i], bytes);
- }
- count += num;
- }
- synth->cur = num;
- time = fluid_utime() - time;
- 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;
- }
- /**
- * Synthesize floating point audio to audio buffers.
- * @param synth FluidSynth instance
- * @param len Count of audio frames to synthesize
- * @param nin Ignored
- * @param in Ignored
- * @param nout Count of arrays in 'out'
- * @param out Array of arrays to store audio to
- * @return FLUID_OK on success, FLUID_FAIL otherwise
- *
- * This function implements the default interface defined in fluidsynth/audio.h.
- * NOTE: Should only be called from synthesis thread.
- */
- /*
- * FIXME: Currently if nout != 2 memory allocation will occur!
- */
- int
- fluid_synth_process(fluid_synth_t* synth, int len, int nin, float** in,
- int nout, float** out)
- {
- if (nout==2) {
- return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1);
- }
- else {
- float **left, **right;
- int i;
- left = FLUID_ARRAY(float*, nout/2);
- right = FLUID_ARRAY(float*, nout/2);
- for(i=0; i<nout/2; i++) {
- left[i] = out[2*i];
- right[i] = out[2*i+1];
- }
- fluid_synth_nwrite_float(synth, len, left, right, NULL, NULL);
- FLUID_FREE(left);
- FLUID_FREE(right);
- return FLUID_OK;
- }
- }
- /**
- * Synthesize a block of floating point audio samples to audio buffers.
- * @param synth FluidSynth instance
- * @param len Count of audio frames to synthesize
- * @param lout Array of floats to store left channel of audio
- * @param loff Offset index in 'lout' for first sample
- * @param lincr Increment between samples stored to 'lout'
- * @param rout Array of floats to store right channel of audio
- * @param roff Offset index in 'rout' for first sample
- * @param rincr Increment between samples stored to 'rout'
- * @return FLUID_OK on success, FLUID_FAIL otherwise
- *
- * Useful for storing interleaved stereo (lout = rout, loff = 0, roff = 1,
- * lincr = 2, rincr = 2).
- *
- * NOTE: Should only be called from synthesis thread.
- */
- int
- fluid_synth_write_float(fluid_synth_t* synth, int len,
- void* lout, int loff, int lincr,
- void* rout, int roff, int rincr)
- {
- int i, j, k, l;
- float* left_out = (float*) lout;
- float* right_out = (float*) rout;
- fluid_real_t* left_in = synth->left_buf[0];
- fluid_real_t* right_in = synth->right_buf[0];
- double time = fluid_utime();
- float cpu_load;
- l = synth->cur;
- for (i = 0, j = loff, k = roff; i < len; i++, l++, j += lincr, k += rincr) {
- /* fill up the buffers as needed */
- if (l == FLUID_BUFSIZE) {
- fluid_synth_one_block(synth, 0);
- l = 0;
- }
- left_out[j] = (float) left_in[l];
- right_out[k] = (float) right_in[l];
- }
- synth->cur = l;
- time = fluid_utime() - time;
- 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;
- }
- #define DITHER_SIZE 48000
- #define DITHER_CHANNELS 2
- static float rand_table[DITHER_CHANNELS][DITHER_SIZE];