1 /* FluidSynth - A Software Synthesizer
3 * Copyright (C) 2003 Peter Hanappe and others.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public License
7 * as published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #include "fluid_synth.h"
24 #include "fluid_sys.h"
25 #include "fluid_chan.h"
26 #include "fluid_tuning.h"
27 #include "fluid_settings.h"
28 #include "fluid_sfont.h"
29 #include "fluid_hash.h"
30 #include "fluid_defsfont.h"
36 /* seems to not be declared in fenv.h */
37 extern int feenableexcept (int excepts);
40 static void fluid_synth_init(void);
42 static int fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key,
44 static int fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key);
45 static int fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num);
46 static int fluid_synth_update_device_id (fluid_synth_t *synth, char *name,
48 static int fluid_synth_update_overflow (fluid_synth_t *synth, char *name,
50 static int fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, const char *data,
51 int len, char *response,
52 int *response_len, int avail_response,
53 int *handled, int dryrun);
54 static int fluid_synth_all_notes_off_LOCAL(fluid_synth_t* synth, int chan);
55 static int fluid_synth_all_sounds_off_LOCAL(fluid_synth_t* synth, int chan);
56 static int fluid_synth_system_reset_LOCAL(fluid_synth_t* synth);
57 static int fluid_synth_modulate_voices_LOCAL(fluid_synth_t* synth, int chan,
59 static int fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan);
60 static int fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int channum);
61 static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan);
62 static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan);
63 static int fluid_synth_set_preset (fluid_synth_t *synth, int chan,
64 fluid_preset_t *preset);
65 static fluid_preset_t*
66 fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
67 unsigned int banknum, unsigned int prognum);
68 static fluid_preset_t*
69 fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname,
70 unsigned int banknum, unsigned int prognum);
72 static void fluid_synth_update_presets(fluid_synth_t* synth);
73 static int fluid_synth_update_sample_rate(fluid_synth_t* synth,
74 char* name, double value);
75 static int fluid_synth_update_gain(fluid_synth_t* synth,
76 char* name, double value);
77 static void fluid_synth_update_gain_LOCAL(fluid_synth_t* synth);
78 static int fluid_synth_update_polyphony(fluid_synth_t* synth,
79 char* name, int value);
80 static int fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth, int new_polyphony);
81 static void init_dither(void);
82 static inline int roundi (float x);
83 static int fluid_synth_render_blocks(fluid_synth_t* synth, int blockcount);
84 //static void fluid_synth_core_thread_func (void* data);
85 //static FLUID_INLINE void fluid_synth_process_event_queue_LOCAL
86 // (fluid_synth_t *synth, fluid_event_queue_t *queue);
87 static fluid_voice_t* fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth);
88 static void fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t* synth,
89 fluid_voice_t* new_voice);
90 static fluid_sfont_info_t *new_fluid_sfont_info (fluid_synth_t *synth,
91 fluid_sfont_t *sfont);
92 static int fluid_synth_sfunload_callback(void* data, unsigned int msec);
93 static void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth,
95 static fluid_tuning_t* fluid_synth_get_tuning(fluid_synth_t* synth,
97 static int fluid_synth_replace_tuning_LOCK (fluid_synth_t* synth,
98 fluid_tuning_t *tuning,
99 int bank, int prog, int apply);
100 static void fluid_synth_replace_tuning_LOCAL (fluid_synth_t *synth,
101 fluid_tuning_t *old_tuning,
102 fluid_tuning_t *new_tuning,
103 int apply, int unref_new);
104 static void fluid_synth_update_voice_tuning_LOCAL (fluid_synth_t *synth,
105 fluid_channel_t *channel);
106 static int fluid_synth_set_tuning_LOCAL (fluid_synth_t *synth, int chan,
107 fluid_tuning_t *tuning, int apply);
108 static void fluid_synth_set_gen_LOCAL (fluid_synth_t* synth, int chan,
109 int param, float value, int absolute);
110 static void fluid_synth_stop_LOCAL (fluid_synth_t *synth, unsigned int id);
114 /***************************************************************
119 /* has the synth module been initialized? */
120 static int fluid_synth_initialized = 0;
121 static void fluid_synth_init(void);
122 static void init_dither(void);
124 /* default modulators
127 * There is a set of predefined default modulators. They have to be
128 * explicitly overridden by the sound font in order to turn them off.
131 fluid_mod_t default_vel2att_mod; /* SF2.01 section 8.4.1 */
132 fluid_mod_t default_vel2filter_mod; /* SF2.01 section 8.4.2 */
133 fluid_mod_t default_at2viblfo_mod; /* SF2.01 section 8.4.3 */
134 fluid_mod_t default_mod2viblfo_mod; /* SF2.01 section 8.4.4 */
135 fluid_mod_t default_att_mod; /* SF2.01 section 8.4.5 */
136 fluid_mod_t default_pan_mod; /* SF2.01 section 8.4.6 */
137 fluid_mod_t default_expr_mod; /* SF2.01 section 8.4.7 */
138 fluid_mod_t default_reverb_mod; /* SF2.01 section 8.4.8 */
139 fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */
140 fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */
143 static fluid_revmodel_presets_t revmodel_preset[] = {
144 /* name */ /* roomsize */ /* damp */ /* width */ /* level */
145 { "Test 1", 0.2f, 0.0f, 0.5f, 0.9f },
146 { "Test 2", 0.4f, 0.2f, 0.5f, 0.8f },
147 { "Test 3", 0.6f, 0.4f, 0.5f, 0.7f },
148 { "Test 4", 0.8f, 0.7f, 0.5f, 0.6f },
149 { "Test 5", 0.8f, 1.0f, 0.5f, 0.5f },
150 { NULL, 0.0f, 0.0f, 0.0f, 0.0f }
154 /***************************************************************
156 * INITIALIZATION & UTILITIES
159 static void fluid_synth_register_overflow(fluid_settings_t* settings,
160 fluid_num_update_t update_func,
163 fluid_settings_register_num(settings, "synth.overflow.percussion",
164 4000, -10000, 10000, 0, update_func, update_data);
165 fluid_settings_register_num(settings, "synth.overflow.sustained",
166 -1000, -10000, 10000, 0, update_func, update_data);
167 fluid_settings_register_num(settings, "synth.overflow.released",
168 -2000, -10000, 10000, 0, update_func, update_data);
169 fluid_settings_register_num(settings, "synth.overflow.age",
170 1000, -10000, 10000, 0, update_func, update_data);
171 fluid_settings_register_num(settings, "synth.overflow.volume",
172 500, -10000, 10000, 0, update_func, update_data);
175 void fluid_synth_settings(fluid_settings_t* settings)
177 fluid_settings_register_int(settings, "synth.verbose", 0, 0, 1,
178 FLUID_HINT_TOGGLED, NULL, NULL);
179 fluid_settings_register_int(settings, "synth.dump", 0, 0, 1,
180 FLUID_HINT_TOGGLED, NULL, NULL);
181 fluid_settings_register_int(settings, "synth.reverb.active", 1, 0, 1,
182 FLUID_HINT_TOGGLED, NULL, NULL);
183 fluid_settings_register_int(settings, "synth.chorus.active", 1, 0, 1,
184 FLUID_HINT_TOGGLED, NULL, NULL);
185 fluid_settings_register_int(settings, "synth.ladspa.active", 0, 0, 1,
186 FLUID_HINT_TOGGLED, NULL, NULL);
187 fluid_settings_register_int(settings, "synth.lock-memory", 1, 0, 1,
188 FLUID_HINT_TOGGLED, NULL, NULL);
189 fluid_settings_register_str(settings, "midi.portname", "", 0, NULL, NULL);
191 fluid_settings_register_str(settings, "synth.default-soundfont",
192 DEFAULT_SOUNDFONT, 0, NULL, NULL);
194 fluid_settings_register_int(settings, "synth.polyphony",
195 256, 1, 65535, 0, NULL, NULL);
196 fluid_settings_register_int(settings, "synth.midi-channels",
197 16, 16, 256, 0, NULL, NULL);
198 fluid_settings_register_num(settings, "synth.gain",
201 fluid_settings_register_int(settings, "synth.audio-channels",
202 1, 1, 128, 0, NULL, NULL);
203 fluid_settings_register_int(settings, "synth.audio-groups",
204 1, 1, 128, 0, NULL, NULL);
205 fluid_settings_register_int(settings, "synth.effects-channels",
206 2, 2, 2, 0, NULL, NULL);
207 fluid_settings_register_num(settings, "synth.sample-rate",
208 44100.0f, 8000.0f, 96000.0f,
210 fluid_settings_register_int(settings, "synth.device-id",
211 0, 0, 126, 0, NULL, NULL);
212 fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 256, 0, NULL, NULL);
214 fluid_settings_register_int(settings, "synth.min-note-length", 10, 0, 65535, 0, NULL, NULL);
216 fluid_settings_register_int(settings, "synth.threadsafe-api", 1, 0, 1,
217 FLUID_HINT_TOGGLED, NULL, NULL);
218 fluid_settings_register_int(settings, "synth.parallel-render", 1, 0, 1,
219 FLUID_HINT_TOGGLED, NULL, NULL);
221 fluid_synth_register_overflow(settings, NULL, NULL);
223 fluid_settings_register_str(settings, "synth.midi-bank-select", "gs", 0, NULL, NULL);
224 fluid_settings_add_option(settings, "synth.midi-bank-select", "gm");
225 fluid_settings_add_option(settings, "synth.midi-bank-select", "gs");
226 fluid_settings_add_option(settings, "synth.midi-bank-select", "xg");
227 fluid_settings_add_option(settings, "synth.midi-bank-select", "mma");
232 * Get FluidSynth runtime version.
233 * @param major Location to store major number
234 * @param minor Location to store minor number
235 * @param micro Location to store micro number
237 void fluid_version(int *major, int *minor, int *micro)
239 *major = FLUIDSYNTH_VERSION_MAJOR;
240 *minor = FLUIDSYNTH_VERSION_MINOR;
241 *micro = FLUIDSYNTH_VERSION_MICRO;
245 * Get FluidSynth runtime version as a string.
246 * @return FluidSynth version string, which is internal and should not be
250 fluid_version_str (void)
252 return FLUIDSYNTH_VERSION;
255 #define FLUID_API_ENTRY_CHAN(fail_value) \
256 fluid_return_val_if_fail (synth != NULL, fail_value); \
257 fluid_return_val_if_fail (chan >= 0, fail_value); \
258 fluid_synth_api_enter(synth); \
259 if (chan >= synth->midi_channels) { \
260 fluid_synth_api_exit(synth); \
264 #define FLUID_API_RETURN(return_value) \
265 do { fluid_synth_api_exit(synth); \
266 return return_value; } while (0)
269 * void fluid_synth_init
271 * Does all the initialization for this module.
274 fluid_synth_init(void)
276 fluid_synth_initialized++;
279 /* Turn on floating point exception traps */
280 feenableexcept (FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID);
283 fluid_conversion_config();
285 fluid_rvoice_dsp_config();
292 /* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
293 fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */
294 FLUID_MOD_VELOCITY, /* Source. VELOCITY corresponds to 'index=2'. */
295 FLUID_MOD_GC /* Not a MIDI continuous controller */
296 | FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */
297 | FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */
298 | FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */
300 fluid_mod_set_source2(&default_vel2att_mod, 0, 0); /* No 2nd source */
301 fluid_mod_set_dest(&default_vel2att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
302 fluid_mod_set_amount(&default_vel2att_mod, 960.0); /* Modulation amount: 960 */
306 /* SF2.01 page 53 section 8.4.2: MIDI Note-On Velocity to Filter Cutoff
307 * Have to make a design decision here. The specs don't make any sense this way or another.
308 * One sound font, 'Kingston Piano', which has been praised for its quality, tries to
309 * override this modulator with an amount of 0 and positive polarity (instead of what
310 * the specs say, D=1) for the secondary source.
311 * So if we change the polarity to 'positive', one of the best free sound fonts works...
313 fluid_mod_set_source1(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
314 FLUID_MOD_GC /* CC=0 */
315 | FLUID_MOD_LINEAR /* type=0 */
316 | FLUID_MOD_UNIPOLAR /* P=0 */
317 | FLUID_MOD_NEGATIVE /* D=1 */
319 fluid_mod_set_source2(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
320 FLUID_MOD_GC /* CC=0 */
321 | FLUID_MOD_SWITCH /* type=3 */
322 | FLUID_MOD_UNIPOLAR /* P=0 */
323 // do not remove | FLUID_MOD_NEGATIVE /* D=1 */
324 | FLUID_MOD_POSITIVE /* D=0 */
326 fluid_mod_set_dest(&default_vel2filter_mod, GEN_FILTERFC); /* Target: Initial filter cutoff */
327 fluid_mod_set_amount(&default_vel2filter_mod, -2400);
331 /* SF2.01 page 53 section 8.4.3: MIDI Channel pressure to Vibrato LFO pitch depth */
332 fluid_mod_set_source1(&default_at2viblfo_mod, FLUID_MOD_CHANNELPRESSURE, /* Index=13 */
333 FLUID_MOD_GC /* CC=0 */
334 | FLUID_MOD_LINEAR /* type=0 */
335 | FLUID_MOD_UNIPOLAR /* P=0 */
336 | FLUID_MOD_POSITIVE /* D=0 */
338 fluid_mod_set_source2(&default_at2viblfo_mod, 0,0); /* no second source */
339 fluid_mod_set_dest(&default_at2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
340 fluid_mod_set_amount(&default_at2viblfo_mod, 50);
344 /* SF2.01 page 53 section 8.4.4: Mod wheel (Controller 1) to Vibrato LFO pitch depth */
345 fluid_mod_set_source1(&default_mod2viblfo_mod, 1, /* Index=1 */
346 FLUID_MOD_CC /* CC=1 */
347 | FLUID_MOD_LINEAR /* type=0 */
348 | FLUID_MOD_UNIPOLAR /* P=0 */
349 | FLUID_MOD_POSITIVE /* D=0 */
351 fluid_mod_set_source2(&default_mod2viblfo_mod, 0,0); /* no second source */
352 fluid_mod_set_dest(&default_mod2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
353 fluid_mod_set_amount(&default_mod2viblfo_mod, 50);
357 /* SF2.01 page 55 section 8.4.5: MIDI continuous controller 7 to initial attenuation*/
358 fluid_mod_set_source1(&default_att_mod, 7, /* index=7 */
359 FLUID_MOD_CC /* CC=1 */
360 | FLUID_MOD_CONCAVE /* type=1 */
361 | FLUID_MOD_UNIPOLAR /* P=0 */
362 | FLUID_MOD_NEGATIVE /* D=1 */
364 fluid_mod_set_source2(&default_att_mod, 0, 0); /* No second source */
365 fluid_mod_set_dest(&default_att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
366 fluid_mod_set_amount(&default_att_mod, 960.0); /* Amount: 960 */
370 /* SF2.01 page 55 section 8.4.6 MIDI continuous controller 10 to Pan Position */
371 fluid_mod_set_source1(&default_pan_mod, 10, /* index=10 */
372 FLUID_MOD_CC /* CC=1 */
373 | FLUID_MOD_LINEAR /* type=0 */
374 | FLUID_MOD_BIPOLAR /* P=1 */
375 | FLUID_MOD_POSITIVE /* D=0 */
377 fluid_mod_set_source2(&default_pan_mod, 0, 0); /* No second source */
378 fluid_mod_set_dest(&default_pan_mod, GEN_PAN); /* Target: pan */
379 /* Amount: 500. The SF specs $8.4.6, p. 55 syas: "Amount = 1000
380 tenths of a percent". The center value (64) corresponds to 50%,
381 so it follows that amount = 50% x 1000/% = 500. */
382 fluid_mod_set_amount(&default_pan_mod, 500.0);
385 /* SF2.01 page 55 section 8.4.7: MIDI continuous controller 11 to initial attenuation*/
386 fluid_mod_set_source1(&default_expr_mod, 11, /* index=11 */
387 FLUID_MOD_CC /* CC=1 */
388 | FLUID_MOD_CONCAVE /* type=1 */
389 | FLUID_MOD_UNIPOLAR /* P=0 */
390 | FLUID_MOD_NEGATIVE /* D=1 */
392 fluid_mod_set_source2(&default_expr_mod, 0, 0); /* No second source */
393 fluid_mod_set_dest(&default_expr_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
394 fluid_mod_set_amount(&default_expr_mod, 960.0); /* Amount: 960 */
398 /* SF2.01 page 55 section 8.4.8: MIDI continuous controller 91 to Reverb send */
399 fluid_mod_set_source1(&default_reverb_mod, 91, /* index=91 */
400 FLUID_MOD_CC /* CC=1 */
401 | FLUID_MOD_LINEAR /* type=0 */
402 | FLUID_MOD_UNIPOLAR /* P=0 */
403 | FLUID_MOD_POSITIVE /* D=0 */
405 fluid_mod_set_source2(&default_reverb_mod, 0, 0); /* No second source */
406 fluid_mod_set_dest(&default_reverb_mod, GEN_REVERBSEND); /* Target: Reverb send */
407 fluid_mod_set_amount(&default_reverb_mod, 200); /* Amount: 200 ('tenths of a percent') */
411 /* SF2.01 page 55 section 8.4.9: MIDI continuous controller 93 to Chorus send */
412 fluid_mod_set_source1(&default_chorus_mod, 93, /* index=93 */
413 FLUID_MOD_CC /* CC=1 */
414 | FLUID_MOD_LINEAR /* type=0 */
415 | FLUID_MOD_UNIPOLAR /* P=0 */
416 | FLUID_MOD_POSITIVE /* D=0 */
418 fluid_mod_set_source2(&default_chorus_mod, 0, 0); /* No second source */
419 fluid_mod_set_dest(&default_chorus_mod, GEN_CHORUSSEND); /* Target: Chorus */
420 fluid_mod_set_amount(&default_chorus_mod, 200); /* Amount: 200 ('tenths of a percent') */
424 /* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */
425 fluid_mod_set_source1(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEEL, /* Index=14 */
426 FLUID_MOD_GC /* CC =0 */
427 | FLUID_MOD_LINEAR /* type=0 */
428 | FLUID_MOD_BIPOLAR /* P=1 */
429 | FLUID_MOD_POSITIVE /* D=0 */
431 fluid_mod_set_source2(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEELSENS, /* Index = 16 */
432 FLUID_MOD_GC /* CC=0 */
433 | FLUID_MOD_LINEAR /* type=0 */
434 | FLUID_MOD_UNIPOLAR /* P=0 */
435 | FLUID_MOD_POSITIVE /* D=0 */
437 fluid_mod_set_dest(&default_pitch_bend_mod, GEN_PITCH); /* Destination: Initial pitch */
438 fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */
441 static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t* synth)
443 if (synth->eventhandler->is_threadsafe)
444 return fluid_atomic_int_get(&synth->ticks_since_start);
446 return synth->ticks_since_start;
449 static FLUID_INLINE void fluid_synth_add_ticks(fluid_synth_t* synth, int val)
451 if (synth->eventhandler->is_threadsafe)
452 fluid_atomic_int_add((int*) &synth->ticks_since_start, val);
454 synth->ticks_since_start += val;
458 /***************************************************************
459 * FLUID SAMPLE TIMERS
460 * Timers that use written audio data as timing reference
462 struct _fluid_sample_timer_t
464 fluid_sample_timer_t* next; /* Single linked list of timers */
465 unsigned long starttick;
466 fluid_timer_callback_t callback;
472 * fluid_sample_timer_process - called when synth->ticks is updated
474 static void fluid_sample_timer_process(fluid_synth_t* synth)
476 fluid_sample_timer_t* st;
479 unsigned int ticks = fluid_synth_get_ticks(synth);
481 for (st=synth->sample_timers; st; st=st->next) {
482 if (st->isfinished) {
486 msec = (long) (1000.0*((double) (ticks - st->starttick))/synth->sample_rate);
487 cont = (*st->callback)(st->data, msec);
494 fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data)
496 fluid_sample_timer_t* result = FLUID_NEW(fluid_sample_timer_t);
497 if (result == NULL) {
498 FLUID_LOG(FLUID_ERR, "Out of memory");
501 result->starttick = fluid_synth_get_ticks(synth);
502 result->isfinished = 0;
504 result->callback = callback;
505 result->next = synth->sample_timers;
506 synth->sample_timers = result;
510 int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer)
512 fluid_sample_timer_t** ptr = &synth->sample_timers;
519 ptr = &((*ptr)->next);
521 FLUID_LOG(FLUID_ERR,"delete_fluid_sample_timer failed, no timer found");
526 /***************************************************************
531 static FLUID_INLINE void
532 fluid_synth_update_mixer(fluid_synth_t* synth, void* method, int intparam,
533 fluid_real_t realparam)
535 fluid_return_if_fail(synth != NULL || synth->eventhandler != NULL);
536 fluid_return_if_fail(synth->eventhandler->mixer != NULL);
537 fluid_rvoice_eventhandler_push(synth->eventhandler, method,
538 synth->eventhandler->mixer,
539 intparam, realparam);
544 * Create new FluidSynth instance.
545 * @param settings Configuration parameters to use (used directly).
546 * @return New FluidSynth instance or NULL on error
548 * NOTE: The settings parameter is used directly and should not be modified
549 * or freed independently.
552 new_fluid_synth(fluid_settings_t *settings)
554 fluid_synth_t* synth;
555 fluid_sfloader_t* loader;
559 /* initialize all the conversion tables and other stuff */
560 if (fluid_synth_initialized == 0) {
564 /* allocate a new synthesizer object */
565 synth = FLUID_NEW(fluid_synth_t);
567 FLUID_LOG(FLUID_ERR, "Out of memory");
570 FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
572 fluid_rec_mutex_init(synth->mutex);
573 fluid_settings_getint(settings, "synth.threadsafe-api", &synth->use_mutex);
574 synth->public_api_count = 0;
576 synth->settings = settings;
578 fluid_settings_getint(settings, "synth.reverb.active", &synth->with_reverb);
579 fluid_settings_getint(settings, "synth.chorus.active", &synth->with_chorus);
580 fluid_settings_getint(settings, "synth.verbose", &synth->verbose);
581 fluid_settings_getint(settings, "synth.dump", &synth->dump);
583 fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony);
584 fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate);
585 fluid_settings_getint(settings, "synth.midi-channels", &synth->midi_channels);
586 fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels);
587 fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
588 fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
589 fluid_settings_getnum(settings, "synth.gain", &gain);
591 fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
592 fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
594 /* register the callbacks */
595 fluid_settings_register_num(settings, "synth.sample-rate",
596 44100.0f, 8000.0f, 96000.0f, 0,
597 (fluid_num_update_t) fluid_synth_update_sample_rate, synth);
598 fluid_settings_register_num(settings, "synth.gain",
599 0.2f, 0.0f, 10.0f, 0,
600 (fluid_num_update_t) fluid_synth_update_gain, synth);
601 fluid_settings_register_int(settings, "synth.polyphony",
602 synth->polyphony, 1, 65535, 0,
603 (fluid_int_update_t) fluid_synth_update_polyphony,
605 fluid_settings_register_int(settings, "synth.device-id",
606 synth->device_id, 126, 0, 0,
607 (fluid_int_update_t) fluid_synth_update_device_id, synth);
609 fluid_synth_register_overflow(settings,
610 (fluid_num_update_t) fluid_synth_update_overflow, synth);
612 /* do some basic sanity checking on the settings */
614 if (synth->midi_channels % 16 != 0) {
615 int n = synth->midi_channels / 16;
616 synth->midi_channels = (n + 1) * 16;
617 fluid_settings_setint(settings, "synth.midi-channels", synth->midi_channels);
618 FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is not a multiple of 16. "
619 "I'll increase the number of channels to the next multiple.");
622 if (synth->audio_channels < 1) {
623 FLUID_LOG(FLUID_WARN, "Requested number of audio channels is smaller than 1. "
624 "Changing this setting to 1.");
625 synth->audio_channels = 1;
626 } else if (synth->audio_channels > 128) {
627 FLUID_LOG(FLUID_WARN, "Requested number of audio channels is too big (%d). "
628 "Limiting this setting to 128.", synth->audio_channels);
629 synth->audio_channels = 128;
632 if (synth->audio_groups < 1) {
633 FLUID_LOG(FLUID_WARN, "Requested number of audio groups is smaller than 1. "
634 "Changing this setting to 1.");
635 synth->audio_groups = 1;
636 } else if (synth->audio_groups > 128) {
637 FLUID_LOG(FLUID_WARN, "Requested number of audio groups is too big (%d). "
638 "Limiting this setting to 128.", synth->audio_groups);
639 synth->audio_groups = 128;
642 if (synth->effects_channels < 2) {
643 FLUID_LOG(FLUID_WARN, "Invalid number of effects channels (%d)."
644 "Setting effects channels to 2.", synth->effects_channels);
645 synth->effects_channels = 2;
649 /* The number of buffers is determined by the higher number of nr
650 * groups / nr audio channels. If LADSPA is unused, they should be
652 nbuf = synth->audio_channels;
653 if (synth->audio_groups > nbuf) {
654 nbuf = synth->audio_groups;
657 /* as soon as the synth is created it starts playing. */
658 synth->state = FLUID_SYNTH_PLAYING;
659 synth->sfont_info = NULL;
660 synth->sfont_hash = new_fluid_hashtable (NULL, NULL);
662 synth->ticks_since_start = 0;
663 synth->tuning = NULL;
664 fluid_private_init(synth->tuning_iter);
666 /* Allocate event queue for rvoice mixer */
667 fluid_settings_getint(settings, "synth.parallel-render", &i);
668 /* In an overflow situation, a new voice takes about 50 spaces in the queue! */
669 synth->eventhandler = new_fluid_rvoice_eventhandler(i, synth->polyphony*64,
670 synth->polyphony, nbuf, synth->effects_channels, synth->sample_rate);
672 if (synth->eventhandler == NULL)
676 /* Create and initialize the Fx unit.*/
677 synth->LADSPA_FxUnit = new_fluid_LADSPA_FxUnit(synth);
678 fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->LADSPA_FxUnit);
681 /* allocate and add the default sfont loader */
682 loader = new_fluid_defsfloader(settings);
684 if (loader == NULL) {
685 FLUID_LOG(FLUID_WARN, "Failed to create the default SoundFont loader");
687 fluid_synth_add_sfloader(synth, loader);
690 /* allocate all channel objects */
691 synth->channel = FLUID_ARRAY(fluid_channel_t*, synth->midi_channels);
692 if (synth->channel == NULL) {
693 FLUID_LOG(FLUID_ERR, "Out of memory");
696 for (i = 0; i < synth->midi_channels; i++) {
697 synth->channel[i] = new_fluid_channel(synth, i);
698 if (synth->channel[i] == NULL) {
703 /* allocate all synthesis processes */
704 synth->nvoice = synth->polyphony;
705 synth->voice = FLUID_ARRAY(fluid_voice_t*, synth->nvoice);
706 if (synth->voice == NULL) {
709 for (i = 0; i < synth->nvoice; i++) {
710 synth->voice[i] = new_fluid_voice(synth->sample_rate);
711 if (synth->voice[i] == NULL) {
716 fluid_synth_set_sample_rate(synth, synth->sample_rate);
718 fluid_synth_update_overflow(synth, "", 0.0f);
719 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
720 synth->polyphony, 0.0f);
721 fluid_synth_set_reverb_on(synth, synth->with_reverb);
722 fluid_synth_set_chorus_on(synth, synth->with_chorus);
724 synth->cur = FLUID_BUFSIZE;
726 synth->dither_index = 0;
728 synth->reverb_roomsize = FLUID_REVERB_DEFAULT_ROOMSIZE;
729 synth->reverb_damping = FLUID_REVERB_DEFAULT_DAMP;
730 synth->reverb_width = FLUID_REVERB_DEFAULT_WIDTH;
731 synth->reverb_level = FLUID_REVERB_DEFAULT_LEVEL;
733 fluid_rvoice_eventhandler_push5(synth->eventhandler,
734 fluid_rvoice_mixer_set_reverb_params,
735 synth->eventhandler->mixer,
736 FLUID_REVMODEL_SET_ALL, synth->reverb_roomsize,
737 synth->reverb_damping, synth->reverb_width,
738 synth->reverb_level, 0.0f);
740 /* Initialize multi-core variables if multiple cores enabled */
741 if (synth->cores > 1)
744 fluid_settings_getint (synth->settings, "audio.realtime-prio", &prio_level);
745 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_threads,
746 synth->cores-1, prio_level);
749 synth->bank_select = FLUID_BANK_STYLE_GS;
750 if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "gm") == 1)
751 synth->bank_select = FLUID_BANK_STYLE_GM;
752 else if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "gs") == 1)
753 synth->bank_select = FLUID_BANK_STYLE_GS;
754 else if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "xg") == 1)
755 synth->bank_select = FLUID_BANK_STYLE_XG;
756 else if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "mma") == 1)
757 synth->bank_select = FLUID_BANK_STYLE_MMA;
759 fluid_synth_process_event_queue(synth);
762 synth->start = fluid_curtime();
767 delete_fluid_synth(synth);
773 * Delete a FluidSynth instance.
774 * @param synth FluidSynth instance to delete
777 * NOTE: Other users of a synthesizer instance, such as audio and MIDI drivers,
778 * should be deleted prior to freeing the FluidSynth instance.
781 delete_fluid_synth(fluid_synth_t* synth)
785 fluid_sfont_info_t* sfont_info;
786 // fluid_event_queue_t* queue;
787 fluid_sfloader_t* loader;
793 fluid_profiling_print();
795 /* turn off all voices, needed to unload SoundFont data */
796 if (synth->voice != NULL) {
797 for (i = 0; i < synth->nvoice; i++) {
798 fluid_voice_t* voice = synth->voice[i];
801 fluid_voice_unlock_rvoice(voice);
802 fluid_voice_overflow_rvoice_finished(voice);
803 if (fluid_voice_is_playing(voice))
804 fluid_voice_off(voice);
808 /* also unset all presets for clean SoundFont unload */
809 if (synth->channel != NULL)
810 for (i = 0; i < synth->midi_channels; i++)
811 if (synth->channel[i] != NULL)
812 fluid_channel_set_preset(synth->channel[i], NULL);
814 if (synth->eventhandler)
815 delete_fluid_rvoice_eventhandler(synth->eventhandler);
817 /* delete all the SoundFonts */
818 for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
819 sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
820 delete_fluid_sfont (sfont_info->sfont);
821 FLUID_FREE (sfont_info);
824 delete_fluid_list(synth->sfont_info);
827 /* Delete the SoundFont info hash */
828 if (synth->sfont_hash) delete_fluid_hashtable (synth->sfont_hash);
831 /* delete all the SoundFont loaders */
833 for (list = synth->loaders; list; list = fluid_list_next(list)) {
834 loader = (fluid_sfloader_t*) fluid_list_get(list);
835 fluid_sfloader_delete(loader);
838 delete_fluid_list(synth->loaders);
841 if (synth->channel != NULL) {
842 for (i = 0; i < synth->midi_channels; i++) {
843 if (synth->channel[i] != NULL) {
844 delete_fluid_channel(synth->channel[i]);
847 FLUID_FREE(synth->channel);
850 if (synth->voice != NULL) {
851 for (i = 0; i < synth->nvoice; i++) {
852 if (synth->voice[i] != NULL) {
853 delete_fluid_voice(synth->voice[i]);
856 FLUID_FREE(synth->voice);
860 /* free the tunings, if any */
861 if (synth->tuning != NULL) {
862 for (i = 0; i < 128; i++) {
863 if (synth->tuning[i] != NULL) {
864 for (k = 0; k < 128; k++) {
865 if (synth->tuning[i][k] != NULL) {
866 delete_fluid_tuning(synth->tuning[i][k]);
869 FLUID_FREE(synth->tuning[i]);
872 FLUID_FREE(synth->tuning);
875 fluid_private_free (synth->tuning_iter);
878 /* Release the LADSPA Fx unit */
879 fluid_LADSPA_shutdown(synth->LADSPA_FxUnit);
880 FLUID_FREE(synth->LADSPA_FxUnit);
883 fluid_rec_mutex_destroy(synth->mutex);
891 * Get a textual representation of the last error
892 * @param synth FluidSynth instance
893 * @return Pointer to string of last error message. Valid until the same
894 * calling thread calls another FluidSynth function which fails. String is
895 * internal and should not be modified or freed.
897 /* FIXME - The error messages are not thread-safe, yet. They are still stored
898 * in a global message buffer (see fluid_sys.c). */
900 fluid_synth_error(fluid_synth_t* synth)
902 return fluid_error();
906 * Send a note-on event to a FluidSynth object.
907 * @param synth FluidSynth instance
908 * @param chan MIDI channel number (0 to MIDI channel count - 1)
909 * @param key MIDI note number (0-127)
910 * @param vel MIDI velocity (0-127, 0=noteoff)
911 * @return FLUID_OK on success, FLUID_FAILED otherwise
914 fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
917 fluid_return_val_if_fail (key >= 0 && key <= 127, FLUID_FAILED);
918 fluid_return_val_if_fail (vel >= 0 && vel <= 127, FLUID_FAILED);
919 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
921 result = fluid_synth_noteon_LOCAL (synth, chan, key, vel);
922 FLUID_API_RETURN(result);
925 /* Local synthesis thread variant of fluid_synth_noteon */
927 fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key, int vel)
929 fluid_channel_t* channel;
931 /* notes with velocity zero go to noteoff */
932 if (vel == 0) return fluid_synth_noteoff_LOCAL(synth, chan, key);
934 channel = synth->channel[chan];
936 /* make sure this channel has a preset */
937 if (channel->preset == NULL) {
938 if (synth->verbose) {
939 FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d\t%s",
941 fluid_synth_get_ticks(synth) / 44100.0f,
942 (fluid_curtime() - synth->start) / 1000.0f,
943 0.0f, 0, "channel has no preset");
948 /* If there is another voice process on the same channel and key,
949 advance it to the release phase. */
950 fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, key);
953 return fluid_preset_noteon(channel->preset, synth, chan, key, vel);
957 * Send a note-off event to a FluidSynth object.
958 * @param synth FluidSynth instance
959 * @param chan MIDI channel number (0 to MIDI channel count - 1)
960 * @param key MIDI note number (0-127)
961 * @return FLUID_OK on success, FLUID_FAILED otherwise (may just mean that no
962 * voices matched the note off event)
965 fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
968 fluid_return_val_if_fail (key >= 0 && key <= 127, FLUID_FAILED);
969 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
971 result = fluid_synth_noteoff_LOCAL (synth, chan, key);
973 FLUID_API_RETURN(result);
976 /* Local synthesis thread variant of fluid_synth_noteoff */
978 fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key)
980 fluid_voice_t* voice;
981 int status = FLUID_FAILED;
984 for (i = 0; i < synth->polyphony; i++) {
985 voice = synth->voice[i];
986 if (_ON(voice) && (voice->chan == chan) && (voice->key == key)) {
987 if (synth->verbose) {
990 for (k = 0; k < synth->polyphony; k++) {
991 if (!_AVAILABLE(synth->voice[k])) {
995 FLUID_LOG(FLUID_INFO, "noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%d",
996 voice->chan, voice->key, 0, voice->id,
997 (fluid_curtime() - synth->start) / 1000.0f,
1001 fluid_voice_noteoff(voice);
1004 } /* for all voices */
1008 /* Damp voices on a channel (turn notes off), if they're sustained by
1011 fluid_synth_damp_voices_by_sustain_LOCAL(fluid_synth_t* synth, int chan)
1013 fluid_voice_t* voice;
1016 for (i = 0; i < synth->polyphony; i++) {
1017 voice = synth->voice[i];
1019 if ((voice->chan == chan) && _SUSTAINED(voice))
1020 fluid_voice_release(voice);
1026 /* Damp voices on a channel (turn notes off), if they're sustained by
1029 fluid_synth_damp_voices_by_sostenuto_LOCAL(fluid_synth_t* synth, int chan)
1031 fluid_voice_t* voice;
1034 for (i = 0; i < synth->polyphony; i++) {
1035 voice = synth->voice[i];
1037 if ((voice->chan == chan) && _HELD_BY_SOSTENUTO(voice))
1038 fluid_voice_release(voice);
1046 * Send a MIDI controller event on a MIDI channel.
1047 * @param synth FluidSynth instance
1048 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1049 * @param num MIDI controller number (0-127)
1050 * @param val MIDI controller value (0-127)
1051 * @return FLUID_OK on success, FLUID_FAILED otherwise
1054 fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
1057 fluid_return_val_if_fail (num >= 0 && num <= 127, FLUID_FAILED);
1058 fluid_return_val_if_fail (val >= 0 && val <= 127, FLUID_FAILED);
1059 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1062 FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", chan, num, val);
1064 fluid_channel_set_cc (synth->channel[chan], num, val);
1065 result = fluid_synth_cc_LOCAL (synth, chan, num);
1066 FLUID_API_RETURN(result);
1069 /* Local synthesis thread variant of MIDI CC set function. */
1071 fluid_synth_cc_LOCAL (fluid_synth_t* synth, int channum, int num)
1073 fluid_channel_t* chan = synth->channel[channum];
1077 value = fluid_channel_get_cc (chan, num);
1080 case SUSTAIN_SWITCH:
1081 /* Release voices if Sustain switch is released */
1082 if (value < 64) /* Sustain is released */
1083 fluid_synth_damp_voices_by_sustain_LOCAL (synth, channum);
1086 case SOSTENUTO_SWITCH:
1087 /* Release voices if Sostetuno switch is released */
1088 if (value < 64) /* Sostenuto is released */
1089 fluid_synth_damp_voices_by_sostenuto_LOCAL(synth, channum);
1090 else /* Sostenuto is depressed */
1091 /* Update sostenuto order id when pedaling on Sostenuto */
1092 chan->sostenuto_orderid = synth->noteid; /* future voice id value */
1095 case BANK_SELECT_MSB:
1096 fluid_channel_set_bank_msb (chan, value & 0x7F);
1098 case BANK_SELECT_LSB:
1099 fluid_channel_set_bank_lsb (chan, value & 0x7F);
1102 fluid_synth_all_notes_off_LOCAL (synth, channum);
1105 fluid_synth_all_sounds_off_LOCAL (synth, channum);
1108 fluid_channel_init_ctrl (chan, 1);
1109 fluid_synth_modulate_voices_all_LOCAL (synth, channum);
1111 case DATA_ENTRY_MSB:
1113 int data = (value << 7) + fluid_channel_get_cc (chan, DATA_ENTRY_LSB);
1115 if (chan->nrpn_active) /* NRPN is active? */
1116 { /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
1117 if ((fluid_channel_get_cc (chan, NRPN_MSB) == 120)
1118 && (fluid_channel_get_cc (chan, NRPN_LSB) < 100))
1120 nrpn_select = chan->nrpn_select;
1122 if (nrpn_select < GEN_LAST)
1124 float val = fluid_gen_scale_nrpn (nrpn_select, data);
1125 fluid_synth_set_gen_LOCAL (synth, channum, nrpn_select, val, FALSE);
1128 chan->nrpn_select = 0; /* Reset to 0 */
1131 else if (fluid_channel_get_cc (chan, RPN_MSB) == 0) /* RPN is active: MSB = 0? */
1133 switch (fluid_channel_get_cc (chan, RPN_LSB))
1135 case RPN_PITCH_BEND_RANGE: /* Set bend range in semitones */
1136 fluid_channel_set_pitch_wheel_sensitivity (synth->channel[channum], value);
1137 fluid_synth_update_pitch_wheel_sens_LOCAL (synth, channum); /* Update bend range */
1138 /* FIXME - Handle LSB? (Fine bend range in cents) */
1140 case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over 1 semitone (+/- 50 cents, 8192 = center) */
1141 fluid_synth_set_gen_LOCAL (synth, channum, GEN_FINETUNE,
1142 (data - 8192) / 8192.0 * 50.0, FALSE);
1144 case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */
1145 fluid_synth_set_gen_LOCAL (synth, channum, GEN_COARSETUNE,
1148 case RPN_TUNING_PROGRAM_CHANGE:
1149 fluid_channel_set_tuning_prog (chan, value);
1150 fluid_synth_activate_tuning (synth, channum,
1151 fluid_channel_get_tuning_bank (chan),
1154 case RPN_TUNING_BANK_SELECT:
1155 fluid_channel_set_tuning_bank (chan, value);
1157 case RPN_MODULATION_DEPTH_RANGE:
1164 fluid_channel_set_cc (chan, NRPN_LSB, 0);
1165 chan->nrpn_select = 0;
1166 chan->nrpn_active = 1;
1169 /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
1170 if (fluid_channel_get_cc (chan, NRPN_MSB) == 120) {
1172 chan->nrpn_select += 100;
1173 } else if (value == 101) {
1174 chan->nrpn_select += 1000;
1175 } else if (value == 102) {
1176 chan->nrpn_select += 10000;
1177 } else if (value < 100) {
1178 chan->nrpn_select += value;
1182 chan->nrpn_active = 1;
1186 chan->nrpn_active = 0;
1189 return fluid_synth_modulate_voices_LOCAL (synth, channum, 1, num);
1196 * Get current MIDI controller value on a MIDI channel.
1197 * @param synth FluidSynth instance
1198 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1199 * @param num MIDI controller number (0-127)
1200 * @param pval Location to store MIDI controller value (0-127)
1201 * @return FLUID_OK on success, FLUID_FAILED otherwise
1204 fluid_synth_get_cc(fluid_synth_t* synth, int chan, int num, int* pval)
1206 fluid_return_val_if_fail (num >= 0 && num < 128, FLUID_FAILED);
1207 fluid_return_val_if_fail (pval != NULL, FLUID_FAILED);
1209 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1211 *pval = fluid_channel_get_cc (synth->channel[chan], num);
1212 FLUID_API_RETURN(FLUID_OK);
1216 * Handler for synth.device-id setting.
1219 fluid_synth_update_device_id (fluid_synth_t *synth, char *name, int value)
1221 fluid_synth_api_enter(synth);
1222 synth->device_id = value;
1223 fluid_synth_api_exit(synth);
1228 * Process a MIDI SYSEX (system exclusive) message.
1229 * @param synth FluidSynth instance
1230 * @param data Buffer containing SYSEX data (not including 0xF0 and 0xF7)
1231 * @param len Length of data in buffer
1232 * @param response Buffer to store response to or NULL to ignore
1233 * @param response_len IN/OUT parameter, in: size of response buffer, out:
1234 * amount of data written to response buffer (if FLUID_FAILED is returned and
1235 * this value is non-zero, it indicates the response buffer is too small)
1236 * @param handled Optional location to store boolean value if message was
1237 * recognized and handled or not (set to TRUE if it was handled)
1238 * @param dryrun TRUE to just do a dry run but not actually execute the SYSEX
1239 * command (useful for checking if a SYSEX message would be handled)
1240 * @return FLUID_OK on success, FLUID_FAILED otherwise
1243 /* SYSEX format (0xF0 and 0xF7 not passed to this function):
1244 * Non-realtime: 0xF0 0x7E <DeviceId> [BODY] 0xF7
1245 * Realtime: 0xF0 0x7F <DeviceId> [BODY] 0xF7
1246 * Tuning messages: 0xF0 0x7E/0x7F <DeviceId> 0x08 <sub ID2> [BODY] <ChkSum> 0xF7
1249 fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
1250 char *response, int *response_len, int *handled, int dryrun)
1252 int avail_response = 0;
1254 if (handled) *handled = FALSE;
1258 avail_response = *response_len;
1262 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
1263 fluid_return_val_if_fail (data != NULL, FLUID_FAILED);
1264 fluid_return_val_if_fail (len > 0, FLUID_FAILED);
1265 fluid_return_val_if_fail (!response || response_len, FLUID_FAILED);
1267 if (len < 4) return FLUID_OK;
1269 /* MIDI tuning SYSEX message? */
1270 if ((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME)
1271 && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL)
1272 && data[2] == MIDI_SYSEX_MIDI_TUNING_ID)
1275 fluid_synth_api_enter(synth);
1276 result = fluid_synth_sysex_midi_tuning (synth, data, len, response,
1277 response_len, avail_response,
1280 FLUID_API_RETURN(result);
1285 /* Handler for MIDI tuning SYSEX messages */
1287 fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, const char *data, int len,
1288 char *response, int *response_len, int avail_response,
1289 int *handled, int dryrun)
1291 int realtime, msgid;
1292 int bank = 0, prog, channels;
1293 double tunedata[128];
1296 int note, frac, frac2;
1298 int i, count, index;
1299 const char *dataptr;
1302 realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME;
1307 case MIDI_SYSEX_TUNING_BULK_DUMP_REQ:
1308 case MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK:
1309 if (data[3] == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
1311 if (len != 5 || data[4] & 0x80 || !response)
1314 *response_len = 406;
1319 if (len != 6 || data[4] & 0x80 || data[5] & 0x80 || !response)
1322 *response_len = 407;
1329 if (handled) *handled = TRUE;
1333 if (avail_response < *response_len) return FLUID_FAILED;
1335 /* Get tuning data, return if tuning not found */
1336 if (fluid_synth_tuning_dump (synth, bank, prog, name, 17, tunedata) == FLUID_FAILED)
1344 *resptr++ = MIDI_SYSEX_UNIV_NON_REALTIME;
1345 *resptr++ = synth->device_id;
1346 *resptr++ = MIDI_SYSEX_MIDI_TUNING_ID;
1347 *resptr++ = MIDI_SYSEX_TUNING_BULK_DUMP;
1349 if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK)
1353 FLUID_STRNCPY (resptr, name, 16);
1356 for (i = 0; i < 128; i++)
1358 note = tunedata[i] / 100.0;
1359 fluid_clip (note, 0, 127);
1361 frac = ((tunedata[i] - note * 100.0) * 16384.0 + 50.0) / 100.0;
1362 fluid_clip (frac, 0, 16383);
1365 *resptr++ = frac >> 7;
1366 *resptr++ = frac & 0x7F;
1369 if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
1370 { /* NOTE: Checksum is not as straight forward as the bank based messages */
1371 chksum = MIDI_SYSEX_UNIV_NON_REALTIME ^ MIDI_SYSEX_MIDI_TUNING_ID
1372 ^ MIDI_SYSEX_TUNING_BULK_DUMP ^ prog;
1374 for (i = 21; i < 128 * 3 + 21; i++)
1375 chksum ^= response[i];
1379 for (i = 1, chksum = 0; i < 406; i++)
1380 chksum ^= response[i];
1383 *resptr++ = chksum & 0x7F;
1385 if (handled) *handled = TRUE;
1387 case MIDI_SYSEX_TUNING_NOTE_TUNE:
1388 case MIDI_SYSEX_TUNING_NOTE_TUNE_BANK:
1391 if (msgid == MIDI_SYSEX_TUNING_NOTE_TUNE)
1393 if (len < 10 || data[4] & 0x80 || data[5] & 0x80 || len != data[5] * 4 + 6)
1398 if (len < 11 || data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80
1399 || len != data[5] * 4 + 7)
1407 if (handled) *handled = TRUE;
1414 for (i = 0, index = 0; i < count; i++)
1417 if (note & 0x80) return FLUID_OK;
1424 if (note & 0x80 || frac & 0x80 || frac2 & 0x80)
1427 frac = frac << 7 | frac2;
1429 /* No change pitch value? Doesn't really make sense to send that, but.. */
1430 if (note == 0x7F && frac == 16383) continue;
1432 tunedata[index] = note * 100.0 + (frac * 100.0 / 16384.0);
1438 if (fluid_synth_tune_notes (synth, bank, prog, index, keys, tunedata,
1439 realtime) == FLUID_FAILED)
1440 return FLUID_FAILED;
1443 if (handled) *handled = TRUE;
1445 case MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE:
1446 case MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE:
1447 if ((msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE && len != 19)
1448 || (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE && len != 31))
1451 if (data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80)
1456 if (handled) *handled = TRUE;
1460 channels = (data[4] & 0x03) << 14 | data[5] << 7 | data[6];
1462 if (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE)
1464 for (i = 0; i < 12; i++)
1467 if (frac & 0x80) return FLUID_OK;
1468 tunedata[i] = (int)frac - 64;
1473 for (i = 0; i < 12; i++)
1475 frac = data[i * 2 + 7];
1476 frac2 = data[i * 2 + 8];
1477 if (frac & 0x80 || frac2 & 0x80) return FLUID_OK;
1478 tunedata[i] = (((int)frac << 7 | (int)frac2) - 8192) * (200.0 / 16384.0);
1482 if (fluid_synth_activate_octave_tuning (synth, 0, 0, "SYSEX",
1483 tunedata, realtime) == FLUID_FAILED)
1484 return FLUID_FAILED;
1488 for (i = 0; i < 16; i++)
1490 if (channels & (1 << i))
1491 fluid_synth_activate_tuning (synth, i, 0, 0, realtime);
1495 if (handled) *handled = TRUE;
1503 * Turn off all notes on a MIDI channel (put them into release phase).
1504 * @param synth FluidSynth instance
1505 * @param chan MIDI channel number (0 to MIDI channel count - 1), (chan=-1 selects all channels)
1506 * @return FLUID_OK on success, FLUID_FAILED otherwise
1510 fluid_synth_all_notes_off(fluid_synth_t* synth, int chan)
1514 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
1515 fluid_return_val_if_fail (chan >= -1, FLUID_FAILED);
1516 fluid_synth_api_enter(synth);
1517 if (chan >= synth->midi_channels)
1518 result = FLUID_FAILED;
1520 result = fluid_synth_all_notes_off_LOCAL (synth, chan);
1521 FLUID_API_RETURN(result);
1524 /* Local synthesis thread variant of all notes off, (chan=-1 selects all channels) */
1526 fluid_synth_all_notes_off_LOCAL(fluid_synth_t* synth, int chan)
1528 fluid_voice_t* voice;
1531 for (i = 0; i < synth->polyphony; i++) {
1532 voice = synth->voice[i];
1534 if (_PLAYING(voice) && ((-1 == chan) || (chan == voice->chan)))
1535 fluid_voice_noteoff(voice);
1541 * Immediately stop all notes on a MIDI channel (skips release phase).
1542 * @param synth FluidSynth instance
1543 * @param chan MIDI channel number (0 to MIDI channel count - 1), (chan=-1 selects all channels)
1544 * @return FLUID_OK on success, FLUID_FAILED otherwise
1548 fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan)
1552 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
1553 fluid_return_val_if_fail (chan >= -1, FLUID_FAILED);
1554 fluid_synth_api_enter(synth);
1555 if (chan >= synth->midi_channels)
1556 result = FLUID_FAILED;
1558 result = fluid_synth_all_sounds_off_LOCAL (synth, chan);
1559 FLUID_API_RETURN(result);
1562 /* Local synthesis thread variant of all sounds off, (chan=-1 selects all channels) */
1564 fluid_synth_all_sounds_off_LOCAL(fluid_synth_t* synth, int chan)
1566 fluid_voice_t* voice;
1569 for (i = 0; i < synth->polyphony; i++) {
1570 voice = synth->voice[i];
1572 if (_PLAYING(voice) && ((-1 == chan) || (chan == voice->chan)))
1573 fluid_voice_off(voice);
1579 * Reset reverb engine
1580 * @param synth FluidSynth instance
1581 * @return FLUID_OK on success, FLUID_FAILED otherwise
1584 fluid_synth_reset_reverb(fluid_synth_t* synth)
1586 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
1587 fluid_synth_api_enter(synth);
1588 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_reverb, 0, 0.0f);
1589 FLUID_API_RETURN(FLUID_OK);
1593 * Reset chorus engine
1594 * @param synth FluidSynth instance
1595 * @return FLUID_OK on success, FLUID_FAILED otherwise
1598 fluid_synth_reset_chorus(fluid_synth_t* synth)
1600 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
1601 fluid_synth_api_enter(synth);
1602 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_chorus, 0, 0.0f);
1603 FLUID_API_RETURN(FLUID_OK);
1608 * Send MIDI system reset command (big red 'panic' button), turns off notes and
1609 * resets controllers.
1610 * @param synth FluidSynth instance
1611 * @return FLUID_OK on success, FLUID_FAILED otherwise
1614 fluid_synth_system_reset(fluid_synth_t* synth)
1617 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
1618 fluid_synth_api_enter(synth);
1619 result = fluid_synth_system_reset_LOCAL (synth);
1620 FLUID_API_RETURN(result);
1623 /* Local variant of the system reset command */
1625 fluid_synth_system_reset_LOCAL(fluid_synth_t* synth)
1627 fluid_voice_t* voice;
1630 for (i = 0; i < synth->polyphony; i++) {
1631 voice = synth->voice[i];
1633 if (_PLAYING(voice))
1634 fluid_voice_off(voice);
1637 for (i = 0; i < synth->midi_channels; i++)
1638 fluid_channel_reset(synth->channel[i]);
1640 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_fx, 0, 0.0f);
1646 * Update voices on a MIDI channel after a MIDI control change.
1647 * @param synth FluidSynth instance
1648 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1649 * @param is_cc Boolean value indicating if ctrl is a CC controller or not
1650 * @param ctrl MIDI controller value
1651 * @return FLUID_OK on success, FLUID_FAILED otherwise
1654 fluid_synth_modulate_voices_LOCAL(fluid_synth_t* synth, int chan, int is_cc, int ctrl)
1656 fluid_voice_t* voice;
1659 for (i = 0; i < synth->polyphony; i++) {
1660 voice = synth->voice[i];
1662 if (voice->chan == chan)
1663 fluid_voice_modulate(voice, is_cc, ctrl);
1669 * Update voices on a MIDI channel after all MIDI controllers have been changed.
1670 * @param synth FluidSynth instance
1671 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1672 * @return FLUID_OK on success, FLUID_FAILED otherwise
1675 fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan)
1677 fluid_voice_t* voice;
1680 for (i = 0; i < synth->polyphony; i++) {
1681 voice = synth->voice[i];
1683 if (voice->chan == chan)
1684 fluid_voice_modulate_all(voice);
1690 * Set the MIDI channel pressure controller value.
1691 * @param synth FluidSynth instance
1692 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1693 * @param val MIDI channel pressure value (0-127)
1694 * @return FLUID_OK on success, FLUID_FAILED otherwise
1697 fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val)
1700 fluid_return_val_if_fail (val >= 0 && val <= 127, FLUID_FAILED);
1702 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1705 FLUID_LOG(FLUID_INFO, "channelpressure\t%d\t%d", chan, val);
1707 fluid_channel_set_channel_pressure (synth->channel[chan], val);
1709 result = fluid_synth_update_channel_pressure_LOCAL (synth, chan);
1710 FLUID_API_RETURN(result);
1713 /* Updates channel pressure from within synthesis thread */
1715 fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int chan)
1717 return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_CHANNELPRESSURE);
1721 * Set the MIDI pitch bend controller value on a MIDI channel.
1722 * @param synth FluidSynth instance
1723 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1724 * @param val MIDI pitch bend value (0-16383 with 8192 being center)
1725 * @return FLUID_OK on success, FLUID_FAILED otherwise
1728 fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
1731 fluid_return_val_if_fail (val >= 0 && val <= 16383, FLUID_FAILED);
1732 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1735 FLUID_LOG(FLUID_INFO, "pitchb\t%d\t%d", chan, val);
1737 fluid_channel_set_pitch_bend (synth->channel[chan], val);
1739 result = fluid_synth_update_pitch_bend_LOCAL (synth, chan);
1740 FLUID_API_RETURN(result);
1743 /* Local synthesis thread variant of pitch bend */
1745 fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan)
1747 return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_PITCHWHEEL);
1751 * Get the MIDI pitch bend controller value on a MIDI channel.
1752 * @param synth FluidSynth instance
1753 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1754 * @param ppitch_bend Location to store MIDI pitch bend value (0-16383 with
1755 * 8192 being center)
1756 * @return FLUID_OK on success, FLUID_FAILED otherwise
1759 fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend)
1761 fluid_return_val_if_fail (ppitch_bend != NULL, FLUID_FAILED);
1762 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1764 *ppitch_bend = fluid_channel_get_pitch_bend (synth->channel[chan]);
1765 FLUID_API_RETURN(FLUID_OK);
1769 * Set MIDI pitch wheel sensitivity on a MIDI channel.
1770 * @param synth FluidSynth instance
1771 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1772 * @param val Pitch wheel sensitivity value in semitones
1773 * @return FLUID_OK on success, FLUID_FAILED otherwise
1776 fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val)
1779 fluid_return_val_if_fail (val >= 0 && val <= 72, FLUID_FAILED); /* 6 octaves!? Better than no limit.. */
1780 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1783 FLUID_LOG(FLUID_INFO, "pitchsens\t%d\t%d", chan, val);
1785 fluid_channel_set_pitch_wheel_sensitivity (synth->channel[chan], val);
1787 result = fluid_synth_update_pitch_wheel_sens_LOCAL (synth, chan);
1788 FLUID_API_RETURN(result);
1791 /* Local synthesis thread variant of set pitch wheel sensitivity */
1793 fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan)
1795 return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_PITCHWHEELSENS);
1799 * Get MIDI pitch wheel sensitivity on a MIDI channel.
1800 * @param synth FluidSynth instance
1801 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1802 * @param pval Location to store pitch wheel sensitivity value in semitones
1803 * @return FLUID_OK on success, FLUID_FAILED otherwise
1804 * @since Sometime AFTER v1.0 API freeze.
1807 fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval)
1809 fluid_return_val_if_fail (pval != NULL, FLUID_FAILED);
1810 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1812 *pval = fluid_channel_get_pitch_wheel_sensitivity (synth->channel[chan]);
1813 FLUID_API_RETURN(FLUID_OK);
1817 * Assign a preset to a MIDI channel.
1818 * @param synth FluidSynth instance
1819 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1820 * @param preset Preset to assign to channel or NULL to clear (ownership is taken over)
1821 * @return FLUID_OK on success, FLUID_FAILED otherwise
1824 fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset)
1826 fluid_channel_t *channel;
1828 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
1829 fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
1831 channel = synth->channel[chan];
1833 return fluid_channel_set_preset (channel, preset);
1836 /* Get a preset by SoundFont, bank and program numbers.
1837 * Returns preset pointer or NULL.
1839 * NOTE: The returned preset has been allocated, caller owns it and should
1840 * free it when finished using it.
1842 static fluid_preset_t*
1843 fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
1844 unsigned int banknum, unsigned int prognum)
1846 fluid_preset_t *preset = NULL;
1847 fluid_sfont_info_t *sfont_info;
1850 /* 128 indicates an "unset" operation" */
1851 if (prognum == FLUID_UNSET_PROGRAM) return NULL;
1853 for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
1854 sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
1856 if (fluid_sfont_get_id (sfont_info->sfont) == sfontnum)
1858 preset = fluid_sfont_get_preset (sfont_info->sfont,
1859 banknum - sfont_info->bankofs, prognum);
1860 if (preset) sfont_info->refcount++; /* Add reference to SoundFont */
1868 /* Get a preset by SoundFont name, bank and program.
1869 * Returns preset pointer or NULL.
1871 * NOTE: The returned preset has been allocated, caller owns it and should
1872 * free it when finished using it.
1874 static fluid_preset_t*
1875 fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname,
1876 unsigned int banknum, unsigned int prognum)
1878 fluid_preset_t *preset = NULL;
1879 fluid_sfont_info_t *sfont_info;
1882 for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
1883 sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
1885 if (FLUID_STRCMP (fluid_sfont_get_name (sfont_info->sfont), sfontname) == 0)
1887 preset = fluid_sfont_get_preset (sfont_info->sfont,
1888 banknum - sfont_info->bankofs, prognum);
1889 if (preset) sfont_info->refcount++; /* Add reference to SoundFont */
1897 /* Find a preset by bank and program numbers.
1898 * Returns preset pointer or NULL.
1900 * NOTE: The returned preset has been allocated, caller owns it and should
1901 * free it when finished using it. */
1903 fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
1904 unsigned int prognum)
1906 fluid_preset_t *preset = NULL;
1907 fluid_sfont_info_t *sfont_info;
1910 for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
1911 sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
1913 preset = fluid_sfont_get_preset (sfont_info->sfont,
1914 banknum - sfont_info->bankofs, prognum);
1917 sfont_info->refcount++; /* Add reference to SoundFont */
1926 * Send a program change event on a MIDI channel.
1927 * @param synth FluidSynth instance
1928 * @param chan MIDI channel number (0 to MIDI channel count - 1)
1929 * @param prognum MIDI program number (0-127)
1930 * @return FLUID_OK on success, FLUID_FAILED otherwise
1932 /* FIXME - Currently not real-time safe, due to preset allocation and mutex lock,
1933 * and may be called from within synthesis context. */
1935 /* As of 1.1.1 prognum can be set to 128 to unset the preset. Not documented
1936 * since fluid_synth_unset_program() should be used instead. */
1938 fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
1940 fluid_preset_t* preset = NULL;
1941 fluid_channel_t* channel;
1942 int subst_bank, subst_prog, banknum = 0, result;
1944 fluid_return_val_if_fail (prognum >= 0 && prognum <= 128, FLUID_FAILED);
1945 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
1947 channel = synth->channel[chan];
1948 if (channel->channel_type == CHANNEL_TYPE_DRUM)
1949 banknum = DRUM_INST_BANK;
1951 fluid_channel_get_sfont_bank_prog(channel, NULL, &banknum, NULL);
1954 FLUID_LOG(FLUID_INFO, "prog\t%d\t%d\t%d", chan, banknum, prognum);
1956 /* I think this is a hack for MIDI files that do bank changes in GM mode.
1957 * Proper way to handle this would probably be to ignore bank changes when in
1959 * This is now possible by setting synth.midi-bank-select=gm, but let the hack
1960 * stay for the time being. - DH
1962 if (prognum != FLUID_UNSET_PROGRAM)
1964 subst_bank = banknum;
1965 subst_prog = prognum;
1967 preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
1969 /* Fallback to another preset if not found */
1971 /* Percussion: Fallback to preset 0 in percussion bank */
1972 if (subst_bank == DRUM_INST_BANK) {
1974 preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
1976 /* Melodic instrument */
1978 /* Fallback first to bank 0:prognum */
1980 preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
1982 /* Fallback to first preset in bank 0 (usually piano...) */
1986 preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
1991 FLUID_LOG(FLUID_WARN, "Instrument not found on channel %d [bank=%d prog=%d], substituted [bank=%d prog=%d]",
1992 chan, banknum, prognum, subst_bank, subst_prog);
1994 FLUID_LOG(FLUID_WARN, "No preset found on channel %d [bank=%d prog=%d]",
1995 chan, banknum, prognum);
1999 /* Assign the SoundFont ID and program number to the channel */
2000 fluid_channel_set_sfont_bank_prog (channel, preset ? fluid_sfont_get_id (preset->sfont) : 0,
2002 result = fluid_synth_set_preset (synth, chan, preset);
2003 FLUID_API_RETURN(result);
2007 * Set instrument bank number on a MIDI channel.
2008 * @param synth FluidSynth instance
2009 * @param chan MIDI channel number (0 to MIDI channel count - 1)
2010 * @param bank MIDI bank number
2011 * @return FLUID_OK on success, FLUID_FAILED otherwise
2014 fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank)
2016 fluid_return_val_if_fail (bank <= 16383, FLUID_FAILED);
2017 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
2019 fluid_channel_set_sfont_bank_prog (synth->channel[chan], -1, bank, -1);
2020 FLUID_API_RETURN(FLUID_OK);
2024 * Set SoundFont ID on a MIDI channel.
2025 * @param synth FluidSynth instance
2026 * @param chan MIDI channel number (0 to MIDI channel count - 1)
2027 * @param sfont_id ID of a loaded SoundFont
2028 * @return FLUID_OK on success, FLUID_FAILED otherwise
2031 fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id)
2033 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
2035 fluid_channel_set_sfont_bank_prog(synth->channel[chan], sfont_id, -1, -1);
2037 FLUID_API_RETURN(FLUID_OK);
2041 * Set the preset of a MIDI channel to an unassigned state.
2042 * @param synth FluidSynth instance
2043 * @param chan MIDI channel number (0 to MIDI channel count - 1)
2044 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
2047 * Note: Channel retains its SoundFont ID and bank numbers, while the program
2048 * number is set to an "unset" state. MIDI program changes may re-assign a
2049 * preset if one matches.
2052 fluid_synth_unset_program (fluid_synth_t *synth, int chan)
2055 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
2057 result = fluid_synth_program_change (synth, chan, FLUID_UNSET_PROGRAM);
2058 FLUID_API_RETURN(result);
2062 * Get current SoundFont ID, bank number and program number for a MIDI channel.
2063 * @param synth FluidSynth instance
2064 * @param chan MIDI channel number (0 to MIDI channel count - 1)
2065 * @param sfont_id Location to store SoundFont ID
2066 * @param bank_num Location to store MIDI bank number
2067 * @param preset_num Location to store MIDI program number
2068 * @return FLUID_OK on success, FLUID_FAILED otherwise
2071 fluid_synth_get_program(fluid_synth_t* synth, int chan, unsigned int* sfont_id,
2072 unsigned int* bank_num, unsigned int* preset_num)
2074 fluid_channel_t* channel;
2076 fluid_return_val_if_fail (sfont_id != NULL, FLUID_FAILED);
2077 fluid_return_val_if_fail (bank_num != NULL, FLUID_FAILED);
2078 fluid_return_val_if_fail (preset_num != NULL, FLUID_FAILED);
2079 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
2081 channel = synth->channel[chan];
2082 fluid_channel_get_sfont_bank_prog(channel, (int *)sfont_id, (int *)bank_num,
2085 /* 128 indicates that the preset is unset. Set to 0 to be backwards compatible. */
2086 if (*preset_num == FLUID_UNSET_PROGRAM) *preset_num = 0;
2088 FLUID_API_RETURN(FLUID_OK);
2092 * Select an instrument on a MIDI channel by SoundFont ID, bank and program numbers.
2093 * @param synth FluidSynth instance
2094 * @param chan MIDI channel number (0 to MIDI channel count - 1)
2095 * @param sfont_id ID of a loaded SoundFont
2096 * @param bank_num MIDI bank number
2097 * @param preset_num MIDI program number
2098 * @return FLUID_OK on success, FLUID_FAILED otherwise
2101 fluid_synth_program_select(fluid_synth_t* synth, int chan, unsigned int sfont_id,
2102 unsigned int bank_num, unsigned int preset_num)
2104 fluid_preset_t* preset = NULL;
2105 fluid_channel_t* channel;
2107 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
2109 channel = synth->channel[chan];
2111 /* ++ Allocate preset */
2112 preset = fluid_synth_get_preset (synth, sfont_id, bank_num, preset_num);
2114 if (preset == NULL) {
2115 FLUID_LOG(FLUID_ERR,
2116 "There is no preset with bank number %d and preset number %d in SoundFont %d",
2117 bank_num, preset_num, sfont_id);
2118 FLUID_API_RETURN(FLUID_FAILED);
2121 /* Assign the new SoundFont ID, bank and program number to the channel */
2122 fluid_channel_set_sfont_bank_prog (channel, sfont_id, bank_num, preset_num);
2123 result = fluid_synth_set_preset (synth, chan, preset);
2125 FLUID_API_RETURN(result);
2129 * Select an instrument on a MIDI channel by SoundFont name, bank and program numbers.
2130 * @param synth FluidSynth instance
2131 * @param chan MIDI channel number (0 to MIDI channel count - 1)
2132 * @param sfont_name Name of a loaded SoundFont
2133 * @param bank_num MIDI bank number
2134 * @param preset_num MIDI program number
2135 * @return FLUID_OK on success, FLUID_FAILED otherwise
2139 fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
2140 const char *sfont_name, unsigned int bank_num,
2141 unsigned int preset_num)
2143 fluid_preset_t* preset = NULL;
2144 fluid_channel_t* channel;
2146 fluid_return_val_if_fail (sfont_name != NULL, FLUID_FAILED);
2147 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
2149 channel = synth->channel[chan];
2151 /* ++ Allocate preset */
2152 preset = fluid_synth_get_preset_by_sfont_name (synth, sfont_name, bank_num,
2154 if (preset == NULL) {
2155 FLUID_LOG(FLUID_ERR,
2156 "There is no preset with bank number %d and preset number %d in SoundFont %s",
2157 bank_num, preset_num, sfont_name);
2158 FLUID_API_RETURN(FLUID_FAILED);
2161 /* Assign the new SoundFont ID, bank and program number to the channel */
2162 fluid_channel_set_sfont_bank_prog (channel, fluid_sfont_get_id (preset->sfont),
2163 bank_num, preset_num);
2164 result = fluid_synth_set_preset (synth, chan, preset);
2165 FLUID_API_RETURN(result);
2169 * This function assures that every MIDI channel has a valid preset
2170 * (NULL is okay). This function is called after a SoundFont is
2171 * unloaded or reloaded.
2174 fluid_synth_update_presets(fluid_synth_t* synth)
2176 fluid_channel_t *channel;
2177 fluid_preset_t *preset;
2178 int sfont, bank, prog;
2181 for (chan = 0; chan < synth->midi_channels; chan++) {
2182 channel = synth->channel[chan];
2183 fluid_channel_get_sfont_bank_prog (channel, &sfont, &bank, &prog);
2184 preset = fluid_synth_get_preset (synth, sfont, bank, prog);
2185 fluid_synth_set_preset (synth, chan, preset);
2189 /* Handler for synth.gain setting. */
2191 fluid_synth_update_sample_rate(fluid_synth_t* synth, char* name, double value)
2193 fluid_synth_set_sample_rate(synth, (float) value);
2198 * Set sample rate of the synth.
2199 * NOTE: This function is currently experimental and should only be
2200 * used when no voices or notes are active, and before any rendering calls.
2201 * @param synth FluidSynth instance
2202 * @param sample_rate New sample rate (Hz)
2206 fluid_synth_set_sample_rate(fluid_synth_t* synth, float sample_rate)
2209 fluid_return_if_fail (synth != NULL);
2210 fluid_synth_api_enter(synth);
2211 fluid_clip (sample_rate, 8000.0f, 96000.0f);
2212 synth->sample_rate = sample_rate;
2214 fluid_settings_getint(synth->settings, "synth.min-note-length", &i);
2215 synth->min_note_length_ticks = (unsigned int) (i*synth->sample_rate/1000.0f);
2217 for (i=0; i < synth->polyphony; i++)
2218 fluid_voice_set_output_rate(synth->voice[i], sample_rate);
2219 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_samplerate,
2221 fluid_synth_api_exit(synth);
2225 /* Handler for synth.gain setting. */
2227 fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value)
2229 fluid_synth_set_gain(synth, (float) value);
2234 * Set synth output gain value.
2235 * @param synth FluidSynth instance
2236 * @param gain Gain value (function clamps value to the range 0.0 to 10.0)
2239 fluid_synth_set_gain(fluid_synth_t* synth, float gain)
2241 fluid_return_if_fail (synth != NULL);
2242 fluid_synth_api_enter(synth);
2244 fluid_clip (gain, 0.0f, 10.0f);
2247 fluid_synth_update_gain_LOCAL (synth);
2248 fluid_synth_api_exit(synth);
2251 /* Called by synthesis thread to update the gain in all voices */
2253 fluid_synth_update_gain_LOCAL(fluid_synth_t* synth)
2255 fluid_voice_t *voice;
2261 for (i = 0; i < synth->polyphony; i++)
2263 voice = synth->voice[i];
2264 if (_PLAYING (voice)) fluid_voice_set_gain (voice, gain);
2269 * Get synth output gain value.
2270 * @param synth FluidSynth instance
2271 * @return Synth gain value (0.0 to 10.0)
2274 fluid_synth_get_gain(fluid_synth_t* synth)
2277 fluid_return_val_if_fail (synth != NULL, 0.0);
2278 fluid_synth_api_enter(synth);
2280 result = synth->gain;
2281 FLUID_API_RETURN(result);
2285 * Handler for synth.polyphony setting.
2288 fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value)
2290 fluid_synth_set_polyphony(synth, value);
2295 * Set synthesizer polyphony (max number of voices).
2296 * @param synth FluidSynth instance
2297 * @param polyphony Polyphony to assign
2298 * @return FLUID_OK on success, FLUID_FAILED otherwise
2302 fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony)
2305 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
2306 fluid_return_val_if_fail (polyphony >= 1 && polyphony <= 65535, FLUID_FAILED);
2307 fluid_synth_api_enter(synth);
2309 result = fluid_synth_update_polyphony_LOCAL(synth, polyphony);
2311 FLUID_API_RETURN(result);
2314 /* Called by synthesis thread to update the polyphony value */
2316 fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth, int new_polyphony)
2318 fluid_voice_t *voice;
2321 if (new_polyphony > synth->nvoice) {
2322 /* Create more voices */
2323 fluid_voice_t** new_voices = FLUID_REALLOC(synth->voice,
2324 sizeof(fluid_voice_t*) * new_polyphony);
2325 if (new_voices == NULL)
2326 return FLUID_FAILED;
2327 synth->voice = new_voices;
2328 for (i = synth->nvoice; i < new_polyphony; i++) {
2329 synth->voice[i] = new_fluid_voice(synth->sample_rate);
2330 if (synth->voice[i] == NULL)
2331 return FLUID_FAILED;
2333 synth->nvoice = new_polyphony;
2336 synth->polyphony = new_polyphony;
2337 /* turn off any voices above the new limit */
2338 for (i = synth->polyphony; i < synth->nvoice; i++)
2340 voice = synth->voice[i];
2341 if (_PLAYING (voice)) fluid_voice_off (voice);
2344 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
2345 synth->polyphony, 0.0f);
2351 * Get current synthesizer polyphony (max number of voices).
2352 * @param synth FluidSynth instance
2353 * @return Synth polyphony value.
2357 fluid_synth_get_polyphony(fluid_synth_t* synth)
2360 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
2361 fluid_synth_api_enter(synth);
2363 result = synth->polyphony;
2364 FLUID_API_RETURN(result);
2368 * Get current number of active voices.
2369 * @param synth FluidSynth instance
2370 * @return Number of currently active voices.
2373 * Note: To generate accurate continuous statistics of the voice count, caller
2374 * should ensure this function is called synchronously with the audio synthesis
2375 * process. This can be done in the new_fluid_audio_driver2() audio callback
2376 * function for example.
2379 fluid_synth_get_active_voice_count(fluid_synth_t* synth)
2382 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
2383 fluid_synth_api_enter(synth);
2385 result = synth->active_voice_count;
2386 FLUID_API_RETURN(result);
2390 * Get the internal synthesis buffer size value.
2391 * @param synth FluidSynth instance
2392 * @return Internal buffer size in audio frames.
2394 * Audio is synthesized this number of frames at a time. Defaults to 64 frames.
2397 fluid_synth_get_internal_bufsize(fluid_synth_t* synth)
2399 return FLUID_BUFSIZE;
2403 * Resend a bank select and a program change for every channel.
2404 * @param synth FluidSynth instance
2405 * @return FLUID_OK on success, FLUID_FAILED otherwise
2407 * This function is called mainly after a SoundFont has been loaded,
2408 * unloaded or reloaded.
2411 fluid_synth_program_reset(fluid_synth_t* synth)
2414 fluid_synth_api_enter(synth);
2415 /* try to set the correct presets */
2416 for (i = 0; i < synth->midi_channels; i++){
2417 fluid_channel_get_sfont_bank_prog (synth->channel[i], NULL, NULL, &prog);
2418 fluid_synth_program_change(synth, i, prog);
2420 FLUID_API_RETURN(FLUID_OK);
2424 * Synthesize a block of floating point audio to audio buffers.
2425 * @param synth FluidSynth instance
2426 * @param len Count of audio frames to synthesize
2427 * @param left Array of floats to store left channel of audio (len in size)
2428 * @param right Array of floats to store right channel of audio (len in size)
2429 * @param fx_left Not currently used
2430 * @param fx_right Not currently used
2431 * @return FLUID_OK on success, FLUID_FAIL otherwise
2433 * NOTE: Should only be called from synthesis thread.
2436 fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
2437 float** left, float** right,
2438 float** fx_left, float** fx_right)
2440 fluid_real_t** left_in;
2441 fluid_real_t** right_in;
2442 double time = fluid_utime();
2443 int i, num, available, count;
2449 if (!synth->eventhandler->is_threadsafe)
2450 fluid_synth_api_enter(synth);
2452 /* First, take what's still available in the buffer */
2455 if (synth->cur < FLUID_BUFSIZE) {
2456 available = FLUID_BUFSIZE - synth->cur;
2457 fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
2459 num = (available > len)? len : available;
2461 bytes = num * sizeof(float);
2464 for (i = 0; i < synth->audio_channels; i++) {
2466 FLUID_MEMCPY(left[i], left_in[i] + synth->cur, bytes);
2467 FLUID_MEMCPY(right[i], right_in[i] + synth->cur, bytes);
2470 for (j = 0; j < num; j++) {
2471 left[i][j] = (float) left_in[i][j + synth->cur];
2472 right[i][j] = (float) right_in[i][j + synth->cur];
2477 num += synth->cur; /* if we're now done, num becomes the new synth->cur below */
2480 /* Then, run one_block() and copy till we have 'len' samples */
2481 while (count < len) {
2482 fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 0);
2483 fluid_synth_render_blocks(synth, 1); // TODO:
2484 fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
2486 num = (FLUID_BUFSIZE > len - count)? len - count : FLUID_BUFSIZE;
2488 bytes = num * sizeof(float);
2491 for (i = 0; i < synth->audio_channels; i++) {
2493 FLUID_MEMCPY(left[i] + count, left_in[i], bytes);
2494 FLUID_MEMCPY(right[i] + count, right_in[i], bytes);
2497 for (j = 0; j < num; j++) {
2498 left[i][j + count] = (float) left_in[i][j];
2499 right[i][j + count] = (float) right_in[i][j];
2509 time = fluid_utime() - time;
2510 cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
2511 fluid_atomic_float_set (&synth->cpu_load, cpu_load);
2513 if (!synth->eventhandler->is_threadsafe)
2514 fluid_synth_api_exit(synth);
2520 * Synthesize floating point audio to audio buffers.
2521 * @param synth FluidSynth instance
2522 * @param len Count of audio frames to synthesize
2523 * @param nin Ignored
2525 * @param nout Count of arrays in 'out'
2526 * @param out Array of arrays to store audio to
2527 * @return FLUID_OK on success, FLUID_FAIL otherwise
2529 * This function implements the default interface defined in fluidsynth/audio.h.
2530 * NOTE: Should only be called from synthesis thread.
2533 * FIXME: Currently if nout != 2 memory allocation will occur!
2536 fluid_synth_process(fluid_synth_t* synth, int len, int nin, float** in,
2537 int nout, float** out)
2540 return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1);
2543 float **left, **right;
2545 left = FLUID_ARRAY(float*, nout/2);
2546 right = FLUID_ARRAY(float*, nout/2);
2547 for(i=0; i<nout/2; i++) {
2549 right[i] = out[2*i+1];
2551 fluid_synth_nwrite_float(synth, len, left, right, NULL, NULL);
2559 * Synthesize a block of floating point audio samples to audio buffers.
2560 * @param synth FluidSynth instance
2561 * @param len Count of audio frames to synthesize
2562 * @param lout Array of floats to store left channel of audio
2563 * @param loff Offset index in 'lout' for first sample
2564 * @param lincr Increment between samples stored to 'lout'
2565 * @param rout Array of floats to store right channel of audio
2566 * @param roff Offset index in 'rout' for first sample
2567 * @param rincr Increment between samples stored to 'rout'
2568 * @return FLUID_OK on success, FLUID_FAIL otherwise
2570 * Useful for storing interleaved stereo (lout = rout, loff = 0, roff = 1,
2571 * lincr = 2, rincr = 2).
2573 * NOTE: Should only be called from synthesis thread.
2576 fluid_synth_write_float(fluid_synth_t* synth, int len,
2577 void* lout, int loff, int lincr,
2578 void* rout, int roff, int rincr)
2581 float* left_out = (float*) lout;
2582 float* right_out = (float*) rout;
2583 fluid_real_t** left_in;
2584 fluid_real_t** right_in;
2585 double time = fluid_utime();
2588 fluid_profile_ref_var (prof_ref);
2589 if (!synth->eventhandler->is_threadsafe)
2590 fluid_synth_api_enter(synth);
2592 fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
2594 fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
2596 for (i = 0, j = loff, k = roff; i < len; i++, l++, j += lincr, k += rincr) {
2597 /* fill up the buffers as needed */
2598 if (l >= synth->curmax) {
2599 int blocksleft = (len-i+FLUID_BUFSIZE-1) / FLUID_BUFSIZE;
2600 synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
2601 fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
2606 left_out[j] = (float) left_in[0][l];
2607 right_out[k] = (float) right_in[0][l];
2612 time = fluid_utime() - time;
2613 cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
2614 fluid_atomic_float_set (&synth->cpu_load, cpu_load);
2616 if (!synth->eventhandler->is_threadsafe)
2617 fluid_synth_api_exit(synth);
2618 fluid_profile(FLUID_PROF_WRITE, prof_ref);
2623 #define DITHER_SIZE 48000
2624 #define DITHER_CHANNELS 2
2626 static float rand_table[DITHER_CHANNELS][DITHER_SIZE];
2628 /* Init dither table */
2635 for (c = 0; c < DITHER_CHANNELS; c++) {
2637 for (i = 0; i < DITHER_SIZE-1; i++) {
2638 d = rand() / (float)RAND_MAX - 0.5f;
2639 rand_table[c][i] = d - dp;
2642 rand_table[c][DITHER_SIZE-1] = 0 - dp;
2646 /* A portable replacement for roundf(), seems it may actually be faster too! */
2651 return (int)(x+0.5f);
2653 return (int)(x-0.5f);
2657 * Synthesize a block of 16 bit audio samples to audio buffers.
2658 * @param synth FluidSynth instance
2659 * @param len Count of audio frames to synthesize
2660 * @param lout Array of 16 bit words to store left channel of audio
2661 * @param loff Offset index in 'lout' for first sample
2662 * @param lincr Increment between samples stored to 'lout'
2663 * @param rout Array of 16 bit words to store right channel of audio
2664 * @param roff Offset index in 'rout' for first sample
2665 * @param rincr Increment between samples stored to 'rout'
2666 * @return FLUID_OK on success, FLUID_FAIL otherwise
2668 * Useful for storing interleaved stereo (lout = rout, loff = 0, roff = 1,
2669 * lincr = 2, rincr = 2).
2671 * NOTE: Should only be called from synthesis thread.
2672 * NOTE: Dithering is performed when converting from internal floating point to
2676 fluid_synth_write_s16(fluid_synth_t* synth, int len,
2677 void* lout, int loff, int lincr,
2678 void* rout, int roff, int rincr)
2681 signed short* left_out = (signed short*) lout;
2682 signed short* right_out = (signed short*) rout;
2683 fluid_real_t** left_in;
2684 fluid_real_t** right_in;
2685 fluid_real_t left_sample;
2686 fluid_real_t right_sample;
2687 double time = fluid_utime();
2689 //double prof_ref_on_block;
2691 fluid_profile_ref_var (prof_ref);
2693 if (!synth->eventhandler->is_threadsafe)
2694 fluid_synth_api_enter(synth);
2696 fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
2697 fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
2700 di = synth->dither_index;
2702 for (i = 0, j = loff, k = roff; i < len; i++, cur++, j += lincr, k += rincr) {
2704 /* fill up the buffers as needed */
2705 if (cur >= synth->curmax) {
2706 int blocksleft = (len-i+FLUID_BUFSIZE-1) / FLUID_BUFSIZE;
2707 //prof_ref_on_block = fluid_profile_ref();
2708 synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
2709 fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
2712 //fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref_on_block);
2715 left_sample = roundi (left_in[0][cur] * 32766.0f + rand_table[0][di]);
2716 right_sample = roundi (right_in[0][cur] * 32766.0f + rand_table[1][di]);
2719 if (di >= DITHER_SIZE) di = 0;
2721 /* digital clipping */
2722 if (left_sample > 32767.0f) left_sample = 32767.0f;
2723 if (left_sample < -32768.0f) left_sample = -32768.0f;
2724 if (right_sample > 32767.0f) right_sample = 32767.0f;
2725 if (right_sample < -32768.0f) right_sample = -32768.0f;
2727 left_out[j] = (signed short) left_sample;
2728 right_out[k] = (signed short) right_sample;
2732 synth->dither_index = di; /* keep dither buffer continous */
2734 fluid_profile(FLUID_PROF_WRITE, prof_ref);
2736 time = fluid_utime() - time;
2737 cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
2738 fluid_atomic_float_set (&synth->cpu_load, cpu_load);
2740 if (!synth->eventhandler->is_threadsafe)
2741 fluid_synth_api_exit(synth);
2747 * Converts stereo floating point sample data to signed 16 bit data with dithering.
2748 * @param dither_index Pointer to an integer which should be initialized to 0
2749 * before the first call and passed unmodified to additional calls which are
2750 * part of the same synthesis output.
2751 * @param len Length in frames to convert
2752 * @param lin Buffer of left audio samples to convert from
2753 * @param rin Buffer of right audio samples to convert from
2754 * @param lout Array of 16 bit words to store left channel of audio
2755 * @param loff Offset index in 'lout' for first sample
2756 * @param lincr Increment between samples stored to 'lout'
2757 * @param rout Array of 16 bit words to store right channel of audio
2758 * @param roff Offset index in 'rout' for first sample
2759 * @param rincr Increment between samples stored to 'rout'
2761 * NOTE: Currently private to libfluidsynth.
2764 fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
2765 void* lout, int loff, int lincr,
2766 void* rout, int roff, int rincr)
2769 signed short* left_out = (signed short*) lout;
2770 signed short* right_out = (signed short*) rout;
2771 fluid_real_t left_sample;
2772 fluid_real_t right_sample;
2773 int di = *dither_index;
2774 fluid_profile_ref_var (prof_ref);
2776 for (i = 0, j = loff, k = roff; i < len; i++, j += lincr, k += rincr) {
2778 left_sample = roundi (lin[i] * 32766.0f + rand_table[0][di]);
2779 right_sample = roundi (rin[i] * 32766.0f + rand_table[1][di]);
2782 if (di >= DITHER_SIZE) di = 0;
2784 /* digital clipping */
2785 if (left_sample > 32767.0f) left_sample = 32767.0f;
2786 if (left_sample < -32768.0f) left_sample = -32768.0f;
2787 if (right_sample > 32767.0f) right_sample = 32767.0f;
2788 if (right_sample < -32768.0f) right_sample = -32768.0f;
2790 left_out[j] = (signed short) left_sample;
2791 right_out[k] = (signed short) right_sample;
2794 *dither_index = di; /* keep dither buffer continous */
2796 fluid_profile(FLUID_PROF_WRITE, prof_ref);
2800 fluid_synth_check_finished_voices(fluid_synth_t* synth)
2805 while (NULL != (fv = fluid_rvoice_eventhandler_get_finished_voice(synth->eventhandler))) {
2806 for (j=0; j < synth->polyphony; j++) {
2807 if (synth->voice[j]->rvoice == fv) {
2808 fluid_voice_unlock_rvoice(synth->voice[j]);
2809 fluid_voice_off(synth->voice[j]);
2812 else if (synth->voice[j]->overflow_rvoice == fv) {
2813 fluid_voice_overflow_rvoice_finished(synth->voice[j]);
2821 * Process all waiting events in the rvoice queue.
2822 * Make sure no (other) rendering is running in parallel when
2823 * you call this function!
2825 void fluid_synth_process_event_queue(fluid_synth_t* synth)
2827 fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler);
2832 * Process blocks (FLUID_BUFSIZE) of audio.
2833 * Must be called from renderer thread only!
2834 * @return number of blocks rendered. Might (often) return less than requested
2837 fluid_synth_render_blocks(fluid_synth_t* synth, int blockcount)
2840 fluid_profile_ref_var (prof_ref);
2842 /* Assign ID of synthesis thread */
2843 // synth->synth_thread_id = fluid_thread_get_id ();
2845 fluid_check_fpe("??? Just starting up ???");
2847 fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler);
2849 for (i=0; i < blockcount; i++) {
2850 fluid_sample_timer_process(synth);
2851 fluid_synth_add_ticks(synth, FLUID_BUFSIZE);
2852 if (fluid_rvoice_eventhandler_dispatch_count(synth->eventhandler)) {
2853 // Something has happened, we can't process more
2859 fluid_check_fpe("fluid_sample_timer_process");
2861 blockcount = fluid_rvoice_mixer_render(synth->eventhandler->mixer, blockcount);
2863 /* Testcase, that provokes a denormal floating point error */
2865 {float num=1;while (num != 0){num*=0.5;};};
2867 fluid_check_fpe("??? Remainder of synth_one_block ???");
2868 fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref);
2873 static int fluid_synth_update_overflow (fluid_synth_t *synth, char *name,
2877 fluid_synth_api_enter(synth);
2879 fluid_settings_getnum(synth->settings, "synth.overflow.percussion", &d);
2880 synth->overflow.percussion = d;
2881 fluid_settings_getnum(synth->settings, "synth.overflow.released", &d);
2882 synth->overflow.released = d;
2883 fluid_settings_getnum(synth->settings, "synth.overflow.sustained", &d);
2884 synth->overflow.sustained = d;
2885 fluid_settings_getnum(synth->settings, "synth.overflow.volume", &d);
2886 synth->overflow.volume = d;
2887 fluid_settings_getnum(synth->settings, "synth.overflow.age", &d);
2888 synth->overflow.age = d;
2890 FLUID_API_RETURN(0);
2894 /* Selects a voice for killing. */
2895 static fluid_voice_t*
2896 fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth)
2899 fluid_real_t best_prio = OVERFLOW_PRIO_CANNOT_KILL-1;
2900 fluid_real_t this_voice_prio;
2901 fluid_voice_t* voice;
2902 int best_voice_index=-1;
2903 unsigned int ticks = fluid_synth_get_ticks(synth);
2905 for (i = 0; i < synth->polyphony; i++) {
2907 voice = synth->voice[i];
2909 /* safeguard against an available voice. */
2910 if (_AVAILABLE(voice)) {
2913 this_voice_prio = fluid_voice_get_overflow_prio(voice, &synth->overflow,
2916 /* check if this voice has less priority than the previous candidate. */
2917 if (this_voice_prio < best_prio) {
2918 best_voice_index = i;
2919 best_prio = this_voice_prio;
2923 if (best_voice_index < 0) {
2927 voice = synth->voice[best_voice_index];
2928 FLUID_LOG(FLUID_DBG, "Killing voice %d, index %d, chan %d, key %d ",
2929 voice->id, best_voice_index, voice->chan, voice->key);
2930 fluid_voice_off(voice);
2937 * Allocate a synthesis voice.
2938 * @param synth FluidSynth instance
2939 * @param sample Sample to assign to the voice
2940 * @param chan MIDI channel number (0 to MIDI channel count - 1)
2941 * @param key MIDI note number for the voice (0-127)
2942 * @param vel MIDI velocity for the voice (0-127)
2943 * @return Allocated synthesis voice or NULL on error
2945 * This function is called by a SoundFont's preset in response to a noteon event.
2946 * The returned voice comes with default modulators and generators.
2947 * A single noteon event may create any number of voices, when the preset is layered.
2949 * NOTE: Should only be called from within synthesis thread, which includes
2950 * SoundFont loader preset noteon method.
2953 fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan, int key, int vel)
2956 fluid_voice_t* voice = NULL;
2957 fluid_channel_t* channel = NULL;
2960 fluid_return_val_if_fail (sample != NULL, NULL);
2961 FLUID_API_ENTRY_CHAN(NULL);
2963 /* check if there's an available synthesis process */
2964 for (i = 0; i < synth->polyphony; i++) {
2965 if (_AVAILABLE(synth->voice[i])) {
2966 voice = synth->voice[i];
2971 /* No success yet? Then stop a running voice. */
2972 if (voice == NULL) {
2973 FLUID_LOG(FLUID_DBG, "Polyphony exceeded, trying to kill a voice");
2974 voice = fluid_synth_free_voice_by_kill_LOCAL(synth);
2977 if (voice == NULL) {
2978 FLUID_LOG(FLUID_WARN, "Failed to allocate a synthesis process. (chan=%d,key=%d)", chan, key);
2979 FLUID_API_RETURN(NULL);
2981 ticks = fluid_synth_get_ticks(synth);
2983 if (synth->verbose) {
2985 for (i = 0; i < synth->polyphony; i++) {
2986 if (!_AVAILABLE(synth->voice[i])) {
2991 FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d",
2992 chan, key, vel, synth->storeid,
2993 (float) ticks / 44100.0f,
2994 (fluid_curtime() - synth->start) / 1000.0f,
3000 channel = synth->channel[chan];
3003 if (fluid_voice_init (voice, sample, channel, key, vel,
3004 synth->storeid, ticks, synth->gain) != FLUID_OK) {
3005 FLUID_LOG(FLUID_WARN, "Failed to initialize voice");
3006 FLUID_API_RETURN(NULL);
3009 /* add the default modulators to the synthesis process. */
3010 fluid_voice_add_mod(voice, &default_vel2att_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.1 */
3011 fluid_voice_add_mod(voice, &default_vel2filter_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.2 */
3012 fluid_voice_add_mod(voice, &default_at2viblfo_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.3 */
3013 fluid_voice_add_mod(voice, &default_mod2viblfo_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.4 */
3014 fluid_voice_add_mod(voice, &default_att_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.5 */
3015 fluid_voice_add_mod(voice, &default_pan_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.6 */
3016 fluid_voice_add_mod(voice, &default_expr_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.7 */
3017 fluid_voice_add_mod(voice, &default_reverb_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.8 */
3018 fluid_voice_add_mod(voice, &default_chorus_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.9 */
3019 fluid_voice_add_mod(voice, &default_pitch_bend_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.10 */
3021 FLUID_API_RETURN(voice);
3024 /* Kill all voices on a given channel, which have the same exclusive class
3025 * generator as new_voice.
3028 fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t* synth,
3029 fluid_voice_t* new_voice)
3031 int excl_class = _GEN(new_voice,GEN_EXCLUSIVECLASS);
3032 fluid_voice_t* existing_voice;
3035 /* Excl. class 0: No exclusive class */
3036 if (excl_class == 0) return;
3038 /* Kill all notes on the same channel with the same exclusive class */
3039 for (i = 0; i < synth->polyphony; i++) {
3040 existing_voice = synth->voice[i];
3042 /* If voice is playing, on the same channel, has same exclusive
3043 * class and is not part of the same noteon event (voice group), then kill it */
3045 if (_PLAYING(existing_voice)
3046 && existing_voice->chan == new_voice->chan
3047 && (int)_GEN (existing_voice, GEN_EXCLUSIVECLASS) == excl_class
3048 && fluid_voice_get_id (existing_voice) != fluid_voice_get_id(new_voice))
3049 fluid_voice_kill_excl(existing_voice);
3054 * Activate a voice previously allocated with fluid_synth_alloc_voice().
3055 * @param synth FluidSynth instance
3056 * @param voice Voice to activate
3058 * This function is called by a SoundFont's preset in response to a noteon
3059 * event. Exclusive classes are processed here.
3061 * NOTE: Should only be called from within synthesis thread, which includes
3062 * SoundFont loader preset noteon method.
3065 fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
3067 fluid_return_if_fail (synth != NULL);
3068 fluid_return_if_fail (voice != NULL);
3069 // fluid_return_if_fail (fluid_synth_is_synth_thread (synth));
3070 fluid_synth_api_enter(synth);
3072 /* Find the exclusive class of this voice. If set, kill all voices
3073 * that match the exclusive class and are younger than the first
3074 * voice process created by this noteon event. */
3075 fluid_synth_kill_by_exclusive_class_LOCAL(synth, voice);
3077 fluid_voice_start(voice); /* Start the new voice */
3078 if (synth->eventhandler->is_threadsafe)
3079 fluid_voice_lock_rvoice(voice);
3080 fluid_rvoice_eventhandler_add_rvoice(synth->eventhandler, voice->rvoice);
3081 fluid_synth_api_exit(synth);
3085 * Add a SoundFont loader interface.
3086 * @param synth FluidSynth instance
3087 * @param loader Loader API structure, used directly and should remain allocated
3088 * as long as the synth instance is used.
3090 * SoundFont loaders are used to add custom instrument loading to FluidSynth.
3091 * The caller supplied functions for loading files, allocating presets,
3092 * retrieving information on them and synthesizing note-on events. Using this
3093 * method even non SoundFont instruments can be synthesized, although limited
3094 * to the SoundFont synthesis model.
3096 * NOTE: Should only be called before any SoundFont files are loaded.
3099 fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader)
3101 gboolean sfont_already_loaded;
3103 fluid_return_if_fail (synth != NULL);
3104 fluid_return_if_fail (loader != NULL);
3105 fluid_synth_api_enter(synth);
3106 sfont_already_loaded = synth->sfont_info != NULL;
3107 if (!sfont_already_loaded)
3108 synth->loaders = fluid_list_prepend(synth->loaders, loader);
3109 fluid_synth_api_exit(synth);
3113 * Load a SoundFont file (filename is interpreted by SoundFont loaders).
3114 * The newly loaded SoundFont will be put on top of the SoundFont
3115 * stack. Presets are searched starting from the SoundFont on the
3116 * top of the stack, working the way down the stack until a preset is found.
3118 * @param synth SoundFont instance
3119 * @param filename File to load
3120 * @param reset_presets TRUE to re-assign presets for all MIDI channels
3121 * @return SoundFont ID on success, FLUID_FAILED on error
3124 fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets)
3126 fluid_sfont_info_t *sfont_info;
3127 fluid_sfont_t *sfont;
3129 fluid_sfloader_t *loader;
3130 unsigned int sfont_id;
3132 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
3133 fluid_return_val_if_fail (filename != NULL, FLUID_FAILED);
3134 fluid_synth_api_enter(synth);
3136 /* MT NOTE: Loaders list should not change. */
3138 for (list = synth->loaders; list; list = fluid_list_next(list)) {
3139 loader = (fluid_sfloader_t*) fluid_list_get(list);
3141 sfont = fluid_sfloader_load(loader, filename);
3143 if (sfont != NULL) {
3144 sfont_info = new_fluid_sfont_info (synth, sfont);
3148 delete_fluid_sfont (sfont);
3149 FLUID_API_RETURN(FLUID_FAILED);
3152 sfont->id = sfont_id = ++synth->sfont_id;
3153 synth->sfont_info = fluid_list_prepend(synth->sfont_info, sfont_info); /* prepend to list */
3154 fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
3156 /* reset the presets for all channels if requested */
3157 if (reset_presets) fluid_synth_program_reset(synth);
3159 FLUID_API_RETURN((int)sfont_id);
3163 FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename);
3164 FLUID_API_RETURN(FLUID_FAILED);
3167 /* Create a new SoundFont info structure, free with FLUID_FREE */
3168 static fluid_sfont_info_t *
3169 new_fluid_sfont_info (fluid_synth_t *synth, fluid_sfont_t *sfont)
3171 fluid_sfont_info_t *sfont_info;
3173 sfont_info = FLUID_NEW (fluid_sfont_info_t);
3177 FLUID_LOG(FLUID_ERR, "Out of memory");
3181 sfont_info->sfont = sfont;
3182 sfont_info->synth = synth;
3183 sfont_info->refcount = 1; /* Start with refcount of 1 for owning synth */
3184 sfont_info->bankofs = 0;
3186 return (sfont_info);
3190 * Unload a SoundFont.
3191 * @param synth SoundFont instance
3192 * @param id ID of SoundFont to unload
3193 * @param reset_presets TRUE to re-assign presets for all MIDI channels
3194 * @return FLUID_OK on success, FLUID_FAILED on error
3197 fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets)
3199 fluid_sfont_info_t *sfont_info = NULL;
3202 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
3203 fluid_synth_api_enter(synth);
3205 /* remove the SoundFont from the list */
3206 for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
3207 sfont_info = (fluid_sfont_info_t*) fluid_list_get(list);
3209 if (fluid_sfont_get_id (sfont_info->sfont) == id)
3211 synth->sfont_info = fluid_list_remove (synth->sfont_info, sfont_info);
3217 FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
3218 FLUID_API_RETURN(FLUID_FAILED);
3221 /* reset the presets for all channels (SoundFont will be freed when there are no more references) */
3222 if (reset_presets) fluid_synth_program_reset (synth);
3223 else fluid_synth_update_presets (synth);
3225 /* -- Remove synth->sfont_info list's reference to SoundFont */
3226 fluid_synth_sfont_unref (synth, sfont_info->sfont);
3228 FLUID_API_RETURN(FLUID_OK);
3231 /* Unref a SoundFont and destroy if no more references */
3233 fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont)
3235 fluid_sfont_info_t *sfont_info;
3238 sfont_info = fluid_hashtable_lookup (synth->sfont_hash, sfont);
3242 sfont_info->refcount--; /* -- Remove the sfont_info list's reference */
3243 refcount = sfont_info->refcount;
3245 if (refcount == 0) /* Remove SoundFont from hash if no more references */
3246 fluid_hashtable_remove (synth->sfont_hash, sfont_info->sfont);
3249 fluid_return_if_fail (sfont_info != NULL); /* Shouldn't happen, programming error if so */
3251 if (refcount == 0) /* No more references? - Attempt delete */
3253 if (delete_fluid_sfont (sfont_info->sfont) == 0) /* SoundFont loader can block SoundFont unload */
3255 FLUID_FREE (sfont_info);
3256 FLUID_LOG (FLUID_DBG, "Unloaded SoundFont");
3257 } /* spin off a timer thread to unload the sfont later (SoundFont loader blocked unload) */
3258 else new_fluid_timer (100, fluid_synth_sfunload_callback, sfont_info, TRUE, TRUE, FALSE);
3262 /* Callback to continually attempt to unload a SoundFont,
3263 * only if a SoundFont loader blocked the unload operation */
3265 fluid_synth_sfunload_callback(void* data, unsigned int msec)
3267 fluid_sfont_info_t *sfont_info = (fluid_sfont_info_t *)data;
3269 if (delete_fluid_sfont (sfont_info->sfont) == 0)
3271 FLUID_FREE (sfont_info);
3272 FLUID_LOG (FLUID_DBG, "Unloaded SoundFont");
3279 * Reload a SoundFont. The SoundFont retains its ID and index on the SoundFont stack.
3280 * @param synth SoundFont instance
3281 * @param id ID of SoundFont to reload
3282 * @return SoundFont ID on success, FLUID_FAILED on error
3285 fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id)
3287 char filename[1024];
3288 fluid_sfont_info_t *sfont_info, *old_sfont_info;
3289 fluid_sfont_t* sfont;
3290 fluid_sfloader_t* loader;
3294 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
3295 fluid_synth_api_enter(synth);
3297 /* Search for SoundFont and get its index */
3298 for (list = synth->sfont_info, index = 0; list; list = fluid_list_next (list), index++) {
3299 old_sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
3300 if (fluid_sfont_get_id (old_sfont_info->sfont) == id) break;
3304 FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
3305 FLUID_API_RETURN(FLUID_FAILED);
3308 /* keep a copy of the SoundFont's filename */
3309 FLUID_STRCPY (filename, fluid_sfont_get_name (old_sfont_info->sfont));
3311 if (fluid_synth_sfunload (synth, id, FALSE) != FLUID_OK)
3312 FLUID_API_RETURN(FLUID_FAILED);
3314 /* MT Note: SoundFont loader list will not change */
3316 for (list = synth->loaders; list; list = fluid_list_next(list)) {
3317 loader = (fluid_sfloader_t*) fluid_list_get(list);
3319 sfont = fluid_sfloader_load(loader, filename);
3321 if (sfont != NULL) {
3324 sfont_info = new_fluid_sfont_info (synth, sfont);
3328 delete_fluid_sfont (sfont);
3329 FLUID_API_RETURN(FLUID_FAILED);
3332 synth->sfont_info = fluid_list_insert_at(synth->sfont_info, index, sfont_info); /* insert the sfont at the same index */
3333 fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
3335 /* reset the presets for all channels */
3336 fluid_synth_update_presets(synth);
3337 FLUID_API_RETURN(sfont->id);
3341 FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename);
3342 FLUID_API_RETURN(FLUID_FAILED);
3346 * Add a SoundFont. The SoundFont will be added to the top of the SoundFont stack.
3347 * @param synth FluidSynth instance
3348 * @param sfont SoundFont to add
3349 * @return New assigned SoundFont ID or FLUID_FAILED on error
3352 fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
3354 fluid_sfont_info_t *sfont_info;
3355 unsigned int sfont_id;
3357 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
3358 fluid_return_val_if_fail (sfont != NULL, FLUID_FAILED);
3359 fluid_synth_api_enter(synth);
3361 sfont_info = new_fluid_sfont_info (synth, sfont);
3363 FLUID_API_RETURN(FLUID_FAILED);
3365 sfont->id = sfont_id = ++synth->sfont_id;
3366 synth->sfont_info = fluid_list_prepend (synth->sfont_info, sfont_info); /* prepend to list */
3367 fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
3369 /* reset the presets for all channels */
3370 fluid_synth_program_reset (synth);
3372 FLUID_API_RETURN(sfont_id);
3376 * Remove a SoundFont from the SoundFont stack without deleting it.
3377 * @param synth FluidSynth instance
3378 * @param sfont SoundFont to remove
3380 * SoundFont is not freed and is left as the responsibility of the caller.
3382 * NOTE: The SoundFont should only be freed after there are no presets
3383 * referencing it. This can only be ensured by the SoundFont loader and
3384 * therefore this function should not normally be used.
3387 fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
3389 fluid_sfont_info_t *sfont_info;
3392 fluid_return_if_fail (synth != NULL);
3393 fluid_return_if_fail (sfont != NULL);
3394 fluid_synth_api_enter(synth);
3396 /* remove the SoundFont from the list */
3397 for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
3398 sfont_info = (fluid_sfont_info_t*) fluid_list_get(list);
3400 if (sfont_info->sfont == sfont)
3402 synth->sfont_info = fluid_list_remove (synth->sfont_info, sfont_info);
3404 /* Remove from SoundFont hash regardless of refcount (SoundFont delete is up to caller) */
3405 fluid_hashtable_remove (synth->sfont_hash, sfont_info->sfont);
3410 /* reset the presets for all channels */
3411 fluid_synth_program_reset (synth);
3412 fluid_synth_api_exit(synth);
3416 * Count number of loaded SoundFont files.
3417 * @param synth FluidSynth instance
3418 * @return Count of loaded SoundFont files.
3421 fluid_synth_sfcount(fluid_synth_t* synth)
3425 fluid_return_val_if_fail (synth != NULL, 0);
3426 fluid_synth_api_enter(synth);
3427 count = fluid_list_size (synth->sfont_info);
3428 FLUID_API_RETURN(count);
3432 * Get SoundFont by index.
3433 * @param synth FluidSynth instance
3434 * @param num SoundFont index on the stack (starting from 0 for top of stack).
3435 * @return SoundFont instance or NULL if invalid index
3437 * NOTE: Caller should be certain that SoundFont is not deleted (unloaded) for
3438 * the duration of use of the returned pointer.
3441 fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num)
3443 fluid_sfont_t *sfont = NULL;
3446 fluid_return_val_if_fail (synth != NULL, NULL);
3447 fluid_synth_api_enter(synth);
3448 list = fluid_list_nth (synth->sfont_info, num);
3449 if (list) sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
3450 FLUID_API_RETURN(sfont);
3454 * Get SoundFont by ID.
3455 * @param synth FluidSynth instance
3456 * @param id SoundFont ID
3457 * @return SoundFont instance or NULL if invalid ID
3459 * NOTE: Caller should be certain that SoundFont is not deleted (unloaded) for
3460 * the duration of use of the returned pointer.
3463 fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id)
3465 fluid_sfont_t* sfont = NULL;
3468 fluid_return_val_if_fail (synth != NULL, NULL);
3469 fluid_synth_api_enter(synth);
3471 for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
3472 sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
3473 if (fluid_sfont_get_id (sfont) == id)
3477 FLUID_API_RETURN(list ? sfont : NULL);
3481 * Get SoundFont by name.
3482 * @param synth FluidSynth instance
3483 * @param name Name of SoundFont
3484 * @return SoundFont instance or NULL if invalid name
3487 * NOTE: Caller should be certain that SoundFont is not deleted (unloaded) for
3488 * the duration of use of the returned pointer.
3491 fluid_synth_get_sfont_by_name(fluid_synth_t* synth, const char *name)
3493 fluid_sfont_t* sfont = NULL;
3496 fluid_return_val_if_fail (synth != NULL, NULL);
3497 fluid_return_val_if_fail (name != NULL, NULL);
3498 fluid_synth_api_enter(synth);
3500 for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
3501 sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
3502 if (FLUID_STRCMP(fluid_sfont_get_name(sfont), name) == 0)
3506 FLUID_API_RETURN(list ? sfont : NULL);
3510 * Get active preset on a MIDI channel.
3511 * @param synth FluidSynth instance
3512 * @param chan MIDI channel number (0 to MIDI channel count - 1)
3513 * @return Preset or NULL if no preset active on channel
3514 * @deprecated fluid_synth_get_channel_info() should replace most use cases.
3516 * NOTE: Should only be called from within synthesis thread, which includes
3517 * SoundFont loader preset noteon methods. Not thread safe otherwise.
3520 fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan)
3522 fluid_preset_t* result;
3523 fluid_channel_t *channel;
3524 FLUID_API_ENTRY_CHAN(NULL);
3526 channel = synth->channel[chan];
3527 result = channel->preset;
3528 fluid_synth_api_exit(synth);
3533 * Get information on the currently selected preset on a MIDI channel.
3534 * @param synth FluidSynth instance
3535 * @param chan MIDI channel number (0 to MIDI channel count - 1)
3536 * @param info Caller supplied structure to fill with preset information
3537 * @return #FLUID_OK on success, #FLUID_FAILED otherwise
3541 fluid_synth_get_channel_info (fluid_synth_t *synth, int chan,
3542 fluid_synth_channel_info_t *info)
3544 fluid_channel_t *channel;
3545 fluid_preset_t *preset;
3550 info->assigned = FALSE;
3551 info->name[0] = '\0';
3554 fluid_return_val_if_fail (info != NULL, FLUID_FAILED);
3555 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
3557 channel = synth->channel[chan];
3558 preset = channel->preset;
3562 info->assigned = TRUE;
3563 name = fluid_preset_get_name (preset);
3567 strncpy (info->name, name, FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE);
3568 info->name[FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE - 1] = '\0';
3570 else info->name[0] = '\0';
3572 info->sfont_id = preset->sfont->id;
3573 info->bank = fluid_preset_get_banknum (preset);
3574 info->program = fluid_preset_get_num (preset);
3578 info->assigned = FALSE;
3579 fluid_channel_get_sfont_bank_prog (channel, &info->sfont_id, &info->bank, &info->program);
3580 info->name[0] = '\0';
3583 fluid_synth_api_exit(synth);
3588 * Get list of voices.
3589 * @param synth FluidSynth instance
3590 * @param buf Array to store voices to (NULL terminated if not filled completely)
3591 * @param bufsize Count of indexes in buf
3592 * @param id Voice ID to search for or < 0 to return list of all playing voices
3594 * NOTE: Should only be called from within synthesis thread, which includes
3595 * SoundFont loader preset noteon methods. Voices are only guaranteed to remain
3596 * unchanged until next synthesis process iteration.
3599 fluid_synth_get_voicelist(fluid_synth_t* synth, fluid_voice_t* buf[], int bufsize,
3605 fluid_return_if_fail (synth != NULL);
3606 fluid_return_if_fail (buf != NULL);
3607 fluid_synth_api_enter(synth);
3609 for (i = 0; i < synth->polyphony && count < bufsize; i++) {
3610 fluid_voice_t* voice = synth->voice[i];
3612 if (_PLAYING(voice) && (id < 0 || (int)voice->id == id))
3613 buf[count++] = voice;
3616 if (count < bufsize) buf[count] = NULL;
3617 fluid_synth_api_exit(synth);
3621 * Enable or disable reverb effect.
3622 * @param synth FluidSynth instance
3623 * @param on TRUE to enable reverb, FALSE to disable
3626 fluid_synth_set_reverb_on(fluid_synth_t* synth, int on)
3628 fluid_return_if_fail (synth != NULL);
3630 fluid_atomic_int_set (&synth->with_reverb, on != 0);
3631 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_reverb_enabled,
3636 * Activate a reverb preset.
3637 * @param synth FluidSynth instance
3638 * @param num Reverb preset number
3639 * @return FLUID_OK on success, FLUID_FAILED otherwise
3641 * NOTE: Currently private to libfluidsynth.
3644 fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num)
3647 while (revmodel_preset[i].name != NULL) {
3649 fluid_synth_set_reverb (synth, revmodel_preset[i].roomsize,
3650 revmodel_preset[i].damp, revmodel_preset[i].width,
3651 revmodel_preset[i].level);
3656 return FLUID_FAILED;
3660 * Set reverb parameters.
3661 * @param synth FluidSynth instance
3662 * @param roomsize Reverb room size value (0.0-1.2)
3663 * @param damping Reverb damping value (0.0-1.0)
3664 * @param width Reverb width value (0.0-100.0)
3665 * @param level Reverb level value (0.0-1.0)
3667 * NOTE: Not realtime safe and therefore should not be called from synthesis
3668 * context at the risk of stalling audio output.
3671 fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double damping,
3672 double width, double level)
3674 fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_ALL,
3675 roomsize, damping, width, level);
3679 * Set one or more reverb parameters.
3680 * @param synth FluidSynth instance
3681 * @param set Flags indicating which parameters should be set (#fluid_revmodel_set_t)
3682 * @param roomsize Reverb room size value (0.0-1.2)
3683 * @param damping Reverb damping value (0.0-1.0)
3684 * @param width Reverb width value (0.0-100.0)
3685 * @param level Reverb level value (0.0-1.0)
3686 * @return FLUID_OK on success, FLUID_FAILED otherwise
3688 * NOTE: Not realtime safe and therefore should not be called from synthesis
3689 * context at the risk of stalling audio output.
3692 fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
3693 double damping, double width, double level)
3695 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
3697 if (!(set & FLUID_REVMODEL_SET_ALL))
3698 set = FLUID_REVMODEL_SET_ALL;
3700 /* Synth shadow values are set here so that they will be returned if querried */
3702 fluid_synth_api_enter(synth);
3704 if (set & FLUID_REVMODEL_SET_ROOMSIZE)
3705 fluid_atomic_float_set (&synth->reverb_roomsize, roomsize);
3707 if (set & FLUID_REVMODEL_SET_DAMPING)
3708 fluid_atomic_float_set (&synth->reverb_damping, damping);
3710 if (set & FLUID_REVMODEL_SET_WIDTH)
3711 fluid_atomic_float_set (&synth->reverb_width, width);
3713 if (set & FLUID_REVMODEL_SET_LEVEL)
3714 fluid_atomic_float_set (&synth->reverb_level, level);
3716 fluid_rvoice_eventhandler_push5(synth->eventhandler,
3717 fluid_rvoice_mixer_set_reverb_params,
3718 synth->eventhandler->mixer, set,
3719 roomsize, damping, width, level, 0.0f);
3721 FLUID_API_RETURN(FLUID_OK);
3725 * Get reverb room size.
3726 * @param synth FluidSynth instance
3727 * @return Reverb room size (0.0-1.2)
3730 fluid_synth_get_reverb_roomsize(fluid_synth_t* synth)
3733 fluid_return_val_if_fail (synth != NULL, 0.0);
3734 fluid_synth_api_enter(synth);
3735 result = fluid_atomic_float_get (&synth->reverb_roomsize);
3736 FLUID_API_RETURN(result);
3740 * Get reverb damping.
3741 * @param synth FluidSynth instance
3742 * @return Reverb damping value (0.0-1.0)
3745 fluid_synth_get_reverb_damp(fluid_synth_t* synth)
3748 fluid_return_val_if_fail (synth != NULL, 0.0);
3749 fluid_synth_api_enter(synth);
3751 result = fluid_atomic_float_get (&synth->reverb_damping);
3752 FLUID_API_RETURN(result);
3757 * @param synth FluidSynth instance
3758 * @return Reverb level value (0.0-1.0)
3761 fluid_synth_get_reverb_level(fluid_synth_t* synth)
3764 fluid_return_val_if_fail (synth != NULL, 0.0);
3765 fluid_synth_api_enter(synth);
3767 result = fluid_atomic_float_get (&synth->reverb_level);
3768 FLUID_API_RETURN(result);
3773 * @param synth FluidSynth instance
3774 * @return Reverb width value (0.0-100.0)
3777 fluid_synth_get_reverb_width(fluid_synth_t* synth)
3780 fluid_return_val_if_fail (synth != NULL, 0.0);
3781 fluid_synth_api_enter(synth);
3783 result = fluid_atomic_float_get (&synth->reverb_width);
3784 FLUID_API_RETURN(result);
3788 * Enable or disable chorus effect.
3789 * @param synth FluidSynth instance
3790 * @param on TRUE to enable chorus, FALSE to disable
3793 fluid_synth_set_chorus_on(fluid_synth_t* synth, int on)
3795 fluid_return_if_fail (synth != NULL);
3796 fluid_synth_api_enter(synth);
3798 fluid_atomic_int_set (&synth->with_chorus, on != 0);
3799 fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_chorus_enabled,
3801 fluid_synth_api_exit(synth);
3805 * Set chorus parameters.
3806 * @param synth FluidSynth instance
3807 * @param nr Chorus voice count (0-99, CPU time consumption proportional to
3809 * @param level Chorus level (0.0-10.0)
3810 * @param speed Chorus speed in Hz (0.29-5.0)
3811 * @param depth_ms Chorus depth (max value depends on synth sample rate,
3812 * 0.0-21.0 is safe for sample rate values up to 96KHz)
3813 * @param type Chorus waveform type (#fluid_chorus_mod)
3816 fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
3817 double speed, double depth_ms, int type)
3819 fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_ALL, nr, level, speed,
3824 * Set one or more chorus parameters.
3825 * @param synth FluidSynth instance
3826 * @param set Flags indicating which chorus parameters to set (#fluid_chorus_set_t)
3827 * @param nr Chorus voice count (0-99, CPU time consumption proportional to
3829 * @param level Chorus level (0.0-10.0)
3830 * @param speed Chorus speed in Hz (0.29-5.0)
3831 * @param depth_ms Chorus depth (max value depends on synth sample rate,
3832 * 0.0-21.0 is safe for sample rate values up to 96KHz)
3833 * @param type Chorus waveform type (#fluid_chorus_mod)
3836 fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
3837 double speed, double depth_ms, int type)
3839 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
3841 if (!(set & FLUID_CHORUS_SET_ALL))
3842 set = FLUID_CHORUS_SET_ALL;
3844 /* Synth shadow values are set here so that they will be returned if queried */
3845 fluid_synth_api_enter(synth);
3847 if (set & FLUID_CHORUS_SET_NR)
3848 fluid_atomic_int_set (&synth->chorus_nr, nr);
3850 if (set & FLUID_CHORUS_SET_LEVEL)
3851 fluid_atomic_float_set (&synth->chorus_level, level);
3853 if (set & FLUID_CHORUS_SET_SPEED)
3854 fluid_atomic_float_set (&synth->chorus_speed, speed);
3856 if (set & FLUID_CHORUS_SET_DEPTH)
3857 fluid_atomic_float_set (&synth->chorus_depth, depth_ms);
3859 if (set & FLUID_CHORUS_SET_TYPE)
3860 fluid_atomic_int_set (&synth->chorus_type, type);
3862 fluid_rvoice_eventhandler_push5(synth->eventhandler,
3863 fluid_rvoice_mixer_set_chorus_params,
3864 synth->eventhandler->mixer, set,
3865 nr, level, speed, depth_ms, type);
3867 FLUID_API_RETURN(FLUID_OK);
3871 * Get chorus voice number (delay line count) value.
3872 * @param synth FluidSynth instance
3873 * @return Chorus voice count (0-99)
3876 fluid_synth_get_chorus_nr(fluid_synth_t* synth)
3879 fluid_return_val_if_fail (synth != NULL, 0.0);
3880 fluid_synth_api_enter(synth);
3882 result = fluid_atomic_int_get (&synth->chorus_nr);
3883 FLUID_API_RETURN(result);
3888 * @param synth FluidSynth instance
3889 * @return Chorus level value (0.0-10.0)
3892 fluid_synth_get_chorus_level(fluid_synth_t* synth)
3895 fluid_return_val_if_fail (synth != NULL, 0.0);
3896 fluid_synth_api_enter(synth);
3898 result = fluid_atomic_float_get (&synth->chorus_level);
3899 FLUID_API_RETURN(result);
3903 * Get chorus speed in Hz.
3904 * @param synth FluidSynth instance
3905 * @return Chorus speed in Hz (0.29-5.0)
3908 fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth)
3911 fluid_return_val_if_fail (synth != NULL, 0.0);
3912 fluid_synth_api_enter(synth);
3914 result = fluid_atomic_float_get (&synth->chorus_speed);
3915 FLUID_API_RETURN(result);
3920 * @param synth FluidSynth instance
3921 * @return Chorus depth
3924 fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth)
3927 fluid_return_val_if_fail (synth != NULL, 0.0);
3928 fluid_synth_api_enter(synth);
3930 result = fluid_atomic_float_get (&synth->chorus_depth);
3931 FLUID_API_RETURN(result);
3935 * Get chorus waveform type.
3936 * @param synth FluidSynth instance
3937 * @return Chorus waveform type (#fluid_chorus_mod)
3940 fluid_synth_get_chorus_type(fluid_synth_t* synth)
3943 fluid_return_val_if_fail (synth != NULL, 0.0);
3944 fluid_synth_api_enter(synth);
3946 result = fluid_atomic_int_get (&synth->chorus_type);
3947 FLUID_API_RETURN(result);
3951 * If the same note is hit twice on the same channel, then the older
3952 * voice process is advanced to the release stage. Using a mechanical
3953 * MIDI controller, the only way this can happen is when the sustain
3954 * pedal is held. In this case the behaviour implemented here is
3955 * natural for many instruments. Note: One noteon event can trigger
3956 * several voice processes, for example a stereo sample. Don't
3960 fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth, int chan,
3964 fluid_voice_t* voice;
3966 synth->storeid = synth->noteid++;
3968 for (i = 0; i < synth->polyphony; i++) {
3969 voice = synth->voice[i];
3971 && (voice->chan == chan)
3972 && (voice->key == key)
3973 && (fluid_voice_get_id(voice) != synth->noteid)) {
3974 /* Id of voices that was sustained by sostenuto */
3975 if(_HELD_BY_SOSTENUTO(voice))
3976 synth->storeid = voice->id;
3977 /* Force the voice into release stage (pedaling is ignored) */
3978 fluid_voice_release(voice);
3984 * Set synthesis interpolation method on one or all MIDI channels.
3985 * @param synth FluidSynth instance
3986 * @param chan MIDI channel to set interpolation method on or -1 for all channels
3987 * @param interp_method Interpolation method (#fluid_interp)
3988 * @return FLUID_OK on success, FLUID_FAILED otherwise
3991 fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method)
3995 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
3996 fluid_synth_api_enter(synth);
3997 if (chan < -1 || chan >= synth->midi_channels)
3998 FLUID_API_RETURN(FLUID_FAILED);
4000 if (synth->channel[0] == NULL) {
4001 FLUID_LOG (FLUID_ERR, "Channels don't exist (yet)!");
4002 FLUID_API_RETURN(FLUID_FAILED);
4005 for (i = 0; i < synth->midi_channels; i++) {
4006 if (chan < 0 || fluid_channel_get_num(synth->channel[i]) == chan)
4007 fluid_channel_set_interp_method(synth->channel[i], interp_method);
4010 FLUID_API_RETURN(FLUID_OK);
4014 * Get the total count of MIDI channels.
4015 * @param synth FluidSynth instance
4016 * @return Count of MIDI channels
4019 fluid_synth_count_midi_channels(fluid_synth_t* synth)
4022 fluid_return_val_if_fail (synth != NULL, 0);
4023 fluid_synth_api_enter(synth);
4025 result = synth->midi_channels;
4026 FLUID_API_RETURN(result);
4030 * Get the total count of audio channels.
4031 * @param synth FluidSynth instance
4032 * @return Count of audio channel stereo pairs (1 = 2 channels, 2 = 4, etc)
4035 fluid_synth_count_audio_channels(fluid_synth_t* synth)
4038 fluid_return_val_if_fail (synth != NULL, 0);
4039 fluid_synth_api_enter(synth);
4041 result = synth->audio_channels;
4042 FLUID_API_RETURN(result);
4046 * Get the total number of allocated audio channels. Usually identical to the
4047 * number of audio channels. Can be employed by LADSPA effects subsystem.
4049 * @param synth FluidSynth instance
4050 * @return Count of audio group stereo pairs (1 = 2 channels, 2 = 4, etc)
4053 fluid_synth_count_audio_groups(fluid_synth_t* synth)
4056 fluid_return_val_if_fail (synth != NULL, 0);
4057 fluid_synth_api_enter(synth);
4059 result = synth->audio_groups;
4060 FLUID_API_RETURN(result);
4064 * Get the total number of allocated effects channels.
4065 * @param synth FluidSynth instance
4066 * @return Count of allocated effects channels
4069 fluid_synth_count_effects_channels(fluid_synth_t* synth)
4072 fluid_return_val_if_fail (synth != NULL, 0);
4073 fluid_synth_api_enter(synth);
4075 result = synth->effects_channels;
4076 FLUID_API_RETURN(result);
4080 * Get the synth CPU load value.
4081 * @param synth FluidSynth instance
4082 * @return Estimated CPU load value in percent (0-100)
4085 fluid_synth_get_cpu_load(fluid_synth_t* synth)
4087 fluid_return_val_if_fail (synth != NULL, 0);
4088 return fluid_atomic_float_get (&synth->cpu_load);
4091 /* Get tuning for a given bank:program */
4092 static fluid_tuning_t *
4093 fluid_synth_get_tuning(fluid_synth_t* synth, int bank, int prog)
4096 if ((synth->tuning == NULL) ||
4097 (synth->tuning[bank] == NULL) ||
4098 (synth->tuning[bank][prog] == NULL))
4101 return synth->tuning[bank][prog];
4104 /* Replace tuning on a given bank:program (need not already exist).
4105 * Synth mutex should already be locked by caller. */
4107 fluid_synth_replace_tuning_LOCK (fluid_synth_t* synth, fluid_tuning_t *tuning,
4108 int bank, int prog, int apply)
4110 fluid_tuning_t *old_tuning;
4111 // fluid_event_queue_t *queue;
4112 // fluid_event_queue_elem_t *event;
4114 if (synth->tuning == NULL) {
4115 synth->tuning = FLUID_ARRAY(fluid_tuning_t**, 128);
4116 if (synth->tuning == NULL) {
4117 FLUID_LOG(FLUID_PANIC, "Out of memory");
4118 return FLUID_FAILED;
4120 FLUID_MEMSET(synth->tuning, 0, 128 * sizeof(fluid_tuning_t**));
4123 if (synth->tuning[bank] == NULL) {
4124 synth->tuning[bank] = FLUID_ARRAY(fluid_tuning_t*, 128);
4125 if (synth->tuning[bank] == NULL) {
4126 FLUID_LOG(FLUID_PANIC, "Out of memory");
4127 return FLUID_FAILED;
4129 FLUID_MEMSET(synth->tuning[bank], 0, 128 * sizeof(fluid_tuning_t*));
4132 old_tuning = synth->tuning[bank][prog];
4133 synth->tuning[bank][prog] = tuning;
4136 if (!fluid_tuning_unref (old_tuning, 1)) /* -- unref old tuning */
4137 { /* Replace old tuning if present */
4138 fluid_synth_replace_tuning_LOCAL (synth, old_tuning, tuning, apply, FALSE);
4145 /* Replace a tuning with a new one in all MIDI channels. new_tuning can be
4146 * NULL, in which case channels are reset to default equal tempered scale. */
4148 fluid_synth_replace_tuning_LOCAL (fluid_synth_t *synth, fluid_tuning_t *old_tuning,
4149 fluid_tuning_t *new_tuning, int apply, int unref_new)
4151 // fluid_event_queue_elem_t *event;
4152 fluid_channel_t *channel;
4153 int old_tuning_unref = 0;
4156 for (i = 0; i < synth->midi_channels; i++)
4158 channel = synth->channel[i];
4160 if (fluid_channel_get_tuning (channel) == old_tuning)
4163 if (new_tuning) fluid_tuning_ref (new_tuning); /* ++ ref new tuning for channel */
4164 fluid_channel_set_tuning (channel, new_tuning);
4166 if (apply) fluid_synth_update_voice_tuning_LOCAL (synth, channel);
4170 /* Send unref old tuning event if any unrefs */
4171 if (old_tuning && old_tuning_unref)
4172 fluid_tuning_unref (old_tuning, old_tuning_unref);
4173 if (!unref_new || !new_tuning) return;
4175 fluid_tuning_unref (new_tuning, 1);
4178 /* Update voice tunings in realtime */
4180 fluid_synth_update_voice_tuning_LOCAL (fluid_synth_t *synth, fluid_channel_t *channel)
4182 fluid_voice_t *voice;
4185 for (i = 0; i < synth->polyphony; i++)
4187 voice = synth->voice[i];
4189 if (_ON (voice) && (voice->channel == channel))
4191 fluid_voice_calculate_gen_pitch (voice);
4192 fluid_voice_update_param (voice, GEN_PITCH);
4198 * Set the tuning of the entire MIDI note scale.
4199 * @param synth FluidSynth instance
4200 * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
4201 * @param prog Tuning preset number (0-127), not related to MIDI instrument program
4202 * @param name Label name for this tuning
4203 * @param pitch Array of pitch values (length of 128, each value is number of
4204 * cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc).
4205 * Pass NULL to create a well-tempered (normal) scale.
4206 * @return FLUID_OK on success, FLUID_FAILED otherwise
4208 * NOTE: Tuning is not applied in realtime to existing notes of the replaced
4209 * tuning (if any), use fluid_synth_activate_key_tuning() instead to specify
4213 fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
4214 const char* name, const double* pitch)
4216 return fluid_synth_activate_key_tuning (synth, bank, prog, name, pitch, FALSE);
4220 * Set the tuning of the entire MIDI note scale.
4221 * @param synth FluidSynth instance
4222 * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
4223 * @param prog Tuning preset number (0-127), not related to MIDI instrument program
4224 * @param name Label name for this tuning
4225 * @param pitch Array of pitch values (length of 128, each value is number of
4226 * cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc).
4227 * Pass NULL to create a well-tempered (normal) scale.
4228 * @param apply TRUE to apply new tuning in realtime to existing notes which
4229 * are using the replaced tuning (if any), FALSE otherwise
4230 * @return FLUID_OK on success, FLUID_FAILED otherwise
4234 fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
4235 const char* name, const double* pitch, int apply)
4237 fluid_tuning_t* tuning;
4238 int retval = FLUID_OK;
4240 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4241 fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
4242 fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
4243 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4245 fluid_synth_api_enter(synth);
4247 tuning = new_fluid_tuning (name, bank, prog);
4251 if (pitch) fluid_tuning_set_all (tuning, pitch);
4252 retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, apply);
4253 if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
4255 else retval = FLUID_FAILED;
4256 FLUID_API_RETURN(retval);
4260 * Apply an octave tuning to every octave in the MIDI note scale.
4261 * @param synth FluidSynth instance
4262 * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
4263 * @param prog Tuning preset number (0-127), not related to MIDI instrument program
4264 * @param name Label name for this tuning
4265 * @param pitch Array of pitch values (length of 12 for each note of an octave
4266 * starting at note C, values are number of offset cents to add to the normal
4268 * @return FLUID_OK on success, FLUID_FAILED otherwise
4270 * NOTE: Tuning is not applied in realtime to existing notes of the replaced
4271 * tuning (if any), use fluid_synth_activate_octave_tuning() instead to specify
4275 fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
4276 const char* name, const double* pitch)
4278 return fluid_synth_activate_octave_tuning (synth, bank, prog, name, pitch, FALSE);
4282 * Activate an octave tuning on every octave in the MIDI note scale.
4283 * @param synth FluidSynth instance
4284 * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
4285 * @param prog Tuning preset number (0-127), not related to MIDI instrument program
4286 * @param name Label name for this tuning
4287 * @param pitch Array of pitch values (length of 12 for each note of an octave
4288 * starting at note C, values are number of offset cents to add to the normal
4290 * @param apply TRUE to apply new tuning in realtime to existing notes which
4291 * are using the replaced tuning (if any), FALSE otherwise
4292 * @return FLUID_OK on success, FLUID_FAILED otherwise
4296 fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
4297 const char* name, const double* pitch, int apply)
4299 fluid_tuning_t* tuning;
4300 int retval = FLUID_OK;
4302 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4303 fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
4304 fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
4305 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4306 fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
4308 fluid_synth_api_enter(synth);
4309 tuning = new_fluid_tuning (name, bank, prog);
4313 fluid_tuning_set_octave (tuning, pitch);
4314 retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, apply);
4315 if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
4317 else retval = FLUID_FAILED;
4319 FLUID_API_RETURN(retval);
4323 * Set tuning values for one or more MIDI notes for an existing tuning.
4324 * @param synth FluidSynth instance
4325 * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
4326 * @param prog Tuning preset number (0-127), not related to MIDI instrument program
4327 * @param len Number of MIDI notes to assign
4328 * @param key Array of MIDI key numbers (length of 'len', values 0-127)
4329 * @param pitch Array of pitch values (length of 'len', values are number of
4330 * cents from MIDI note 0)
4331 * @param apply TRUE to apply tuning change in realtime to existing notes using
4332 * the specified tuning, FALSE otherwise
4333 * @return FLUID_OK on success, FLUID_FAILED otherwise
4335 * NOTE: Prior to version 1.1.0 it was an error to specify a tuning that didn't
4336 * already exist. Starting with 1.1.0, the default equal tempered scale will be
4337 * used as a basis, if no tuning exists for the given bank and prog.
4340 fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
4341 int len, const int *key, const double* pitch, int apply)
4343 fluid_tuning_t* old_tuning, *new_tuning;
4344 int retval = FLUID_OK;
4347 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4348 fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
4349 fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
4350 fluid_return_val_if_fail (len > 0, FLUID_FAILED);
4351 fluid_return_val_if_fail (key != NULL, FLUID_FAILED);
4352 fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
4354 fluid_synth_api_enter(synth);
4356 old_tuning = fluid_synth_get_tuning (synth, bank, prog);
4359 new_tuning = fluid_tuning_duplicate (old_tuning);
4360 else new_tuning = new_fluid_tuning ("Unnamed", bank, prog);
4364 for (i = 0; i < len; i++)
4365 fluid_tuning_set_pitch (new_tuning, key[i], pitch[i]);
4367 retval = fluid_synth_replace_tuning_LOCK (synth, new_tuning, bank, prog, apply);
4368 if (retval == FLUID_FAILED) fluid_tuning_unref (new_tuning, 1);
4370 else retval = FLUID_FAILED;
4372 FLUID_API_RETURN(retval);
4376 * Select a tuning scale on a MIDI channel.
4377 * @param synth FluidSynth instance
4378 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4379 * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
4380 * @param prog Tuning preset number (0-127), not related to MIDI instrument program
4381 * @return FLUID_OK on success, FLUID_FAILED otherwise
4383 * NOTE: This function does NOT activate tuning in realtime, use
4384 * fluid_synth_activate_tuning() instead to specify whether tuning change
4385 * should cause existing notes to update.
4387 * NOTE: Prior to version 1.1.0 it was an error to select a tuning that didn't
4388 * already exist. Starting with 1.1.0, a default equal tempered scale will be
4389 * created, if no tuning exists for the given bank and prog.
4392 fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
4394 return fluid_synth_activate_tuning (synth, chan, bank, prog, FALSE);
4398 * Activate a tuning scale on a MIDI channel.
4399 * @param synth FluidSynth instance
4400 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4401 * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
4402 * @param prog Tuning preset number (0-127), not related to MIDI instrument program
4403 * @param apply TRUE to apply tuning change to active notes, FALSE otherwise
4404 * @return FLUID_OK on success, FLUID_FAILED otherwise
4407 * NOTE: A default equal tempered scale will be created, if no tuning exists
4408 * on the given bank and prog.
4411 fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
4414 //fluid_event_queue_elem_t *event;
4415 //fluid_event_queue_t *queue;
4416 fluid_tuning_t* tuning;
4417 int retval = FLUID_OK;
4419 //fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4420 //fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
4421 fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
4422 fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
4424 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
4426 tuning = fluid_synth_get_tuning (synth, bank, prog);
4428 /* If no tuning exists, create a new default tuning. We do this, so that
4429 * it can be replaced later, if any changes are made. */
4432 tuning = new_fluid_tuning ("Unnamed", bank, prog);
4433 if (tuning) fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, FALSE);
4436 if (tuning) fluid_tuning_ref (tuning); /* ++ ref for outside of lock */
4439 FLUID_API_RETURN(FLUID_FAILED);
4441 fluid_tuning_ref (tuning); /* ++ ref new tuning for following function */
4442 retval = fluid_synth_set_tuning_LOCAL (synth, chan, tuning, apply);
4444 fluid_tuning_unref (tuning, 1); /* -- unref for outside of lock */
4446 FLUID_API_RETURN(retval);
4449 /* Local synthesis thread set tuning function (takes over tuning reference) */
4451 fluid_synth_set_tuning_LOCAL (fluid_synth_t *synth, int chan,
4452 fluid_tuning_t *tuning, int apply)
4454 fluid_tuning_t *old_tuning;
4455 fluid_channel_t *channel;
4457 channel = synth->channel[chan];
4459 old_tuning = fluid_channel_get_tuning (channel);
4460 fluid_channel_set_tuning (channel, tuning); /* !! Takes over callers reference */
4462 if (apply) fluid_synth_update_voice_tuning_LOCAL (synth, channel);
4464 /* Send unref old tuning event */
4467 fluid_tuning_unref (old_tuning, 1);
4475 * Clear tuning scale on a MIDI channel (set it to the default well-tempered scale).
4476 * @param synth FluidSynth instance
4477 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4478 * @return FLUID_OK on success, FLUID_FAILED otherwise
4480 * NOTE: This function does NOT activate tuning change in realtime, use
4481 * fluid_synth_deactivate_tuning() instead to specify whether tuning change
4482 * should cause existing notes to update.
4485 fluid_synth_reset_tuning(fluid_synth_t* synth, int chan)
4487 return fluid_synth_deactivate_tuning (synth, chan, FALSE);
4491 * Clear tuning scale on a MIDI channel (use default equal tempered scale).
4492 * @param synth FluidSynth instance
4493 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4494 * @param apply TRUE to apply tuning change to active notes, FALSE otherwise
4495 * @return FLUID_OK on success, FLUID_FAILED otherwise
4499 fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply)
4501 int retval = FLUID_OK;
4503 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
4505 retval = fluid_synth_set_tuning_LOCAL (synth, chan, NULL, apply);
4507 FLUID_API_RETURN(retval);
4511 * Start tuning iteration.
4512 * @param synth FluidSynth instance
4515 fluid_synth_tuning_iteration_start(fluid_synth_t* synth)
4517 fluid_return_if_fail (synth != NULL);
4518 fluid_synth_api_enter(synth);
4519 fluid_private_set (synth->tuning_iter, FLUID_INT_TO_POINTER (0));
4520 fluid_synth_api_exit(synth);
4524 * Advance to next tuning.
4525 * @param synth FluidSynth instance
4526 * @param bank Location to store MIDI bank number of next tuning scale
4527 * @param prog Location to store MIDI program number of next tuning scale
4528 * @return 1 if tuning iteration advanced, 0 if no more tunings
4531 fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog)
4536 fluid_return_val_if_fail (synth != NULL, 0);
4537 fluid_return_val_if_fail (bank != NULL, 0);
4538 fluid_return_val_if_fail (prog != NULL, 0);
4539 fluid_synth_api_enter(synth);
4541 /* Current tuning iteration stored as: bank << 8 | program */
4542 pval = fluid_private_get (synth->tuning_iter);
4543 p = FLUID_POINTER_TO_INT (pval);
4544 b = (p >> 8) & 0xFF;
4549 FLUID_API_RETURN(0);
4552 for (; b < 128; b++, p = 0)
4554 if (synth->tuning[b] == NULL) continue;
4556 for (; p < 128; p++)
4558 if (synth->tuning[b][p] == NULL) continue;
4563 if (p < 127) fluid_private_set (synth->tuning_iter,
4564 FLUID_INT_TO_POINTER (b << 8 | (p + 1)));
4565 else fluid_private_set (synth->tuning_iter,
4566 FLUID_INT_TO_POINTER ((b + 1) << 8));
4568 FLUID_API_RETURN(1);
4572 FLUID_API_RETURN(0);
4576 * Get the entire note tuning for a given MIDI bank and program.
4577 * @param synth FluidSynth instance
4578 * @param bank MIDI bank number of tuning
4579 * @param prog MIDI program number of tuning
4580 * @param name Location to store tuning name or NULL to ignore
4581 * @param len Maximum number of chars to store to 'name' (including NULL byte)
4582 * @param pitch Array to store tuning scale to or NULL to ignore (len of 128)
4583 * @return FLUID_OK if matching tuning was found, FLUID_FAILED otherwise
4586 fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
4587 char* name, int len, double* pitch)
4589 fluid_tuning_t* tuning;
4591 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4592 fluid_synth_api_enter(synth);
4594 tuning = fluid_synth_get_tuning (synth, bank, prog);
4600 snprintf (name, len - 1, "%s", fluid_tuning_get_name (tuning));
4601 name[len - 1] = 0; /* make sure the string is null terminated */
4605 FLUID_MEMCPY (pitch, fluid_tuning_get_all (tuning), 128 * sizeof (double));
4608 FLUID_API_RETURN(tuning ? FLUID_OK : FLUID_FAILED);
4612 * Get settings assigned to a synth.
4613 * @param synth FluidSynth instance
4614 * @return FluidSynth settings which are assigned to the synth
4617 fluid_synth_get_settings(fluid_synth_t* synth)
4619 fluid_return_val_if_fail (synth != NULL, NULL);
4621 return synth->settings;
4625 * Convenience function to set a string setting of a synth.
4626 * @param synth FluidSynth instance
4627 * @param name Name of setting parameter
4628 * @param str Value to assign to the setting
4629 * @return FLUID_OK on success, FLUID_FAILED otherwise
4632 fluid_synth_setstr(fluid_synth_t* synth, const char* name, const char* str)
4634 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4635 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4637 return fluid_settings_setstr(synth->settings, name, str);
4641 * Convenience function to duplicate a string setting of a synth.
4642 * @param synth FluidSynth instance
4643 * @param name Name of setting parameter
4644 * @param str Location to store a pointer to the newly allocated string value
4645 * @return FLUID_OK on success, FLUID_FAILED otherwise
4647 * The returned string is owned by the caller and should be freed with free()
4648 * when finished with it.
4651 fluid_synth_dupstr(fluid_synth_t* synth, const char* name, char** str)
4653 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4654 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4655 fluid_return_val_if_fail (str != NULL, FLUID_FAILED);
4657 return fluid_settings_dupstr(synth->settings, name, str);
4661 * Convenience function to set a floating point setting of a synth.
4662 * @param synth FluidSynth instance
4663 * @param name Name of setting parameter
4664 * @param val Value to assign to the setting
4665 * @return FLUID_OK on success, FLUID_FAILED otherwise
4668 fluid_synth_setnum(fluid_synth_t* synth, const char* name, double val)
4670 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4671 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4673 return fluid_settings_setnum(synth->settings, name, val);
4677 * Convenience function to get a floating point setting of a synth.
4678 * @param synth FluidSynth instance
4679 * @param name Name of setting parameter
4680 * @param val Location to store the current value of the setting
4681 * @return FLUID_OK on success, FLUID_FAILED otherwise
4684 fluid_synth_getnum(fluid_synth_t* synth, const char* name, double* val)
4686 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4687 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4689 return fluid_settings_getnum(synth->settings, name, val);
4693 * Convenience function to set an integer setting of a synth.
4694 * @param synth FluidSynth instance
4695 * @param name Name of setting parameter
4696 * @param val Value to assign to the setting
4697 * @return FLUID_OK on success, FLUID_FAILED otherwise
4700 fluid_synth_setint(fluid_synth_t* synth, const char* name, int val)
4702 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4703 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4705 return fluid_settings_setint(synth->settings, name, val);
4709 * Convenience function to get an integer setting of a synth.
4710 * @param synth FluidSynth instance
4711 * @param name Name of setting parameter
4712 * @param val Location to store the current value of the setting
4713 * @return FLUID_OK on success, FLUID_FAILED otherwise
4716 fluid_synth_getint(fluid_synth_t* synth, const char* name, int* val)
4718 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4719 fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
4721 return fluid_settings_getint(synth->settings, name, val);
4725 * Set a SoundFont generator (effect) value on a MIDI channel in real-time.
4726 * @param synth FluidSynth instance
4727 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4728 * @param param SoundFont generator ID (#fluid_gen_type)
4729 * @param value Offset generator value to assign to the MIDI channel
4730 * @return FLUID_OK on success, FLUID_FAILED otherwise
4732 * Parameter numbers and ranges are described in the SoundFont 2.01
4733 * specification PDF, paragraph 8.1.3, page 48. See #fluid_gen_type.
4736 fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value)
4738 fluid_return_val_if_fail (param >= 0 && param < GEN_LAST, FLUID_FAILED);
4739 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
4741 fluid_synth_set_gen_LOCAL (synth, chan, param, value, FALSE);
4743 FLUID_API_RETURN(FLUID_OK);
4746 /* Synthesis thread local set gen function */
4748 fluid_synth_set_gen_LOCAL (fluid_synth_t* synth, int chan, int param, float value,
4751 fluid_voice_t* voice;
4754 fluid_channel_set_gen (synth->channel[chan], param, value, absolute);
4756 for (i = 0; i < synth->polyphony; i++) {
4757 voice = synth->voice[i];
4759 if (voice->chan == chan)
4760 fluid_voice_set_param (voice, param, value, absolute);
4765 * Set a SoundFont generator (effect) value on a MIDI channel in real-time.
4766 * @param synth FluidSynth instance
4767 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4768 * @param param SoundFont generator ID (#fluid_gen_type)
4769 * @param value Offset or absolute generator value to assign to the MIDI channel
4770 * @param absolute 0 to assign a relative value, non-zero to assign an absolute value
4771 * @param normalized 0 if value is specified in the native units of the generator,
4772 * non-zero to take the value as a 0.0-1.0 range and apply it to the valid
4773 * generator effect range (scaled and shifted as necessary).
4774 * @return FLUID_OK on success, FLUID_FAILED otherwise
4777 * This function allows for setting all effect parameters in real time on a
4778 * MIDI channel. Setting absolute to non-zero will cause the value to override
4779 * any generator values set in the instruments played on the MIDI channel.
4780 * See SoundFont 2.01 spec, paragraph 8.1.3, page 48 for details on SoundFont
4781 * generator parameters and valid ranges.
4784 fluid_synth_set_gen2(fluid_synth_t* synth, int chan, int param,
4785 float value, int absolute, int normalized)
4788 fluid_return_val_if_fail (param >= 0 && param < GEN_LAST, FLUID_FAILED);
4789 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
4791 v = normalized ? fluid_gen_scale(param, value) : value;
4793 fluid_synth_set_gen_LOCAL (synth, chan, param, v, absolute);
4795 FLUID_API_RETURN(FLUID_OK);
4799 * Get generator value assigned to a MIDI channel.
4800 * @param synth FluidSynth instance
4801 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4802 * @param param SoundFont generator ID (#fluid_gen_type)
4803 * @return Current generator value assigned to MIDI channel
4806 fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param)
4809 fluid_return_val_if_fail (param >= 0 && param < GEN_LAST, FLUID_FAILED);
4810 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
4812 result = fluid_channel_get_gen(synth->channel[chan], param);
4813 FLUID_API_RETURN(result);
4817 * Assign a MIDI router to a synth.
4818 * @param synth FluidSynth instance
4819 * @param router MIDI router to assign to the synth
4821 * NOTE: This should only be done once and prior to using the synth.
4824 fluid_synth_set_midi_router(fluid_synth_t* synth, fluid_midi_router_t* router)
4826 fluid_return_if_fail (synth != NULL);
4827 fluid_synth_api_enter(synth);
4829 synth->midi_router = router;
4830 fluid_synth_api_exit(synth);
4834 * Handle MIDI event from MIDI router, used as a callback function.
4835 * @param data FluidSynth instance
4836 * @param event MIDI event to handle
4837 * @return FLUID_OK on success, FLUID_FAILED otherwise
4840 fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event)
4842 fluid_synth_t* synth = (fluid_synth_t*) data;
4843 int type = fluid_midi_event_get_type(event);
4844 int chan = fluid_midi_event_get_channel(event);
4848 return fluid_synth_noteon(synth, chan,
4849 fluid_midi_event_get_key(event),
4850 fluid_midi_event_get_velocity(event));
4853 return fluid_synth_noteoff(synth, chan, fluid_midi_event_get_key(event));
4855 case CONTROL_CHANGE:
4856 return fluid_synth_cc(synth, chan,
4857 fluid_midi_event_get_control(event),
4858 fluid_midi_event_get_value(event));
4860 case PROGRAM_CHANGE:
4861 return fluid_synth_program_change(synth, chan, fluid_midi_event_get_program(event));
4863 case CHANNEL_PRESSURE:
4864 return fluid_synth_channel_pressure(synth, chan, fluid_midi_event_get_program(event));
4867 return fluid_synth_pitch_bend(synth, chan, fluid_midi_event_get_pitch(event));
4869 case MIDI_SYSTEM_RESET:
4870 return fluid_synth_system_reset(synth);
4872 return fluid_synth_sysex (synth, event->paramptr, event->param1, NULL, NULL, NULL, FALSE);
4874 return FLUID_FAILED;
4878 * Create and start voices using a preset and a MIDI note on event.
4879 * @param synth FluidSynth instance
4880 * @param id Voice group ID to use (can be used with fluid_synth_stop()).
4881 * @param preset Preset to synthesize
4882 * @param audio_chan Unused currently, set to 0
4883 * @param chan MIDI channel number (0 to MIDI channel count - 1)
4884 * @param key MIDI note number (0-127)
4885 * @param vel MIDI velocity number (1-127)
4886 * @return FLUID_OK on success, FLUID_FAILED otherwise
4888 * NOTE: Should only be called from within synthesis thread, which includes
4889 * SoundFont loader preset noteon method.
4892 fluid_synth_start(fluid_synth_t* synth, unsigned int id, fluid_preset_t* preset,
4893 int audio_chan, int chan, int key, int vel)
4896 fluid_return_val_if_fail (preset != NULL, FLUID_FAILED);
4897 fluid_return_val_if_fail (key >= 0 && key <= 127, FLUID_FAILED);
4898 fluid_return_val_if_fail (vel >= 1 && vel <= 127, FLUID_FAILED);
4899 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
4900 synth->storeid = id;
4901 result = fluid_preset_noteon (preset, synth, chan, key, vel);
4902 FLUID_API_RETURN(result);
4906 * Stop notes for a given note event voice ID.
4907 * @param synth FluidSynth instance
4908 * @param id Voice note event ID
4909 * @return FLUID_OK on success, FLUID_FAILED otherwise
4911 * NOTE: In FluidSynth versions prior to 1.1.0 #FLUID_FAILED would be returned
4912 * if no matching voice note event ID was found. Versions after 1.1.0 only
4913 * return #FLUID_FAILED if an error occurs.
4916 fluid_synth_stop(fluid_synth_t* synth, unsigned int id)
4919 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4920 fluid_synth_api_enter(synth);
4921 fluid_synth_stop_LOCAL (synth, id);
4923 FLUID_API_RETURN(result);
4926 /* Local synthesis thread variant of fluid_synth_stop */
4928 fluid_synth_stop_LOCAL (fluid_synth_t *synth, unsigned int id)
4930 fluid_voice_t* voice;
4933 for (i = 0; i < synth->polyphony; i++) {
4934 voice = synth->voice[i];
4936 if (_ON(voice) && (fluid_voice_get_id (voice) == id))
4937 fluid_voice_noteoff(voice);
4942 * Offset the bank numbers of a loaded SoundFont.
4943 * @param synth FluidSynth instance
4944 * @param sfont_id ID of a loaded SoundFont
4945 * @param offset Bank offset value to apply to all instruments
4948 fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset)
4950 fluid_sfont_info_t *sfont_info;
4953 fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
4954 fluid_synth_api_enter(synth);
4956 for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
4957 sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
4959 if (fluid_sfont_get_id (sfont_info->sfont) == (unsigned int)sfont_id)
4961 sfont_info->bankofs = offset;
4968 FLUID_LOG (FLUID_ERR, "No SoundFont with id = %d", sfont_id);
4969 FLUID_API_RETURN(FLUID_FAILED);
4972 FLUID_API_RETURN(FLUID_OK);
4976 * Get bank offset of a loaded SoundFont.
4977 * @param synth FluidSynth instance
4978 * @param sfont_id ID of a loaded SoundFont
4979 * @return SoundFont bank offset value
4982 fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id)
4984 fluid_sfont_info_t *sfont_info;
4988 fluid_return_val_if_fail (synth != NULL, 0);
4989 fluid_synth_api_enter(synth);
4991 for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
4992 sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
4994 if (fluid_sfont_get_id (sfont_info->sfont) == (unsigned int)sfont_id)
4996 offset = sfont_info->bankofs;
5003 FLUID_LOG (FLUID_ERR, "No SoundFont with id = %d", sfont_id);
5004 FLUID_API_RETURN(0);
5007 FLUID_API_RETURN(offset);
5011 fluid_synth_api_enter(fluid_synth_t* synth)
5013 if (synth->use_mutex) {
5014 fluid_rec_mutex_lock(synth->mutex);
5016 if (!synth->public_api_count) {
5017 fluid_synth_check_finished_voices(synth);
5019 synth->public_api_count++;
5022 void fluid_synth_api_exit(fluid_synth_t* synth)
5024 synth->public_api_count--;
5025 if (!synth->public_api_count) {
5026 fluid_rvoice_eventhandler_flush(synth->eventhandler);
5029 if (synth->use_mutex) {
5030 fluid_rec_mutex_unlock(synth->mutex);
5037 * Set midi channel type
5038 * @param synth FluidSynth instance
5039 * @param chan MIDI channel number (0 to MIDI channel count - 1)
5040 * @param type CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM
5041 * @return FLUID_OK on success, FLUID_FAILED otherwise
5044 int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type)
5046 fluid_return_val_if_fail ((type >= CHANNEL_TYPE_MELODIC) && (type <= CHANNEL_TYPE_DRUM), FLUID_FAILED);
5047 FLUID_API_ENTRY_CHAN(FLUID_FAILED);
5049 synth->channel[chan]->channel_type = type;
5051 FLUID_API_RETURN(FLUID_OK);