summaryrefslogtreecommitdiff
path: root/libs/fluidsynth
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2018-10-18 00:41:02 +0200
committerRobin Gareus <robin@gareus.org>2018-10-18 01:43:43 +0200
commitabf7905d5f82ad796544aa664cf3abaf20385cf7 (patch)
tree982dc729adea5bb604a12cd511f5f20a95a9b74d /libs/fluidsynth
parent5b280463ce220ca27c067ce33cd9af2f457f240b (diff)
Update Fluidsynth to 2.0.1
Diffstat (limited to 'libs/fluidsynth')
-rw-r--r--libs/fluidsynth/README5
-rw-r--r--libs/fluidsynth/fluidsynth/event.h151
-rw-r--r--libs/fluidsynth/fluidsynth/fluidsynth.h2
-rw-r--r--libs/fluidsynth/fluidsynth/gen.h172
-rw-r--r--libs/fluidsynth/fluidsynth/log.h35
-rw-r--r--libs/fluidsynth/fluidsynth/midi.h168
-rw-r--r--libs/fluidsynth/fluidsynth/misc.h24
-rw-r--r--libs/fluidsynth/fluidsynth/mod.h96
-rw-r--r--libs/fluidsynth/fluidsynth/settings.h115
-rw-r--r--libs/fluidsynth/fluidsynth/sfont.h439
-rw-r--r--libs/fluidsynth/fluidsynth/synth.h468
-rw-r--r--libs/fluidsynth/fluidsynth/types.h19
-rw-r--r--libs/fluidsynth/fluidsynth/voice.h46
-rw-r--r--libs/fluidsynth/src/fluid_adsr_env.c35
-rw-r--r--libs/fluidsynth/src/fluid_adsr_env.h196
-rw-r--r--libs/fluidsynth/src/fluid_chan.c805
-rw-r--r--libs/fluidsynth/src/fluid_chan.h279
-rw-r--r--libs/fluidsynth/src/fluid_chorus.c673
-rw-r--r--libs/fluidsynth/src/fluid_chorus.h52
-rw-r--r--libs/fluidsynth/src/fluid_conv.c463
-rw-r--r--libs/fluidsynth/src/fluid_conv.h58
-rw-r--r--libs/fluidsynth/src/fluid_defsfont.c4647
-rw-r--r--libs/fluidsynth/src/fluid_defsfont.h547
-rw-r--r--libs/fluidsynth/src/fluid_event.c694
-rw-r--r--libs/fluidsynth/src/fluid_event.h87
-rw-r--r--libs/fluidsynth/src/fluid_gen.c195
-rw-r--r--libs/fluidsynth/src/fluid_gen.h47
-rw-r--r--libs/fluidsynth/src/fluid_hash.c969
-rw-r--r--libs/fluidsynth/src/fluid_hash.h124
-rw-r--r--libs/fluidsynth/src/fluid_iir_filter.c568
-rw-r--r--libs/fluidsynth/src/fluid_iir_filter.h74
-rw-r--r--libs/fluidsynth/src/fluid_lfo.c16
-rw-r--r--libs/fluidsynth/src/fluid_lfo.h71
-rw-r--r--libs/fluidsynth/src/fluid_list.c373
-rw-r--r--libs/fluidsynth/src/fluid_list.h32
-rw-r--r--libs/fluidsynth/src/fluid_midi.c1457
-rw-r--r--libs/fluidsynth/src/fluid_midi.h490
-rw-r--r--libs/fluidsynth/src/fluid_mod.c845
-rw-r--r--libs/fluidsynth/src/fluid_mod.h39
-rw-r--r--libs/fluidsynth/src/fluid_phase.h24
-rw-r--r--libs/fluidsynth/src/fluid_rev.c688
-rw-r--r--libs/fluidsynth/src/fluid_rev.h58
-rw-r--r--libs/fluidsynth/src/fluid_ringbuffer.c63
-rw-r--r--libs/fluidsynth/src/fluid_ringbuffer.h73
-rw-r--r--libs/fluidsynth/src/fluid_rvoice.c1102
-rw-r--r--libs/fluidsynth/src/fluid_rvoice.h267
-rw-r--r--libs/fluidsynth/src/fluid_rvoice_dsp.c1112
-rw-r--r--libs/fluidsynth/src/fluid_rvoice_event.c364
-rw-r--r--libs/fluidsynth/src/fluid_rvoice_event.h119
-rw-r--r--libs/fluidsynth/src/fluid_rvoice_mixer.c1885
-rw-r--r--libs/fluidsynth/src/fluid_rvoice_mixer.h67
-rw-r--r--libs/fluidsynth/src/fluid_samplecache.c295
-rw-r--r--libs/fluidsynth/src/fluid_samplecache.h34
-rw-r--r--libs/fluidsynth/src/fluid_settings.c2355
-rw-r--r--libs/fluidsynth/src/fluid_settings.h49
-rw-r--r--libs/fluidsynth/src/fluid_sffile.c2566
-rw-r--r--libs/fluidsynth/src/fluid_sffile.h230
-rw-r--r--libs/fluidsynth/src/fluid_sfont.c784
-rw-r--r--libs/fluidsynth/src/fluid_sfont.h159
-rw-r--r--libs/fluidsynth/src/fluid_synth.c8397
-rw-r--r--libs/fluidsynth/src/fluid_synth.h268
-rw-r--r--libs/fluidsynth/src/fluid_synth_monopoly.c727
-rw-r--r--libs/fluidsynth/src/fluid_sys.c1865
-rw-r--r--libs/fluidsynth/src/fluid_sys.h453
-rw-r--r--libs/fluidsynth/src/fluid_tuning.c207
-rw-r--r--libs/fluidsynth/src/fluid_tuning.h41
-rw-r--r--libs/fluidsynth/src/fluid_voice.c2692
-rw-r--r--libs/fluidsynth/src/fluid_voice.h247
-rw-r--r--libs/fluidsynth/src/fluidsynth_priv.h177
-rw-r--r--libs/fluidsynth/wscript10
70 files changed, 26056 insertions, 16898 deletions
diff --git a/libs/fluidsynth/README b/libs/fluidsynth/README
index 6032b9c299..de74bfb548 100644
--- a/libs/fluidsynth/README
+++ b/libs/fluidsynth/README
@@ -1,8 +1,7 @@
This is a stripped down version of fluidsynth (library only)
-from git://git.code.sf.net/p/fluidsynth/code-git
-revisition f52597be038a5a045fc74b6f96d5f9b0bbbbc044 from May/2015
-imported into Ardour Aug/2016
+from git://github.com/FluidSynth/fluidsynth.git
+rev. v2.0.1-5-gebc177f Oct/2018
fluidsynth is licensed in terms of the LGPL-2+, see individual source
files for (C) holders.
diff --git a/libs/fluidsynth/fluidsynth/event.h b/libs/fluidsynth/fluidsynth/event.h
index b154304515..cbd1fa6a09 100644
--- a/libs/fluidsynth/fluidsynth/event.h
+++ b/libs/fluidsynth/fluidsynth/event.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -35,99 +35,102 @@ extern "C" {
/**
* Sequencer event type enumeration.
*/
-enum fluid_seq_event_type {
- FLUID_SEQ_NOTE = 0, /**< Note event with duration */
- FLUID_SEQ_NOTEON, /**< Note on event */
- FLUID_SEQ_NOTEOFF, /**< Note off event */
- FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
- FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
- FLUID_SEQ_BANKSELECT, /**< Bank select message */
- FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
- FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */
- FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
- FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was mispelled previously */
- FLUID_SEQ_MODULATION, /**< Modulation controller event */
- FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
- FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
- FLUID_SEQ_PAN, /**< Stereo pan set event */
- FLUID_SEQ_VOLUME, /**< Volume set event */
- FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
- FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
- FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
- FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
- FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
- FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
- FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
- FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
+enum fluid_seq_event_type
+{
+ FLUID_SEQ_NOTE = 0, /**< Note event with duration */
+ FLUID_SEQ_NOTEON, /**< Note on event */
+ FLUID_SEQ_NOTEOFF, /**< Note off event */
+ FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
+ FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
+ FLUID_SEQ_BANKSELECT, /**< Bank select message */
+ FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
+ FLUID_SEQ_PROGRAMSELECT, /**< Program select message */
+ FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
+ FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was mispelled previously */
+ FLUID_SEQ_MODULATION, /**< Modulation controller event */
+ FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
+ FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
+ FLUID_SEQ_PAN, /**< Stereo pan set event */
+ FLUID_SEQ_VOLUME, /**< Volume set event */
+ FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
+ FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
+ FLUID_SEQ_TIMER, /**< Timer event (useful for giving a callback at a certain time) */
+ FLUID_SEQ_ANYCONTROLCHANGE, /**< Any control change message (only internally used for remove_events) */
+ FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
+ FLUID_SEQ_KEYPRESSURE, /**< Polyphonic aftertouch event @since 2.0.0 */
+ FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
+ FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
+#ifndef __DOXYGEN__
+ FLUID_SEQ_LASTEVENT /**< @internal Defines the count of events enums @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
+#endif
};
-#define FLUID_SEQ_PITCHWHHELSENS FLUID_SEQ_PITCHWHEELSENS /**< Old deprecated misspelling of #FLUID_SEQ_PITCHWHEELSENS */
-
/* Event alloc/free */
-FLUIDSYNTH_API fluid_event_t* new_fluid_event(void);
-FLUIDSYNTH_API void delete_fluid_event(fluid_event_t* evt);
+FLUIDSYNTH_API fluid_event_t *new_fluid_event(void);
+FLUIDSYNTH_API void delete_fluid_event(fluid_event_t *evt);
/* Initializing events */
-FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t* evt, short src);
-FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t* evt, short dest);
+FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src);
+FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest);
/* Timer events */
-FLUIDSYNTH_API void fluid_event_timer(fluid_event_t* evt, void* data);
+FLUIDSYNTH_API void fluid_event_timer(fluid_event_t *evt, void *data);
/* Note events */
-FLUIDSYNTH_API void fluid_event_note(fluid_event_t* evt, int channel,
- short key, short vel,
- unsigned int duration);
+FLUIDSYNTH_API void fluid_event_note(fluid_event_t *evt, int channel,
+ short key, short vel,
+ unsigned int duration);
-FLUIDSYNTH_API void fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel);
-FLUIDSYNTH_API void fluid_event_noteoff(fluid_event_t* evt, int channel, short key);
-FLUIDSYNTH_API void fluid_event_all_sounds_off(fluid_event_t* evt, int channel);
-FLUIDSYNTH_API void fluid_event_all_notes_off(fluid_event_t* evt, int channel);
+FLUIDSYNTH_API void fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel);
+FLUIDSYNTH_API void fluid_event_noteoff(fluid_event_t *evt, int channel, short key);
+FLUIDSYNTH_API void fluid_event_all_sounds_off(fluid_event_t *evt, int channel);
+FLUIDSYNTH_API void fluid_event_all_notes_off(fluid_event_t *evt, int channel);
/* Instrument selection */
-FLUIDSYNTH_API void fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num);
-FLUIDSYNTH_API void fluid_event_program_change(fluid_event_t* evt, int channel, short preset_num);
-FLUIDSYNTH_API void fluid_event_program_select(fluid_event_t* evt, int channel, unsigned int sfont_id, short bank_num, short preset_num);
+FLUIDSYNTH_API void fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num);
+FLUIDSYNTH_API void fluid_event_program_change(fluid_event_t *evt, int channel, short preset_num);
+FLUIDSYNTH_API void fluid_event_program_select(fluid_event_t *evt, int channel, unsigned int sfont_id, short bank_num, short preset_num);
/* Real-time generic instrument controllers */
-FLUIDSYNTH_API
-void fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val);
+FLUIDSYNTH_API
+void fluid_event_control_change(fluid_event_t *evt, int channel, short control, short val);
/* Real-time instrument controllers shortcuts */
-FLUIDSYNTH_API void fluid_event_pitch_bend(fluid_event_t* evt, int channel, int val);
-FLUIDSYNTH_API void fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t* evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t* evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_pan(fluid_event_t* evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_volume(fluid_event_t* evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t* evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t* evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_pitch_bend(fluid_event_t *evt, int channel, int val);
+FLUIDSYNTH_API void fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t *evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t *evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_pan(fluid_event_t *evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_volume(fluid_event_t *evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t *evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t *evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val);
-FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t* evt);
+FLUIDSYNTH_API void fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, short val);
+FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t *evt, int channel, short val);
+FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t *evt);
/* Only for removing events */
-FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel);
+FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t *evt, int channel);
/* Only when unregistering clients */
-FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t* evt);
+FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t *evt);
/* Accessing event data */
-FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_source(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_dest(fluid_event_t* evt);
-FLUIDSYNTH_API int fluid_event_get_channel(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_key(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_velocity(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_control(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_value(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_program(fluid_event_t* evt);
-FLUIDSYNTH_API void* fluid_event_get_data(fluid_event_t* evt);
-FLUIDSYNTH_API unsigned int fluid_event_get_duration(fluid_event_t* evt);
-FLUIDSYNTH_API short fluid_event_get_bank(fluid_event_t* evt);
-FLUIDSYNTH_API int fluid_event_get_pitch(fluid_event_t* evt);
-FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t* evt);
+FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t *evt);
+FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt);
+FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_dest(fluid_event_t *evt);
+FLUIDSYNTH_API int fluid_event_get_channel(fluid_event_t *evt);
+FLUIDSYNTH_API short fluid_event_get_key(fluid_event_t *evt);
+FLUIDSYNTH_API short fluid_event_get_velocity(fluid_event_t *evt);
+FLUIDSYNTH_API short fluid_event_get_control(fluid_event_t *evt);
+FLUIDSYNTH_API short fluid_event_get_value(fluid_event_t *evt);
+FLUIDSYNTH_API short fluid_event_get_program(fluid_event_t *evt);
+FLUIDSYNTH_API void *fluid_event_get_data(fluid_event_t *evt);
+FLUIDSYNTH_API unsigned int fluid_event_get_duration(fluid_event_t *evt);
+FLUIDSYNTH_API short fluid_event_get_bank(fluid_event_t *evt);
+FLUIDSYNTH_API int fluid_event_get_pitch(fluid_event_t *evt);
+FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t *evt);
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/fluidsynth/fluidsynth.h b/libs/fluidsynth/fluidsynth/fluidsynth.h
index 8c599b5be7..8852ea2d84 100644
--- a/libs/fluidsynth/fluidsynth/fluidsynth.h
+++ b/libs/fluidsynth/fluidsynth/fluidsynth.h
@@ -15,7 +15,7 @@ extern "C" {
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
-FLUIDSYNTH_API char* fluid_version_str(void);
+FLUIDSYNTH_API const char* fluid_version_str(void);
#include "types.h"
diff --git a/libs/fluidsynth/fluidsynth/gen.h b/libs/fluidsynth/fluidsynth/gen.h
index e4bbc8ef69..4b625831b0 100644
--- a/libs/fluidsynth/fluidsynth/gen.h
+++ b/libs/fluidsynth/fluidsynth/gen.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -33,99 +33,83 @@ extern "C" {
/**
* Generator (effect) numbers (Soundfont 2.01 specifications section 8.1.3)
*/
-enum fluid_gen_type {
- GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
- GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
- GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
- GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
- GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
- GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
- GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
- GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
- GEN_FILTERFC, /**< Filter cutoff */
- GEN_FILTERQ, /**< Filter Q */
- GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
- GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
- GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
- GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
- GEN_UNUSED1, /**< Unused */
- GEN_CHORUSSEND, /**< Chorus send amount */
- GEN_REVERBSEND, /**< Reverb send amount */
- GEN_PAN, /**< Stereo panning */
- GEN_UNUSED2, /**< Unused */
- GEN_UNUSED3, /**< Unused */
- GEN_UNUSED4, /**< Unused */
- GEN_MODLFODELAY, /**< Modulation LFO delay */
- GEN_MODLFOFREQ, /**< Modulation LFO frequency */
- GEN_VIBLFODELAY, /**< Vibrato LFO delay */
- GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
- GEN_MODENVDELAY, /**< Modulation envelope delay */
- GEN_MODENVATTACK, /**< Modulation envelope attack */
- GEN_MODENVHOLD, /**< Modulation envelope hold */
- GEN_MODENVDECAY, /**< Modulation envelope decay */
- GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
- GEN_MODENVRELEASE, /**< Modulation envelope release */
- GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
- GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
- GEN_VOLENVDELAY, /**< Volume envelope delay */
- GEN_VOLENVATTACK, /**< Volume envelope attack */
- GEN_VOLENVHOLD, /**< Volume envelope hold */
- GEN_VOLENVDECAY, /**< Volume envelope decay */
- GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
- GEN_VOLENVRELEASE, /**< Volume envelope release */
- GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
- GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
- GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
- GEN_RESERVED1, /**< Reserved */
- GEN_KEYRANGE, /**< MIDI note range */
- GEN_VELRANGE, /**< MIDI velocity range */
- GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
- GEN_KEYNUM, /**< Fixed MIDI note number */
- GEN_VELOCITY, /**< Fixed MIDI velocity value */
- GEN_ATTENUATION, /**< Initial volume attenuation */
- GEN_RESERVED2, /**< Reserved */
- GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
- GEN_COARSETUNE, /**< Coarse tuning */
- GEN_FINETUNE, /**< Fine tuning */
- GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
- GEN_SAMPLEMODE, /**< Sample mode flags */
- GEN_RESERVED3, /**< Reserved */
- GEN_SCALETUNE, /**< Scale tuning */
- GEN_EXCLUSIVECLASS, /**< Exclusive class number */
- GEN_OVERRIDEROOTKEY, /**< Sample root note override */
-
- /* the initial pitch is not a "standard" generator. It is not
- * mentioned in the list of generator in the SF2 specifications. It
- * is used, however, as the destination for the default pitch wheel
- * modulator. */
- GEN_PITCH, /**< Pitch (NOTE: Not a real SoundFont generator) */
- GEN_LAST /**< Value defines the count of generators (#fluid_gen_type) */
-};
-
-
-/**
- * SoundFont generator structure.
- */
-typedef struct _fluid_gen_t
+enum fluid_gen_type
{
- unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
- double val; /**< The nominal value */
- double mod; /**< Change by modulators */
- double nrpn; /**< Change by NRPN messages */
-} fluid_gen_t;
+ GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
+ GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
+ GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
+ GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
+ GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
+ GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
+ GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
+ GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
+ GEN_FILTERFC, /**< Filter cutoff */
+ GEN_FILTERQ, /**< Filter Q */
+ GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
+ GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
+ GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
+ GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
+ GEN_UNUSED1, /**< Unused */
+ GEN_CHORUSSEND, /**< Chorus send amount */
+ GEN_REVERBSEND, /**< Reverb send amount */
+ GEN_PAN, /**< Stereo panning */
+ GEN_UNUSED2, /**< Unused */
+ GEN_UNUSED3, /**< Unused */
+ GEN_UNUSED4, /**< Unused */
+ GEN_MODLFODELAY, /**< Modulation LFO delay */
+ GEN_MODLFOFREQ, /**< Modulation LFO frequency */
+ GEN_VIBLFODELAY, /**< Vibrato LFO delay */
+ GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
+ GEN_MODENVDELAY, /**< Modulation envelope delay */
+ GEN_MODENVATTACK, /**< Modulation envelope attack */
+ GEN_MODENVHOLD, /**< Modulation envelope hold */
+ GEN_MODENVDECAY, /**< Modulation envelope decay */
+ GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
+ GEN_MODENVRELEASE, /**< Modulation envelope release */
+ GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
+ GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
+ GEN_VOLENVDELAY, /**< Volume envelope delay */
+ GEN_VOLENVATTACK, /**< Volume envelope attack */
+ GEN_VOLENVHOLD, /**< Volume envelope hold */
+ GEN_VOLENVDECAY, /**< Volume envelope decay */
+ GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
+ GEN_VOLENVRELEASE, /**< Volume envelope release */
+ GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
+ GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
+ GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
+ GEN_RESERVED1, /**< Reserved */
+ GEN_KEYRANGE, /**< MIDI note range */
+ GEN_VELRANGE, /**< MIDI velocity range */
+ GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
+ GEN_KEYNUM, /**< Fixed MIDI note number */
+ GEN_VELOCITY, /**< Fixed MIDI velocity value */
+ GEN_ATTENUATION, /**< Initial volume attenuation */
+ GEN_RESERVED2, /**< Reserved */
+ GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
+ GEN_COARSETUNE, /**< Coarse tuning */
+ GEN_FINETUNE, /**< Fine tuning */
+ GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
+ GEN_SAMPLEMODE, /**< Sample mode flags */
+ GEN_RESERVED3, /**< Reserved */
+ GEN_SCALETUNE, /**< Scale tuning */
+ GEN_EXCLUSIVECLASS, /**< Exclusive class number */
+ GEN_OVERRIDEROOTKEY, /**< Sample root note override */
-/**
- * Enum value for 'flags' field of #fluid_gen_t (not really flags).
- */
-enum fluid_gen_flags
-{
- GEN_UNUSED, /**< Generator value is not set */
- GEN_SET, /**< Generator value is set */
- GEN_ABS_NRPN /**< Generator is an absolute value */
-};
+ /* the initial pitch is not a "standard" generator. It is not
+ * mentioned in the list of generator in the SF2 specifications. It
+ * is used, however, as the destination for the default pitch wheel
+ * modulator. */
+ GEN_PITCH, /**< Pitch @note Not a real SoundFont generator */
-FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
+ GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
+ /* non-standard generator for an additional custom high- or low-pass filter */
+ GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */
+ GEN_CUSTOM_FILTERQ, /**< Custom filter Q */
+#ifndef __DOXYGEN__
+ GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
+#endif
+};
#ifdef __cplusplus
diff --git a/libs/fluidsynth/fluidsynth/log.h b/libs/fluidsynth/fluidsynth/log.h
index 85db03e1cb..00d802f50e 100644
--- a/libs/fluidsynth/fluidsynth/log.h
+++ b/libs/fluidsynth/fluidsynth/log.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -52,13 +52,16 @@ extern "C" {
/**
* FluidSynth log levels.
*/
-enum fluid_log_level {
- FLUID_PANIC, /**< The synth can't function correctly any more */
- FLUID_ERR, /**< Serious error occurred */
- FLUID_WARN, /**< Warning */
- FLUID_INFO, /**< Verbose informational messages */
- FLUID_DBG, /**< Debugging messages */
- LAST_LOG_LEVEL
+enum fluid_log_level
+{
+ FLUID_PANIC, /**< The synth can't function correctly any more */
+ FLUID_ERR, /**< Serious error occurred */
+ FLUID_WARN, /**< Warning */
+ FLUID_INFO, /**< Verbose informational messages */
+ FLUID_DBG, /**< Debugging messages */
+#ifndef __DOXYGEN__
+ LAST_LOG_LEVEL /**< @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
+#endif
};
/**
@@ -67,12 +70,12 @@ enum fluid_log_level {
* @param message Log message text
* @param data User data pointer supplied to fluid_set_log_function().
*/
-typedef void (*fluid_log_function_t)(int level, char* message, void* data);
+typedef void (*fluid_log_function_t)(int level, const char *message, void *data);
-FLUIDSYNTH_API
-fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void* data);
+FLUIDSYNTH_API
+fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void *data);
-FLUIDSYNTH_API void fluid_default_log_function(int level, char* message, void* data);
+FLUIDSYNTH_API void fluid_default_log_function(int level, const char *message, void *data);
FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...);
diff --git a/libs/fluidsynth/fluidsynth/midi.h b/libs/fluidsynth/fluidsynth/midi.h
index ab1e6a198b..cd30e2088b 100644
--- a/libs/fluidsynth/fluidsynth/midi.h
+++ b/libs/fluidsynth/fluidsynth/midi.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -30,27 +30,31 @@ extern "C" {
* @brief Functions for MIDI events, drivers and MIDI file playback.
*/
-FLUIDSYNTH_API fluid_midi_event_t* new_fluid_midi_event(void);
-FLUIDSYNTH_API int delete_fluid_midi_event(fluid_midi_event_t* event);
-
-FLUIDSYNTH_API int fluid_midi_event_set_type(fluid_midi_event_t* evt, int type);
-FLUIDSYNTH_API int fluid_midi_event_get_type(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_set_channel(fluid_midi_event_t* evt, int chan);
-FLUIDSYNTH_API int fluid_midi_event_get_channel(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_get_key(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_set_key(fluid_midi_event_t* evt, int key);
-FLUIDSYNTH_API int fluid_midi_event_get_velocity(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_set_velocity(fluid_midi_event_t* evt, int vel);
-FLUIDSYNTH_API int fluid_midi_event_get_control(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_set_control(fluid_midi_event_t* evt, int ctrl);
-FLUIDSYNTH_API int fluid_midi_event_get_value(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_set_value(fluid_midi_event_t* evt, int val);
-FLUIDSYNTH_API int fluid_midi_event_get_program(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t* evt, int val);
-FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t* evt);
-FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val);
-FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t* evt, void *data,
- int size, int dynamic);
+FLUIDSYNTH_API fluid_midi_event_t *new_fluid_midi_event(void);
+FLUIDSYNTH_API void delete_fluid_midi_event(fluid_midi_event_t *event);
+
+FLUIDSYNTH_API int fluid_midi_event_set_type(fluid_midi_event_t *evt, int type);
+FLUIDSYNTH_API int fluid_midi_event_get_type(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_set_channel(fluid_midi_event_t *evt, int chan);
+FLUIDSYNTH_API int fluid_midi_event_get_channel(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_get_key(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_set_key(fluid_midi_event_t *evt, int key);
+FLUIDSYNTH_API int fluid_midi_event_get_velocity(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_set_velocity(fluid_midi_event_t *evt, int vel);
+FLUIDSYNTH_API int fluid_midi_event_get_control(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_set_control(fluid_midi_event_t *evt, int ctrl);
+FLUIDSYNTH_API int fluid_midi_event_get_value(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_set_value(fluid_midi_event_t *evt, int val);
+FLUIDSYNTH_API int fluid_midi_event_get_program(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t *evt, int val);
+FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t *evt);
+FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val);
+FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data,
+ int size, int dynamic);
+FLUIDSYNTH_API int fluid_midi_event_set_text(fluid_midi_event_t *evt,
+ void *data, int size, int dynamic);
+FLUIDSYNTH_API int fluid_midi_event_set_lyrics(fluid_midi_event_t *evt,
+ void *data, int size, int dynamic);
/**
* MIDI router rule type.
@@ -58,13 +62,15 @@ FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t* evt, void *dat
*/
typedef enum
{
- FLUID_MIDI_ROUTER_RULE_NOTE, /**< MIDI note rule */
- FLUID_MIDI_ROUTER_RULE_CC, /**< MIDI controller rule */
- FLUID_MIDI_ROUTER_RULE_PROG_CHANGE, /**< MIDI program change rule */
- FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */
- FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */
- FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */
- FLUID_MIDI_ROUTER_RULE_COUNT /**< Total count of rule types */
+ FLUID_MIDI_ROUTER_RULE_NOTE, /**< MIDI note rule */
+ FLUID_MIDI_ROUTER_RULE_CC, /**< MIDI controller rule */
+ FLUID_MIDI_ROUTER_RULE_PROG_CHANGE, /**< MIDI program change rule */
+ FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */
+ FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */
+ FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */
+#ifndef __DOXYGEN__
+ FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time!*/
+#endif
} fluid_midi_router_rule_type;
/**
@@ -79,35 +85,35 @@ typedef enum
* to communicate events.
* In the not-so-far future...
*/
-typedef int (*handle_midi_event_func_t)(void* data, fluid_midi_event_t* event);
-
-FLUIDSYNTH_API fluid_midi_router_t* new_fluid_midi_router(fluid_settings_t* settings,
- handle_midi_event_func_t handler,
- void* event_handler_data);
-FLUIDSYNTH_API int delete_fluid_midi_router(fluid_midi_router_t* handler);
-FLUIDSYNTH_API int fluid_midi_router_set_default_rules (fluid_midi_router_t *router);
-FLUIDSYNTH_API int fluid_midi_router_clear_rules (fluid_midi_router_t *router);
-FLUIDSYNTH_API int fluid_midi_router_add_rule (fluid_midi_router_t *router,
- fluid_midi_router_rule_t *rule, int type);
-FLUIDSYNTH_API fluid_midi_router_rule_t *new_fluid_midi_router_rule (void);
-FLUIDSYNTH_API void delete_fluid_midi_router_rule (fluid_midi_router_rule_t *rule);
-FLUIDSYNTH_API void fluid_midi_router_rule_set_chan (fluid_midi_router_rule_t *rule,
- int min, int max, float mul, int add);
-FLUIDSYNTH_API void fluid_midi_router_rule_set_param1 (fluid_midi_router_rule_t *rule,
- int min, int max, float mul, int add);
-FLUIDSYNTH_API void fluid_midi_router_rule_set_param2 (fluid_midi_router_rule_t *rule,
- int min, int max, float mul, int add);
-FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event);
-FLUIDSYNTH_API int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event);
-FLUIDSYNTH_API int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event);
-
-
-FLUIDSYNTH_API
-fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings,
- handle_midi_event_func_t handler,
- void* event_handler_data);
-
-FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t* driver);
+typedef int (*handle_midi_event_func_t)(void *data, fluid_midi_event_t *event);
+
+FLUIDSYNTH_API fluid_midi_router_t *new_fluid_midi_router(fluid_settings_t *settings,
+ handle_midi_event_func_t handler,
+ void *event_handler_data);
+FLUIDSYNTH_API void delete_fluid_midi_router(fluid_midi_router_t *handler);
+FLUIDSYNTH_API int fluid_midi_router_set_default_rules(fluid_midi_router_t *router);
+FLUIDSYNTH_API int fluid_midi_router_clear_rules(fluid_midi_router_t *router);
+FLUIDSYNTH_API int fluid_midi_router_add_rule(fluid_midi_router_t *router,
+ fluid_midi_router_rule_t *rule, int type);
+FLUIDSYNTH_API fluid_midi_router_rule_t *new_fluid_midi_router_rule(void);
+FLUIDSYNTH_API void delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule);
+FLUIDSYNTH_API void fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule,
+ int min, int max, float mul, int add);
+FLUIDSYNTH_API void fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule,
+ int min, int max, float mul, int add);
+FLUIDSYNTH_API void fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule,
+ int min, int max, float mul, int add);
+FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event);
+FLUIDSYNTH_API int fluid_midi_dump_prerouter(void *data, fluid_midi_event_t *event);
+FLUIDSYNTH_API int fluid_midi_dump_postrouter(void *data, fluid_midi_event_t *event);
+
+
+FLUIDSYNTH_API
+fluid_midi_driver_t *new_fluid_midi_driver(fluid_settings_t *settings,
+ handle_midi_event_func_t handler,
+ void *event_handler_data);
+
+FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t *driver);
/**
@@ -116,23 +122,31 @@ FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t* driver);
*/
enum fluid_player_status
{
- FLUID_PLAYER_READY, /**< Player is ready */
- FLUID_PLAYER_PLAYING, /**< Player is currently playing */
- FLUID_PLAYER_DONE /**< Player is finished playing */
+ FLUID_PLAYER_READY, /**< Player is ready */
+ FLUID_PLAYER_PLAYING, /**< Player is currently playing */
+ FLUID_PLAYER_DONE /**< Player is finished playing */
};
-FLUIDSYNTH_API fluid_player_t* new_fluid_player(fluid_synth_t* synth);
-FLUIDSYNTH_API int delete_fluid_player(fluid_player_t* player);
-FLUIDSYNTH_API int fluid_player_add(fluid_player_t* player, const char *midifile);
-FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t* player, const void *buffer, size_t len);
-FLUIDSYNTH_API int fluid_player_play(fluid_player_t* player);
-FLUIDSYNTH_API int fluid_player_stop(fluid_player_t* player);
-FLUIDSYNTH_API int fluid_player_join(fluid_player_t* player);
-FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t* player, int loop);
-FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t* player, int tempo);
-FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t* player, int bpm);
-FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t* player);
-FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t* player, handle_midi_event_func_t handler, void* handler_data);
+FLUIDSYNTH_API fluid_player_t *new_fluid_player(fluid_synth_t *synth);
+FLUIDSYNTH_API void delete_fluid_player(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_add(fluid_player_t *player, const char *midifile);
+FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t *player, const void *buffer, size_t len);
+FLUIDSYNTH_API int fluid_player_play(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_stop(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_join(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t *player, int loop);
+FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo);
+FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t *player, int bpm);
+FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t *player, handle_midi_event_func_t handler, void *handler_data);
+
+FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_get_current_tick(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_get_total_ticks(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_get_bpm(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_get_midi_tempo(fluid_player_t *player);
+FLUIDSYNTH_API int fluid_player_seek(fluid_player_t *player, int ticks);
+
+///
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/fluidsynth/misc.h b/libs/fluidsynth/fluidsynth/misc.h
index 4f97d8437d..7a2b457b5a 100644
--- a/libs/fluidsynth/fluidsynth/misc.h
+++ b/libs/fluidsynth/fluidsynth/misc.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -36,7 +36,7 @@ extern "C" {
* Value that indicates success, used by most libfluidsynth functions.
* @since 1.1.0
*
- * NOTE: This was not publicly defined prior to libfluidsynth 1.1.0. When
+ * @note This was not publicly defined prior to libfluidsynth 1.1.0. When
* writing code which should also be compatible with older versions, something
* like the following can be used:
*
@@ -55,19 +55,13 @@ extern "C" {
* Value that indicates failure, used by most libfluidsynth functions.
* @since 1.1.0
*
- * NOTE: See #FLUID_OK for more details.
+ * @note See #FLUID_OK for more details.
*/
#define FLUID_FAILED (-1)
-FLUIDSYNTH_API int fluid_is_soundfont (const char *filename);
-FLUIDSYNTH_API int fluid_is_midifile (const char *filename);
-
-
-#ifdef WIN32
-FLUIDSYNTH_API void* fluid_get_hinstance(void);
-FLUIDSYNTH_API void fluid_set_hinstance(void* hinstance);
-#endif
+FLUIDSYNTH_API int fluid_is_soundfont(const char *filename);
+FLUIDSYNTH_API int fluid_is_midifile(const char *filename);
#ifdef __cplusplus
diff --git a/libs/fluidsynth/fluidsynth/mod.h b/libs/fluidsynth/fluidsynth/mod.h
index e34309546b..5ea5f89d4a 100644
--- a/libs/fluidsynth/fluidsynth/mod.h
+++ b/libs/fluidsynth/fluidsynth/mod.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -30,26 +30,6 @@ extern "C" {
* @brief SoundFont modulator functions and constants.
*/
-#define FLUID_NUM_MOD 64 /**< Maximum number of modulators in a voice */
-
-/**
- * Modulator structure. See SoundFont 2.04 PDF section 8.2.
- */
-struct _fluid_mod_t
-{
- unsigned char dest; /**< Destination generator to control */
- unsigned char src1; /**< Source controller 1 */
- unsigned char flags1; /**< Source controller 1 flags */
- unsigned char src2; /**< Source controller 2 */
- unsigned char flags2; /**< Source controller 2 flags */
- double amount; /**< Multiplier amount */
- /* The 'next' field allows to link modulators into a list. It is
- * not used in fluid_voice.c, there each voice allocates memory for a
- * fixed number of modulators. Since there may be a huge number of
- * different zones, this is more efficient.
- */
- fluid_mod_t * next;
-};
/**
* Flags defining the polarity, mapping function and type of a modulator source.
@@ -60,16 +40,18 @@ struct _fluid_mod_t
*/
enum fluid_mod_flags
{
- FLUID_MOD_POSITIVE = 0, /**< Mapping function is positive */
- FLUID_MOD_NEGATIVE = 1, /**< Mapping function is negative */
- FLUID_MOD_UNIPOLAR = 0, /**< Mapping function is unipolar */
- FLUID_MOD_BIPOLAR = 2, /**< Mapping function is bipolar */
- FLUID_MOD_LINEAR = 0, /**< Linear mapping function */
- FLUID_MOD_CONCAVE = 4, /**< Concave mapping function */
- FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
- FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
- FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
- FLUID_MOD_CC = 16 /**< MIDI CC controller (source will be a MIDI CC number) */
+ FLUID_MOD_POSITIVE = 0, /**< Mapping function is positive */
+ FLUID_MOD_NEGATIVE = 1, /**< Mapping function is negative */
+ FLUID_MOD_UNIPOLAR = 0, /**< Mapping function is unipolar */
+ FLUID_MOD_BIPOLAR = 2, /**< Mapping function is bipolar */
+ FLUID_MOD_LINEAR = 0, /**< Linear mapping function */
+ FLUID_MOD_CONCAVE = 4, /**< Concave mapping function */
+ FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
+ FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
+ FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
+ FLUID_MOD_CC = 16, /**< MIDI CC controller (source will be a MIDI CC number) */
+
+ FLUID_MOD_SIN = 0x80, /**< Custom non-standard sinus mapping function */
};
/**
@@ -78,32 +60,36 @@ enum fluid_mod_flags
*/
enum fluid_mod_src
{
- FLUID_MOD_NONE = 0, /**< No source controller */
- FLUID_MOD_VELOCITY = 2, /**< MIDI note-on velocity */
- FLUID_MOD_KEY = 3, /**< MIDI note-on note number */
- FLUID_MOD_KEYPRESSURE = 10, /**< MIDI key pressure */
- FLUID_MOD_CHANNELPRESSURE = 13, /**< MIDI channel pressure */
- FLUID_MOD_PITCHWHEEL = 14, /**< Pitch wheel */
- FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */
+ FLUID_MOD_NONE = 0, /**< No source controller */
+ FLUID_MOD_VELOCITY = 2, /**< MIDI note-on velocity */
+ FLUID_MOD_KEY = 3, /**< MIDI note-on note number */
+ FLUID_MOD_KEYPRESSURE = 10, /**< MIDI key pressure */
+ FLUID_MOD_CHANNELPRESSURE = 13, /**< MIDI channel pressure */
+ FLUID_MOD_PITCHWHEEL = 14, /**< Pitch wheel */
+ FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */
};
-FLUIDSYNTH_API fluid_mod_t* fluid_mod_new(void);
-FLUIDSYNTH_API void fluid_mod_delete(fluid_mod_t * mod);
+FLUIDSYNTH_API fluid_mod_t *new_fluid_mod(void);
+FLUIDSYNTH_API void delete_fluid_mod(fluid_mod_t *mod);
+FLUIDSYNTH_API size_t fluid_mod_sizeof(void);
-FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags);
-FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags);
-FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t* mod, int dst);
-FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t* mod, double amount);
+FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags);
+FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags);
+FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t *mod, int dst);
+FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t *mod, double amount);
-FLUIDSYNTH_API int fluid_mod_get_source1(fluid_mod_t* mod);
-FLUIDSYNTH_API int fluid_mod_get_flags1(fluid_mod_t* mod);
-FLUIDSYNTH_API int fluid_mod_get_source2(fluid_mod_t* mod);
-FLUIDSYNTH_API int fluid_mod_get_flags2(fluid_mod_t* mod);
-FLUIDSYNTH_API int fluid_mod_get_dest(fluid_mod_t* mod);
-FLUIDSYNTH_API double fluid_mod_get_amount(fluid_mod_t* mod);
+FLUIDSYNTH_API int fluid_mod_get_source1(const fluid_mod_t *mod);
+FLUIDSYNTH_API int fluid_mod_get_flags1(const fluid_mod_t *mod);
+FLUIDSYNTH_API int fluid_mod_get_source2(const fluid_mod_t *mod);
+FLUIDSYNTH_API int fluid_mod_get_flags2(const fluid_mod_t *mod);
+FLUIDSYNTH_API int fluid_mod_get_dest(const fluid_mod_t *mod);
+FLUIDSYNTH_API double fluid_mod_get_amount(const fluid_mod_t *mod);
-FLUIDSYNTH_API int fluid_mod_test_identity(fluid_mod_t * mod1, fluid_mod_t * mod2);
+FLUIDSYNTH_API int fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2);
+FLUIDSYNTH_API int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl);
+FLUIDSYNTH_API int fluid_mod_has_dest(const fluid_mod_t *mod, int gen);
+FLUIDSYNTH_API void fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src);
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/fluidsynth/settings.h b/libs/fluidsynth/fluidsynth/settings.h
index 3a0502a920..aa7f083129 100644
--- a/libs/fluidsynth/fluidsynth/settings.h
+++ b/libs/fluidsynth/fluidsynth/settings.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -78,35 +78,6 @@ extern "C" {
*/
#define FLUID_HINT_TOGGLED 0x4
-/**
- * Hint FLUID_HINT_SAMPLE_RATE indicates that any bounds specified
- * should be interpreted as multiples of the sample rate. For
- * instance, a frequency range from 0Hz to the Nyquist frequency (half
- * the sample rate) could be requested by this hint in conjunction
- * with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
- * at all must support this hint to retain meaning.
- */
-#define FLUID_HINT_SAMPLE_RATE 0x8
-
-/**
- * Hint FLUID_HINT_LOGARITHMIC indicates that it is likely that the
- * user will find it more intuitive to view values using a logarithmic
- * scale. This is particularly useful for frequencies and gains.
- */
-#define FLUID_HINT_LOGARITHMIC 0x10
-
-/**
- * Hint FLUID_HINT_INTEGER indicates that a user interface would
- * probably wish to provide a stepped control taking only integer
- * values.
- * @deprecated
- *
- * As there is an integer setting type, this hint is not used.
- */
-#define FLUID_HINT_INTEGER 0x20
-
-
-#define FLUID_HINT_FILENAME 0x01 /**< String setting is a file name */
#define FLUID_HINT_OPTIONLIST 0x02 /**< Setting is a list of string options */
@@ -117,70 +88,68 @@ extern "C" {
* set of values. The type of each setting can be retrieved using the
* function fluid_settings_get_type()
*/
-enum fluid_types_enum {
- FLUID_NO_TYPE = -1, /**< Undefined type */
- FLUID_NUM_TYPE, /**< Numeric (double) */
- FLUID_INT_TYPE, /**< Integer */
- FLUID_STR_TYPE, /**< String */
- FLUID_SET_TYPE /**< Set of values */
+enum fluid_types_enum
+{
+ FLUID_NO_TYPE = -1, /**< Undefined type */
+ FLUID_NUM_TYPE, /**< Numeric (double) */
+ FLUID_INT_TYPE, /**< Integer */
+ FLUID_STR_TYPE, /**< String */
+ FLUID_SET_TYPE /**< Set of values */
};
-FLUIDSYNTH_API fluid_settings_t* new_fluid_settings(void);
-FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t* settings);
-
-FLUIDSYNTH_API
-int fluid_settings_get_type(fluid_settings_t* settings, const char *name);
+FLUIDSYNTH_API fluid_settings_t *new_fluid_settings(void);
+FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t *settings);
FLUIDSYNTH_API
-int fluid_settings_get_hints(fluid_settings_t* settings, const char *name);
+int fluid_settings_get_type(fluid_settings_t *settings, const char *name);
FLUIDSYNTH_API
-int fluid_settings_is_realtime(fluid_settings_t* settings, const char *name);
+int fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *val);
FLUIDSYNTH_API
-int fluid_settings_setstr(fluid_settings_t* settings, const char *name, const char *str);
+int fluid_settings_is_realtime(fluid_settings_t *settings, const char *name);
FLUIDSYNTH_API
-int fluid_settings_copystr(fluid_settings_t* settings, const char *name, char *str, int len);
+int fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str);
FLUIDSYNTH_API
-int fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str);
+int fluid_settings_copystr(fluid_settings_t *settings, const char *name, char *str, int len);
FLUIDSYNTH_API
-int fluid_settings_getstr(fluid_settings_t* settings, const char *name, char** str);
+int fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str);
FLUIDSYNTH_API
-char* fluid_settings_getstr_default(fluid_settings_t* settings, const char *name);
+int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def);
FLUIDSYNTH_API
-int fluid_settings_str_equal(fluid_settings_t* settings, const char *name, const char *value);
+int fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *value);
FLUIDSYNTH_API
-int fluid_settings_setnum(fluid_settings_t* settings, const char *name, double val);
+int fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val);
FLUIDSYNTH_API
-int fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val);
+int fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val);
FLUIDSYNTH_API
-double fluid_settings_getnum_default(fluid_settings_t* settings, const char *name);
+int fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val);
FLUIDSYNTH_API
-void fluid_settings_getnum_range(fluid_settings_t* settings, const char *name,
- double* min, double* max);
+int fluid_settings_getnum_range(fluid_settings_t *settings, const char *name,
+ double *min, double *max);
FLUIDSYNTH_API
-int fluid_settings_setint(fluid_settings_t* settings, const char *name, int val);
+int fluid_settings_setint(fluid_settings_t *settings, const char *name, int val);
FLUIDSYNTH_API
-int fluid_settings_getint(fluid_settings_t* settings, const char *name, int* val);
+int fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val);
FLUIDSYNTH_API
-int fluid_settings_getint_default(fluid_settings_t* settings, const char *name);
+int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val);
FLUIDSYNTH_API
-void fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
- int* min, int* max);
+int fluid_settings_getint_range(fluid_settings_t *settings, const char *name,
+ int *min, int *max);
/**
* Callback function type used with fluid_settings_foreach_option()
@@ -188,17 +157,17 @@ void fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
* @param name Setting name
* @param option A string option for this setting (iterates through the list)
*/
-typedef void (*fluid_settings_foreach_option_t)(void *data, char *name, char *option);
+typedef void (*fluid_settings_foreach_option_t)(void *data, const char *name, const char *option);
FLUIDSYNTH_API
-void fluid_settings_foreach_option(fluid_settings_t* settings,
- const char* name, void* data,
- fluid_settings_foreach_option_t func);
+void fluid_settings_foreach_option(fluid_settings_t *settings,
+ const char *name, void *data,
+ fluid_settings_foreach_option_t func);
FLUIDSYNTH_API
-int fluid_settings_option_count (fluid_settings_t* settings, const char* name);
-FLUIDSYNTH_API char *fluid_settings_option_concat (fluid_settings_t* settings,
- const char* name,
- const char* separator);
+int fluid_settings_option_count(fluid_settings_t *settings, const char *name);
+FLUIDSYNTH_API char *fluid_settings_option_concat(fluid_settings_t *settings,
+ const char *name,
+ const char *separator);
/**
* Callback function type used with fluid_settings_foreach()
@@ -206,11 +175,11 @@ FLUIDSYNTH_API char *fluid_settings_option_concat (fluid_settings_t* settings,
* @param name Setting name
* @param type Setting type (#fluid_types_enum)
*/
-typedef void (*fluid_settings_foreach_t)(void *data, char *name, int type);
+typedef void (*fluid_settings_foreach_t)(void *data, const char *name, int type);
FLUIDSYNTH_API
-void fluid_settings_foreach(fluid_settings_t* settings, void* data,
- fluid_settings_foreach_t func);
+void fluid_settings_foreach(fluid_settings_t *settings, void *data,
+ fluid_settings_foreach_t func);
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/fluidsynth/sfont.h b/libs/fluidsynth/fluidsynth/sfont.h
index 30aebfd126..55413a9e24 100644
--- a/libs/fluidsynth/fluidsynth/sfont.h
+++ b/libs/fluidsynth/fluidsynth/sfont.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -31,30 +31,30 @@ extern "C" {
* @brief SoundFont plugins
*
* It is possible to add new SoundFont loaders to the
- * synthesizer. The API uses a couple of "interfaces" (structures
- * with callback functions): #fluid_sfloader_t, #fluid_sfont_t, and
- * #fluid_preset_t. This API allows for virtual SoundFont files to be loaded
+ * synthesizer. This API allows for virtual SoundFont files to be loaded
* and synthesized, which may not actually be SoundFont files, as long as they
* can be represented by the SoundFont synthesis model.
*
* To add a new SoundFont loader to the synthesizer, call
* fluid_synth_add_sfloader() and pass a pointer to an
- * fluid_sfloader_t structure. The important callback function in
- * this structure is "load", which should try to load a file and
- * returns a #fluid_sfont_t structure, or NULL if it fails.
+ * #fluid_sfloader_t instance created by new_fluid_sfloader().
+ * On creation, you must specify a callback function \p load
+ * that will be called for every file attempting to load it and
+ * if successful returns a #fluid_sfont_t instance, or NULL if it fails.
*
* The #fluid_sfont_t structure contains a callback to obtain the
* name of the SoundFont. It contains two functions to iterate
* though the contained presets, and one function to obtain a
* preset corresponding to a bank and preset number. This
- * function should return a #fluid_preset_t structure.
+ * function should return a #fluid_preset_t instance.
*
- * The #fluid_preset_t structure contains some functions to obtain
+ * The #fluid_preset_t instance contains some functions to obtain
* information from the preset (name, bank, number). The most
* important callback is the noteon function. The noteon function
+ * is called by fluidsynth internally and
* should call fluid_synth_alloc_voice() for every sample that has
* to be played. fluid_synth_alloc_voice() expects a pointer to a
- * #fluid_sample_t structure and returns a pointer to the opaque
+ * #fluid_sample_t instance and returns a pointer to the opaque
* #fluid_voice_t structure. To set or increment the values of a
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
* finished initializing the voice call fluid_voice_start() to
@@ -64,215 +64,250 @@ extern "C" {
/**
* Some notification enums for presets and samples.
*/
-enum {
- FLUID_PRESET_SELECTED, /**< Preset selected notify */
- FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
- FLUID_SAMPLE_DONE /**< Sample no longer needed notify */
+enum
+{
+ FLUID_PRESET_SELECTED, /**< Preset selected notify */
+ FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
+ FLUID_SAMPLE_DONE /**< Sample no longer needed notify */
};
-
/**
- * SoundFont loader structure.
+ * Indicates the type of a sample used by the _fluid_sample_t::sampletype field.
*/
-struct _fluid_sfloader_t {
- void* data; /**< User defined data pointer */
-
- /**
- * The free method should free the memory allocated for the loader in
- * addition to any private data.
- * @param loader SoundFont loader
- * @return Should return 0 if no error occured, non-zero otherwise
- */
- int (*free)(fluid_sfloader_t* loader);
-
- /**
- * Method to load an instrument file (does not actually need to be a real file name,
- * could be another type of string identifier that the \a loader understands).
- * @param loader SoundFont loader
- * @param filename File name or other string identifier
- * @return The loaded instrument file (SoundFont) or NULL if an error occured.
- */
- fluid_sfont_t* (*load)(fluid_sfloader_t* loader, const char* filename);
+enum fluid_sample_type
+{
+ FLUID_SAMPLETYPE_MONO = 0x1, /**< Used for mono samples */
+ FLUID_SAMPLETYPE_RIGHT = 0x2, /**< Used for right samples of a stereo pair */
+ FLUID_SAMPLETYPE_LEFT = 0x4, /**< Used for left samples of a stereo pair */
+ FLUID_SAMPLETYPE_LINKED = 0x8, /**< Currently not used */
+ FLUID_SAMPLETYPE_OGG_VORBIS = 0x10, /**< Used for Ogg Vorbis compressed samples @since 1.1.7 */
+ FLUID_SAMPLETYPE_ROM = 0x8000 /**< Indicates ROM samples, causes sample to be ignored */
};
+
/**
- * Virtual SoundFont instance structure.
+ * Method to load an instrument file (does not actually need to be a real file name,
+ * could be another type of string identifier that the \a loader understands).
+ * @param loader SoundFont loader
+ * @param filename File name or other string identifier
+ * @return The loaded instrument file (SoundFont) or NULL if an error occured.
*/
-struct _fluid_sfont_t {
- void* data; /**< User defined data */
- unsigned int id; /**< SoundFont ID */
-
- /**
- * Method to free a virtual SoundFont bank.
- * @param sfont Virtual SoundFont to free.
- * @return Should return 0 when it was able to free all resources or non-zero
- * if some of the samples could not be freed because they are still in use,
- * in which case the free will be tried again later, until success.
- */
- int (*free)(fluid_sfont_t* sfont);
-
- /**
- * Method to return the name of a virtual SoundFont.
- * @param sfont Virtual SoundFont
- * @return The name of the virtual SoundFont.
- */
- char* (*get_name)(fluid_sfont_t* sfont);
-
- /**
- * Get a virtual SoundFont preset by bank and program numbers.
- * @param sfont Virtual SoundFont
- * @param bank MIDI bank number (0-16384)
- * @param prenum MIDI preset number (0-127)
- * @return Should return an allocated virtual preset or NULL if it could not
- * be found.
- */
- fluid_preset_t* (*get_preset)(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
-
- /**
- * Start virtual SoundFont preset iteration method.
- * @param sfont Virtual SoundFont
- *
- * Starts/re-starts virtual preset iteration in a SoundFont.
- */
- void (*iteration_start)(fluid_sfont_t* sfont);
-
- /**
- * Virtual SoundFont preset iteration function.
- * @param sfont Virtual SoundFont
- * @param preset Caller supplied preset to fill in with current preset information
- * @return 0 when no more presets are available, 1 otherwise
- *
- * Should store preset information to the caller supplied \a preset structure
- * and advance the internal iteration state to the next preset for subsequent
- * calls.
- */
- int (*iteration_next)(fluid_sfont_t* sfont, fluid_preset_t* preset);
-};
+typedef fluid_sfont_t *(*fluid_sfloader_load_t)(fluid_sfloader_t *loader, const char *filename);
+
+/**
+ * The free method should free the memory allocated for a fluid_sfloader_t instance in
+ * addition to any private data. Any custom user provided cleanup function must ultimately call
+ * delete_fluid_sfloader() to ensure proper cleanup of the #fluid_sfloader_t struct. If no private data
+ * needs to be freed, setting this to delete_fluid_sfloader() is sufficient.
+ * @param loader SoundFont loader
+ */
+typedef void (*fluid_sfloader_free_t)(fluid_sfloader_t *loader);
+
+
+FLUIDSYNTH_API fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free);
+FLUIDSYNTH_API void delete_fluid_sfloader(fluid_sfloader_t *loader);
-#define fluid_sfont_get_id(_sf) ((_sf)->id)
+FLUIDSYNTH_API fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings);
/**
- * Virtual SoundFont preset.
+ * Opens the file or memory indicated by \c filename in binary read mode.
+ * \c filename matches the string provided during the fluid_synth_sfload() call.
+ *
+ * @return returns a file handle on success, NULL otherwise
*/
-struct _fluid_preset_t {
- void* data; /**< User supplied data */
- fluid_sfont_t* sfont; /**< Parent virtual SoundFont */
-
- /**
- * Method to free a virtual SoundFont preset.
- * @param preset Virtual SoundFont preset
- * @return Should return 0
- */
- int (*free)(fluid_preset_t* preset);
-
- /**
- * Method to get a virtual SoundFont preset name.
- * @param preset Virtual SoundFont preset
- * @return Should return the name of the preset. The returned string must be
- * valid for the duration of the virtual preset (or the duration of the
- * SoundFont, in the case of preset iteration).
- */
- char* (*get_name)(fluid_preset_t* preset);
-
- /**
- * Method to get a virtual SoundFont preset MIDI bank number.
- * @param preset Virtual SoundFont preset
- * @param return The bank number of the preset
- */
- int (*get_banknum)(fluid_preset_t* preset);
-
- /**
- * Method to get a virtual SoundFont preset MIDI program number.
- * @param preset Virtual SoundFont preset
- * @param return The program number of the preset
- */
- int (*get_num)(fluid_preset_t* preset);
-
- /**
- * Method to handle a noteon event (synthesize the instrument).
- * @param preset Virtual SoundFont preset
- * @param synth Synthesizer instance
- * @param chan MIDI channel number of the note on event
- * @param key MIDI note number (0-127)
- * @param vel MIDI velocity (0-127)
- * @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
- *
- * This method may be called from within synthesis context and therefore
- * should be as efficient as possible and not perform any operations considered
- * bad for realtime audio output (memory allocations and other OS calls).
- *
- * Call fluid_synth_alloc_voice() for every sample that has
- * to be played. fluid_synth_alloc_voice() expects a pointer to a
- * #fluid_sample_t structure and returns a pointer to the opaque
- * #fluid_voice_t structure. To set or increment the values of a
- * generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
- * finished initializing the voice call fluid_voice_start() to
- * start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
- * created will be started at the same time.
- */
- int (*noteon)(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
-
- /**
- * Virtual SoundFont preset notify method.
- * @param preset Virtual SoundFont preset
- * @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED
- * @param chan MIDI channel number
- * @return Should return #FLUID_OK
- *
- * Implement this optional method if the preset needs to be notified about
- * preset select and unselect events.
- *
- * This method may be called from within synthesis context and therefore
- * should be as efficient as possible and not perform any operations considered
- * bad for realtime audio output (memory allocations and other OS calls).
- */
- int (*notify)(fluid_preset_t* preset, int reason, int chan);
-};
+typedef void *(* fluid_sfloader_callback_open_t)(const char *filename);
/**
- * Virtual SoundFont sample.
+ * Reads \c count bytes to the specified buffer \c buf.
+ *
+ * @return returns #FLUID_OK if exactly \c count bytes were successfully read, else returns #FLUID_FAILED and leaves \a buf unmodified.
*/
-struct _fluid_sample_t
-{
- char name[21]; /**< Sample name */
- unsigned int start; /**< Start index */
- unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */
- unsigned int loopstart; /**< Loop start index */
- unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */
- unsigned int samplerate; /**< Sample rate */
- int origpitch; /**< Original pitch (MIDI note number, 0-127) */
- int pitchadj; /**< Fine pitch adjustment (+/- 99 cents) */
- int sampletype; /**< Values: #FLUID_SAMPLETYPE_MONO, FLUID_SAMPLETYPE_RIGHT, FLUID_SAMPLETYPE_LEFT, FLUID_SAMPLETYPE_ROM */
- int valid; /**< Should be TRUE if sample data is valid, FALSE otherwise (in which case it will not be synthesized) */
- short* data; /**< Pointer to the sample's data */
-
- int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */
- double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */
-
- unsigned int refcount; /**< Count of voices using this sample (use #fluid_sample_refcount to access this field) */
-
- /**
- * Implement this function to receive notification when sample is no longer used.
- * @param sample Virtual SoundFont sample
- * @param reason #FLUID_SAMPLE_DONE only currently
- * @return Should return #FLUID_OK
- */
- int (*notify)(fluid_sample_t* sample, int reason);
-
- void* userdata; /**< User defined data */
-};
+typedef int (* fluid_sfloader_callback_read_t)(void *buf, int count, void *handle);
+
+/**
+ * Same purpose and behaviour as fseek.
+ *
+ * @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
+ *
+ * @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise
+ */
+typedef int (* fluid_sfloader_callback_seek_t)(void *handle, long offset, int origin);
+
+/**
+ * Closes the handle returned by #fluid_sfloader_callback_open_t and frees used ressources.
+ *
+ * @return returns #FLUID_OK on success, #FLUID_FAILED on error
+ */
+typedef int (* fluid_sfloader_callback_close_t)(void *handle);
+
+/** @return returns current file offset or #FLUID_FAILED on error */
+typedef long (* fluid_sfloader_callback_tell_t)(void *handle);
+
+
+FLUIDSYNTH_API int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
+ fluid_sfloader_callback_open_t open,
+ fluid_sfloader_callback_read_t read,
+ fluid_sfloader_callback_seek_t seek,
+ fluid_sfloader_callback_tell_t tell,
+ fluid_sfloader_callback_close_t close);
+
+FLUIDSYNTH_API int fluid_sfloader_set_data(fluid_sfloader_t *loader, void *data);
+FLUIDSYNTH_API void *fluid_sfloader_get_data(fluid_sfloader_t *loader);
+
+
+
+/**
+ * Method to return the name of a virtual SoundFont.
+ * @param sfont Virtual SoundFont
+ * @return The name of the virtual SoundFont.
+ */
+typedef const char *(*fluid_sfont_get_name_t)(fluid_sfont_t *sfont);
+
+/**
+ * Get a virtual SoundFont preset by bank and program numbers.
+ * @param sfont Virtual SoundFont
+ * @param bank MIDI bank number (0-16383)
+ * @param prenum MIDI preset number (0-127)
+ * @return Should return an allocated virtual preset or NULL if it could not
+ * be found.
+ */
+typedef fluid_preset_t *(*fluid_sfont_get_preset_t)(fluid_sfont_t *sfont, int bank, int prenum);
+
+/**
+ * Start virtual SoundFont preset iteration method.
+ * @param sfont Virtual SoundFont
+ *
+ * Starts/re-starts virtual preset iteration in a SoundFont.
+ */
+typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t *sfont);
+
+/**
+ * Virtual SoundFont preset iteration function.
+ * @param sfont Virtual SoundFont
+ * @param preset Caller supplied uninitialized buffer to fill in with current preset information
+ * @return NULL when no more presets are available, otherwise the a pointer to the current preset
+ *
+ * Should store preset information to the caller supplied \a preset structure
+ * and advance the internal iteration state to the next preset for subsequent
+ * calls.
+ */
+typedef fluid_preset_t *(*fluid_sfont_iteration_next_t)(fluid_sfont_t *sfont);
+
+/**
+ * Method to free a virtual SoundFont bank. Any custom user provided cleanup function must ultimately call
+ * delete_fluid_sfont() to ensure proper cleanup of the #fluid_sfont_t struct. If no private data
+ * needs to be freed, setting this to delete_fluid_sfont() is sufficient.
+ * @param sfont Virtual SoundFont to free.
+ * @return Should return 0 when it was able to free all resources or non-zero
+ * if some of the samples could not be freed because they are still in use,
+ * in which case the free will be tried again later, until success.
+ */
+typedef int (*fluid_sfont_free_t)(fluid_sfont_t *sfont);
-#define fluid_sample_refcount(_sample) ((_sample)->refcount) /**< Get the reference count of a sample. Should only be called from within synthesis context (noteon method for example) */
+FLUIDSYNTH_API fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name,
+ fluid_sfont_get_preset_t get_preset,
+ fluid_sfont_iteration_start_t iter_start,
+ fluid_sfont_iteration_next_t iter_next,
+ fluid_sfont_free_t free);
+FLUIDSYNTH_API int delete_fluid_sfont(fluid_sfont_t *sfont);
-#define FLUID_SAMPLETYPE_MONO 1 /**< Flag for #fluid_sample_t \a sampletype field for mono samples */
-#define FLUID_SAMPLETYPE_RIGHT 2 /**< Flag for #fluid_sample_t \a sampletype field for right samples of a stereo pair */
-#define FLUID_SAMPLETYPE_LEFT 4 /**< Flag for #fluid_sample_t \a sampletype field for left samples of a stereo pair */
-#define FLUID_SAMPLETYPE_LINKED 8 /**< Flag for #fluid_sample_t \a sampletype field, not used currently */
-#define FLUID_SAMPLETYPE_ROM 0x8000 /**< Flag for #fluid_sample_t \a sampletype field, ROM sample, causes sample to be ignored */
+FLUIDSYNTH_API int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data);
+FLUIDSYNTH_API void *fluid_sfont_get_data(fluid_sfont_t *sfont);
+FLUIDSYNTH_API int fluid_sfont_get_id(fluid_sfont_t *sfont);
+FLUIDSYNTH_API const char *fluid_sfont_get_name(fluid_sfont_t *sfont);
+FLUIDSYNTH_API fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum);
+FLUIDSYNTH_API void fluid_sfont_iteration_start(fluid_sfont_t *sfont);
+FLUIDSYNTH_API fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont);
+/**
+ * Method to get a virtual SoundFont preset name.
+ * @param preset Virtual SoundFont preset
+ * @return Should return the name of the preset. The returned string must be
+ * valid for the duration of the virtual preset (or the duration of the
+ * SoundFont, in the case of preset iteration).
+ */
+typedef const char *(*fluid_preset_get_name_t)(fluid_preset_t *preset);
+
+/**
+ * Method to get a virtual SoundFont preset MIDI bank number.
+ * @param preset Virtual SoundFont preset
+ * @param return The bank number of the preset
+ */
+typedef int (*fluid_preset_get_banknum_t)(fluid_preset_t *preset);
+
+/**
+ * Method to get a virtual SoundFont preset MIDI program number.
+ * @param preset Virtual SoundFont preset
+ * @param return The program number of the preset
+ */
+typedef int (*fluid_preset_get_num_t)(fluid_preset_t *preset);
+
+/**
+ * Method to handle a noteon event (synthesize the instrument).
+ * @param preset Virtual SoundFont preset
+ * @param synth Synthesizer instance
+ * @param chan MIDI channel number of the note on event
+ * @param key MIDI note number (0-127)
+ * @param vel MIDI velocity (0-127)
+ * @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
+ *
+ * This method may be called from within synthesis context and therefore
+ * should be as efficient as possible and not perform any operations considered
+ * bad for realtime audio output (memory allocations and other OS calls).
+ *
+ * Call fluid_synth_alloc_voice() for every sample that has
+ * to be played. fluid_synth_alloc_voice() expects a pointer to a
+ * #fluid_sample_t structure and returns a pointer to the opaque
+ * #fluid_voice_t structure. To set or increment the values of a
+ * generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
+ * finished initializing the voice call fluid_voice_start() to
+ * start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
+ * created will be started at the same time.
+ */
+typedef int (*fluid_preset_noteon_t)(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel);
+
+/**
+ * Method to free a virtual SoundFont preset. Any custom user provided cleanup function must ultimately call
+ * delete_fluid_preset() to ensure proper cleanup of the #fluid_preset_t struct. If no private data
+ * needs to be freed, setting this to delete_fluid_preset() is sufficient.
+ * @param preset Virtual SoundFont preset
+ * @return Should return 0
+ */
+typedef void (*fluid_preset_free_t)(fluid_preset_t *preset);
+
+FLUIDSYNTH_API fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont,
+ fluid_preset_get_name_t get_name,
+ fluid_preset_get_banknum_t get_bank,
+ fluid_preset_get_num_t get_num,
+ fluid_preset_noteon_t noteon,
+ fluid_preset_free_t free);
+FLUIDSYNTH_API void delete_fluid_preset(fluid_preset_t *preset);
+
+FLUIDSYNTH_API int fluid_preset_set_data(fluid_preset_t *preset, void *data);
+FLUIDSYNTH_API void *fluid_preset_get_data(fluid_preset_t *preset);
+
+FLUIDSYNTH_API const char *fluid_preset_get_name(fluid_preset_t *preset);
+FLUIDSYNTH_API int fluid_preset_get_banknum(fluid_preset_t *preset);
+FLUIDSYNTH_API int fluid_preset_get_num(fluid_preset_t *preset);
+FLUIDSYNTH_API fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset);
+
+FLUIDSYNTH_API fluid_sample_t *new_fluid_sample(void);
+FLUIDSYNTH_API void delete_fluid_sample(fluid_sample_t *sample);
+FLUIDSYNTH_API size_t fluid_sample_sizeof(void);
+
+FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t *sample, const char *name);
+FLUIDSYNTH_API int fluid_sample_set_sound_data(fluid_sample_t *sample,
+ short *data,
+ char *data24,
+ unsigned int nbframes,
+ unsigned int sample_rate,
+ short copy_data);
+
+FLUIDSYNTH_API int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end);
+FLUIDSYNTH_API int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune);
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/fluidsynth/synth.h b/libs/fluidsynth/fluidsynth/synth.h
index f62e60cd1b..a4afb90947 100644
--- a/libs/fluidsynth/fluidsynth/synth.h
+++ b/libs/fluidsynth/fluidsynth/synth.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -30,126 +30,112 @@ extern "C" {
/**
* @file synth.h
* @brief Embeddable SoundFont synthesizer
- *
+ *
* You create a new synthesizer with new_fluid_synth() and you destroy
* if with delete_fluid_synth(). Use the settings structure to specify
- * the synthesizer characteristics.
+ * the synthesizer characteristics.
*
* You have to load a SoundFont in order to hear any sound. For that
* you use the fluid_synth_sfload() function.
*
* You can use the audio driver functions described below to open
* the audio device and create a background audio thread.
- *
+ *
* The API for sending MIDI events is probably what you expect:
* fluid_synth_noteon(), fluid_synth_noteoff(), ...
*/
-#define FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE 32 /**< Length of channel info name field (including zero terminator) */
-
-/**
- * Channel information structure for fluid_synth_get_channel_info().
- * @since 1.1.1
- */
-struct _fluid_synth_channel_info_t
-{
- int assigned : 1; /**< TRUE if a preset is assigned, FALSE otherwise */
- /* Reserved flag bits (at the least 31) */
- int sfont_id; /**< ID of parent SoundFont */
- int bank; /**< MIDI bank number (0-16383) */
- int program; /**< MIDI program number (0-127) */
- char name[FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE]; /**< Channel preset name */
- char reserved[32]; /**< Reserved data for future expansion */
-};
-
-FLUIDSYNTH_API fluid_synth_t* new_fluid_synth(fluid_settings_t* settings);
-FLUIDSYNTH_API int delete_fluid_synth(fluid_synth_t* synth);
-FLUIDSYNTH_API fluid_settings_t* fluid_synth_get_settings(fluid_synth_t* synth);
+FLUIDSYNTH_API fluid_synth_t *new_fluid_synth(fluid_settings_t *settings);
+FLUIDSYNTH_API void delete_fluid_synth(fluid_synth_t *synth);
+FLUIDSYNTH_API fluid_settings_t *fluid_synth_get_settings(fluid_synth_t *synth);
/* MIDI channel messages */
-FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel);
-FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key);
-FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t* synth, int chan, int ctrl, int val);
-FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t* synth, int chan, int ctrl, int* pval);
+FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t *synth, int chan, int key, int vel);
+FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t *synth, int chan, int key);
+FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t *synth, int chan, int ctrl, int val);
+FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t *synth, int chan, int ctrl, int *pval);
FLUIDSYNTH_API int fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
char *response, int *response_len, int *handled, int dryrun);
-FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val);
-FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend);
-FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val);
-FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
-FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
-FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val);
-FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
-FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id);
+FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t *synth, int chan, int val);
+FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t *synth, int chan, int *ppitch_bend);
+FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t *synth, int chan, int val);
+FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t *synth, int chan, int *pval);
+FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t *synth, int chan, int program);
+FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t *synth, int chan, int val);
+FLUIDSYNTH_API int fluid_synth_key_pressure(fluid_synth_t *synth, int chan, int key, int val);
+FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t *synth, int chan, int bank);
+FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t *synth, int chan, int sfont_id);
FLUIDSYNTH_API
-int fluid_synth_program_select(fluid_synth_t* synth, int chan, unsigned int sfont_id,
- unsigned int bank_num, unsigned int preset_num);
+int fluid_synth_program_select(fluid_synth_t *synth, int chan, int sfont_id,
+ int bank_num, int preset_num);
FLUIDSYNTH_API int
-fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
- const char *sfont_name, unsigned int bank_num,
- unsigned int preset_num);
-FLUIDSYNTH_API
-int fluid_synth_get_program(fluid_synth_t* synth, int chan, unsigned int* sfont_id,
- unsigned int* bank_num, unsigned int* preset_num);
-FLUIDSYNTH_API int fluid_synth_unset_program (fluid_synth_t *synth, int chan);
-FLUIDSYNTH_API int fluid_synth_get_channel_info (fluid_synth_t *synth, int chan,
- fluid_synth_channel_info_t *info);
-FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
-
-FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan);
-FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan);
+fluid_synth_program_select_by_sfont_name(fluid_synth_t *synth, int chan,
+ const char *sfont_name, int bank_num,
+ int preset_num);
+FLUIDSYNTH_API
+int fluid_synth_get_program(fluid_synth_t *synth, int chan, int *sfont_id,
+ int *bank_num, int *preset_num);
+FLUIDSYNTH_API int fluid_synth_unset_program(fluid_synth_t *synth, int chan);
+FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t *synth, int chan);
+FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t *synth, int chan);
+
+/**
+ * The midi channel type used by fluid_synth_set_channel_type()
+ */
enum fluid_midi_channel_type
{
- CHANNEL_TYPE_MELODIC = 0,
- CHANNEL_TYPE_DRUM = 1
+ CHANNEL_TYPE_MELODIC = 0, /**< Melodic midi channel */
+ CHANNEL_TYPE_DRUM = 1 /**< Drum midi channel */
};
-int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type);
+FLUIDSYNTH_API int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type);
/* Low level access */
-FLUIDSYNTH_API fluid_preset_t* fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan);
-FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t* synth, unsigned int id,
- fluid_preset_t* preset, int audio_chan,
- int midi_chan, int key, int vel);
-FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t* synth, unsigned int id);
+FLUIDSYNTH_API fluid_preset_t *fluid_synth_get_channel_preset(fluid_synth_t *synth, int chan);
+FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t *synth, unsigned int id,
+ fluid_preset_t *preset, int audio_chan,
+ int midi_chan, int key, int vel);
+FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t *synth, unsigned int id);
/* SoundFont management */
-FLUIDSYNTH_API
-int fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets);
-FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
-FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets);
-FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
-FLUIDSYNTH_API void fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
-FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t* synth);
-FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num);
-FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id);
-FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_name (fluid_synth_t* synth,
- const char *name);
-FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset);
-FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id);
+FLUIDSYNTH_API
+int fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets);
+FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t *synth, int id);
+FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets);
+FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont);
+FLUIDSYNTH_API int fluid_synth_remove_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont);
+FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t *synth);
+FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont(fluid_synth_t *synth, unsigned int num);
+FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_id(fluid_synth_t *synth, int id);
+FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_name(fluid_synth_t *synth,
+ const char *name);
+FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t *synth, int sfont_id, int offset);
+FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t *synth, int sfont_id);
/* Reverb */
-FLUIDSYNTH_API void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize,
- double damping, double width, double level);
-FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t* synth, int on);
-FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t* synth);
-FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t* synth);
-FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t* synth);
-FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t* synth);
-#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f /**< Default reverb room size */
-#define FLUID_REVERB_DEFAULT_DAMP 0.0f /**< Default reverb damping */
-#define FLUID_REVERB_DEFAULT_WIDTH 0.5f /**< Default reverb width */
-#define FLUID_REVERB_DEFAULT_LEVEL 0.9f /**< Default reverb level */
+FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize,
+ double damping, double width, double level);
+FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize);
+FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping);
+FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width);
+FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level);
+
+FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on);
+FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth);
+FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t *synth);
+FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t *synth);
+FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t *synth);
/* Chorus */
@@ -157,107 +143,112 @@ FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t* synth);
/**
* Chorus modulation waveform type.
*/
-enum fluid_chorus_mod {
- FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */
- FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
+enum fluid_chorus_mod
+{
+ FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */
+ FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
};
-FLUIDSYNTH_API void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
- double speed, double depth_ms, int type);
-FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t* synth, int on);
-FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t* synth);
-FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t* synth);
-FLUIDSYNTH_API double fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth);
-FLUIDSYNTH_API double fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t* synth); /* see fluid_chorus_mod */
+FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level,
+ double speed, double depth_ms, int type);
+FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr);
+FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level);
+FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed);
+FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms);
+FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type);
-#define FLUID_CHORUS_DEFAULT_N 3 /**< Default chorus voice count */
-#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f /**< Default chorus level */
-#define FLUID_CHORUS_DEFAULT_SPEED 0.3f /**< Default chorus speed */
-#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f /**< Default chorus depth */
-#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE /**< Default chorus waveform type */
+FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on);
+FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t *synth);
+FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t *synth);
+FLUIDSYNTH_API double fluid_synth_get_chorus_speed(fluid_synth_t *synth);
+FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */
/* Audio and MIDI channels */
-FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t* synth);
+FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_count_effects_groups(fluid_synth_t *synth);
/* Synthesis parameters */
-FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t* synth, float sample_rate);
-FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t* synth, float gain);
-FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony);
-FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_get_active_voice_count(fluid_synth_t* synth);
-FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t* synth);
+FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate);
+FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t *synth, float gain);
+FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t *synth, int polyphony);
+FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_get_active_voice_count(fluid_synth_t *synth);
+FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t *synth);
-FLUIDSYNTH_API
-int fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method);
+FLUIDSYNTH_API
+int fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method);
/**
* Synthesis interpolation method.
*/
-enum fluid_interp {
- FLUID_INTERP_NONE = 0, /**< No interpolation: Fastest, but questionable audio quality */
- FLUID_INTERP_LINEAR = 1, /**< Straight-line interpolation: A bit slower, reasonable audio quality */
- FLUID_INTERP_4THORDER = 4, /**< Fourth-order interpolation, good quality, the default */
- FLUID_INTERP_7THORDER = 7 /**< Seventh-order interpolation */
-};
-
-#define FLUID_INTERP_DEFAULT FLUID_INTERP_4THORDER /**< Default interpolation method from #fluid_interp. */
-#define FLUID_INTERP_HIGHEST FLUID_INTERP_7THORDER /**< Highest interpolation method from #fluid_interp. */
+enum fluid_interp
+{
+ FLUID_INTERP_NONE = 0, /**< No interpolation: Fastest, but questionable audio quality */
+ FLUID_INTERP_LINEAR = 1, /**< Straight-line interpolation: A bit slower, reasonable audio quality */
+ FLUID_INTERP_4THORDER = 4, /**< Fourth-order interpolation, good quality, the default */
+ FLUID_INTERP_7THORDER = 7, /**< Seventh-order interpolation */
+ FLUID_INTERP_DEFAULT = FLUID_INTERP_4THORDER, /**< Default interpolation method */
+ FLUID_INTERP_HIGHEST = FLUID_INTERP_7THORDER, /**< Highest interpolation method */
+};
/* Generator interface */
-FLUIDSYNTH_API
-int fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value);
-FLUIDSYNTH_API int fluid_synth_set_gen2 (fluid_synth_t* synth, int chan,
- int param, float value,
- int absolute, int normalized);
-FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
+FLUIDSYNTH_API int fluid_synth_set_gen(fluid_synth_t *synth, int chan,
+ int param, float value);
+FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param);
/* Tuning */
-FLUIDSYNTH_API
-int fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch);
FLUIDSYNTH_API
-int fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch, int apply);
-FLUIDSYNTH_API
-int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch);
+int fluid_synth_activate_key_tuning(fluid_synth_t *synth, int bank, int prog,
+ const char *name, const double *pitch, int apply);
+FLUIDSYNTH_API
+int fluid_synth_activate_octave_tuning(fluid_synth_t *synth, int bank, int prog,
+ const char *name, const double *pitch, int apply);
FLUIDSYNTH_API
-int fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch, int apply);
-FLUIDSYNTH_API
-int fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
- int len, const int *keys, const double* pitch, int apply);
-FLUIDSYNTH_API
-int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog);
+int fluid_synth_tune_notes(fluid_synth_t *synth, int bank, int prog,
+ int len, const int *keys, const double *pitch, int apply);
FLUIDSYNTH_API
-int fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
+int fluid_synth_activate_tuning(fluid_synth_t *synth, int chan, int bank, int prog,
int apply);
-FLUIDSYNTH_API int fluid_synth_reset_tuning(fluid_synth_t* synth, int chan);
FLUIDSYNTH_API
-int fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply);
-FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t* synth);
-FLUIDSYNTH_API
-int fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog);
-FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
- char* name, int len, double* pitch);
+int fluid_synth_deactivate_tuning(fluid_synth_t *synth, int chan, int apply);
+FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t *synth);
+FLUIDSYNTH_API
+int fluid_synth_tuning_iteration_next(fluid_synth_t *synth, int *bank, int *prog);
+FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int prog,
+ char *name, int len, double *pitch);
/* Misc */
-FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t* synth);
-FLUIDSYNTH_API char* fluid_synth_error(fluid_synth_t* synth);
+FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t *synth);
+FLUIDSYNTH_API const char *fluid_synth_error(fluid_synth_t *synth);
+
+
+/* Default modulators */
+
+/**
+ * Enum used with fluid_synth_add_default_mod() to specify how to handle duplicate modulators.
+ */
+enum fluid_synth_add_mod
+{
+ FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */
+ FLUID_SYNTH_ADD, /**< Add (sum) modulator amounts */
+};
+
+FLUIDSYNTH_API int fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode);
+FLUIDSYNTH_API int fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod);
/*
@@ -265,48 +256,141 @@ FLUIDSYNTH_API char* fluid_synth_error(fluid_synth_t* synth);
*
* To create a synthesizer plugin, create the synthesizer as
* explained above. Once the synthesizer is created you can call
- * any of the functions below to get the audio.
+ * any of the functions below to get the audio.
*/
-FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t* synth, int len,
- void* lout, int loff, int lincr,
- void* rout, int roff, int rincr);
-FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t* synth, int len,
- void* lout, int loff, int lincr,
- void* rout, int roff, int rincr);
-FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
- float** left, float** right,
- float** fx_left, float** fx_right);
-FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t* synth, int len,
- int nin, float** in,
- int nout, float** out);
+FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t *synth, int len,
+ void *lout, int loff, int lincr,
+ void *rout, int roff, int rincr);
+FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t *synth, int len,
+ void *lout, int loff, int lincr,
+ void *rout, int roff, int rincr);
+FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
+ float **left, float **right,
+ float **fx_left, float **fx_right);
+FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t *synth, int len,
+ int nfx, float *fx[],
+ int nout, float *out[]);
+
+
+/* Synthesizer's interface to handle SoundFont loaders */
+
+FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t *synth, fluid_sfloader_t *loader);
+FLUIDSYNTH_API fluid_voice_t *fluid_synth_alloc_voice(fluid_synth_t *synth,
+ fluid_sample_t *sample,
+ int channum, int key, int vel);
+FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t *synth, fluid_voice_t *voice);
+FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t *synth,
+ fluid_voice_t *buf[], int bufsize, int ID);
+FLUIDSYNTH_API int fluid_synth_handle_midi_event(void *data, fluid_midi_event_t *event);
+
+/**
+ * Specifies the type of filter to use for the custom IIR filter
+ */
+enum fluid_iir_filter_type
+{
+ FLUID_IIR_DISABLED = 0, /**< Custom IIR filter is not operating */
+ FLUID_IIR_LOWPASS, /**< Custom IIR filter is operating as low-pass filter */
+ FLUID_IIR_HIGHPASS, /**< Custom IIR filter is operating as high-pass filter */
+ FLUID_IIR_LAST /**< @internal Value defines the count of filter types (#fluid_iir_filter_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
+};
/**
- * Type definition of the synthesizer's audio callback function.
- * @param synth FluidSynth instance
- * @param len Count of audio frames to synthesize
- * @param out1 Array to store left channel of audio to
- * @param loff Offset index in 'out1' for first sample
- * @param lincr Increment between samples stored to 'out1'
- * @param out2 Array to store right channel of audio to
- * @param roff Offset index in 'out2' for first sample
- * @param rincr Increment between samples stored to 'out2'
+ * Specifies optional settings to use for the custom IIR filter
*/
-typedef int (*fluid_audio_callback_t)(fluid_synth_t* synth, int len,
- void* out1, int loff, int lincr,
- void* out2, int roff, int rincr);
+enum fluid_iir_filter_flags
+{
+ FLUID_IIR_Q_LINEAR = 1 << 0, /**< The Soundfont spec requires the filter Q to be interpreted in dB. If this flag is set the filter Q is instead assumed to be in a linear range */
+ FLUID_IIR_Q_ZERO_OFF = 1 << 1, /**< If this flag the filter is switched off if Q == 0 (prior to any transformation) */
+ FLUID_IIR_NO_GAIN_AMP = 1 << 2 /**< The Soundfont spec requires to correct the gain of the filter depending on the filter's Q. If this flag is set the filter gain will not be corrected. */
+};
-/* Synthesizer's interface to handle SoundFont loaders */
+FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int flags);
+
+
+/* LADSPA */
+
+#ifdef LADSPA
+FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
+#endif
+
+
+/* API: Poly mono mode */
+
+/** Interface to poly/mono mode variables
+ *
+ * Channel mode bits OR-ed together so that it matches with the midi spec: poly omnion (0), mono omnion (1), poly omnioff (2), mono omnioff (3)
+ */
+enum fluid_channel_mode_flags
+{
+ FLUID_CHANNEL_POLY_OFF = 0x01, /**< if flag is set, the basic channel is in mono on state, if not set poly is on */
+ FLUID_CHANNEL_OMNI_OFF = 0x02, /**< if flag is set, the basic channel is in omni off state, if not set omni is on */
+};
+
+/** Indicates the breath mode a channel is set to */
+enum fluid_channel_breath_flags
+{
+ FLUID_CHANNEL_BREATH_POLY = 0x10, /**< when channel is poly, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath to initial attenuation modulator */
+ FLUID_CHANNEL_BREATH_MONO = 0x20, /**< when channel is mono, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath modulator */
+ FLUID_CHANNEL_BREATH_SYNC = 0x40, /**< when channel is mono, this flag indicates that the breath controler(MSB)triggers noteon/noteoff on the running note */
+};
+
+/** Indicates the mode a basic channel is set to */
+enum fluid_basic_channel_modes
+{
+ FLUID_CHANNEL_MODE_MASK = (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< Mask Poly and Omni bits of #fluid_channel_mode_flags, usually only used internally */
+ FLUID_CHANNEL_MODE_OMNION_POLY = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 0 */
+ FLUID_CHANNEL_MODE_OMNION_MONO = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 1 */
+ FLUID_CHANNEL_MODE_OMNIOFF_POLY = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 2 */
+ FLUID_CHANNEL_MODE_OMNIOFF_MONO = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 3 */
+ FLUID_CHANNEL_MODE_LAST /**< @internal Value defines the count of basic channel modes (#fluid_basic_channel_modes) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
+};
+
+FLUIDSYNTH_API int fluid_synth_reset_basic_channel(fluid_synth_t *synth, int chan);
+
+FLUIDSYNTH_API int fluid_synth_get_basic_channel(fluid_synth_t *synth, int chan,
+ int *basic_chan_out,
+ int *mode_chan_out,
+ int *basic_val_out);
+FLUIDSYNTH_API int fluid_synth_set_basic_channel(fluid_synth_t *synth, int chan, int mode, int val);
+
+/** Interface to mono legato mode
+ *
+ * Indicates the legato mode a channel is set to
+ * n1,n2,n3,.. is a legato passage. n1 is the first note, and n2,n3,n4 are played legato with previous note. */
+enum fluid_channel_legato_mode
+{
+ FLUID_CHANNEL_LEGATO_MODE_RETRIGGER, /**< Mode 0 - Release previous note, start a new note */
+ FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER, /**< Mode 1 - On contiguous notes retrigger in attack section using current value, shape attack using current dynamic and make use of previous voices if any */
+ FLUID_CHANNEL_LEGATO_MODE_LAST /**< @internal Value defines the count of legato modes (#fluid_channel_legato_mode) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
+};
+
+FLUIDSYNTH_API int fluid_synth_set_legato_mode(fluid_synth_t *synth, int chan, int legatomode);
+FLUIDSYNTH_API int fluid_synth_get_legato_mode(fluid_synth_t *synth, int chan, int *legatomode);
+
+/** Interface to portamento mode
+ *
+ * Indicates the portamento mode a channel is set to
+ */
+enum fluid_channel_portamento_mode
+{
+ FLUID_CHANNEL_PORTAMENTO_MODE_EACH_NOTE, /**< Mode 0 - Portamento on each note (staccato or legato) */
+ FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY, /**< Mode 1 - Portamento only on legato note */
+ FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY, /**< Mode 2 - Portamento only on staccato note */
+ FLUID_CHANNEL_PORTAMENTO_MODE_LAST /**< @internal Value defines the count of portamento modes (#fluid_channel_portamento_mode) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
+};
+
+FLUIDSYNTH_API int fluid_synth_set_portamento_mode(fluid_synth_t *synth,
+ int chan, int portamentomode);
+FLUIDSYNTH_API int fluid_synth_get_portamento_mode(fluid_synth_t *synth,
+ int chan, int *portamentomode);
+
+/* Interface to breath mode */
+FLUIDSYNTH_API int fluid_synth_set_breath_mode(fluid_synth_t *synth,
+ int chan, int breathmode);
+FLUIDSYNTH_API int fluid_synth_get_breath_mode(fluid_synth_t *synth,
+ int chan, int *breathmode);
-FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader);
-FLUIDSYNTH_API fluid_voice_t* fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample,
- int channum, int key, int vel);
-FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice);
-FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t* synth,
- fluid_voice_t* buf[], int bufsize, int ID);
-FLUIDSYNTH_API int fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event);
-FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
- fluid_midi_router_t* router);
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/fluidsynth/types.h b/libs/fluidsynth/fluidsynth/types.h
index e956d818db..5ad29281ad 100644
--- a/libs/fluidsynth/fluidsynth/types.h
+++ b/libs/fluidsynth/fluidsynth/types.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -35,7 +35,6 @@ extern "C" {
typedef struct _fluid_hashtable_t fluid_settings_t; /**< Configuration settings instance */
typedef struct _fluid_synth_t fluid_synth_t; /**< Synthesizer instance */
-typedef struct _fluid_synth_channel_info_t fluid_synth_channel_info_t; /**< SoundFont channel info */
typedef struct _fluid_voice_t fluid_voice_t; /**< Synthesis voice instance */
typedef struct _fluid_sfloader_t fluid_sfloader_t; /**< SoundFont loader plugin */
typedef struct _fluid_sfont_t fluid_sfont_t; /**< SoundFont */
@@ -49,17 +48,23 @@ typedef struct _fluid_midi_event_t fluid_midi_event_t; /**< MIDI event
typedef struct _fluid_midi_driver_t fluid_midi_driver_t; /**< MIDI driver instance */
typedef struct _fluid_midi_router_t fluid_midi_router_t; /**< MIDI router instance */
typedef struct _fluid_midi_router_rule_t fluid_midi_router_rule_t; /**< MIDI router rule */
-typedef struct _fluid_hashtable_t fluid_cmd_handler_t; /**< Command handler */
+typedef struct _fluid_hashtable_t fluid_cmd_hash_t; /**< Command handler hash table */
typedef struct _fluid_shell_t fluid_shell_t; /**< Command shell */
typedef struct _fluid_server_t fluid_server_t; /**< TCP/IP shell server instance */
typedef struct _fluid_event_t fluid_event_t; /**< Sequencer event */
typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer instance */
typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */
typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */
+typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */
+#ifdef LADSPA
+typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t; /**< LADSPA effects instance */
+#endif
+typedef struct _fluid_file_callbacks_t fluid_file_callbacks_t; /**< Callback struct to perform custom file loading of soundfonts */
typedef int fluid_istream_t; /**< Input stream descriptor */
typedef int fluid_ostream_t; /**< Output stream descriptor */
+typedef short fluid_seq_id_t; /**< Unique client IDs used by the sequencer and #fluid_event_t, obtained by fluid_sequencer_register_client() and fluid_sequencer_register_fluidsynth() */
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/fluidsynth/voice.h b/libs/fluidsynth/fluidsynth/voice.h
index fe7ad8c1ab..f0644718b2 100644
--- a/libs/fluidsynth/fluidsynth/voice.h
+++ b/libs/fluidsynth/fluidsynth/voice.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -36,26 +36,34 @@ extern "C" {
*/
-FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t* voice, int gen);
-
/**
* Enum used with fluid_voice_add_mod() to specify how to handle duplicate modulators.
*/
-enum fluid_voice_add_mod {
- FLUID_VOICE_OVERWRITE, /**< Overwrite any existing matching modulator */
- FLUID_VOICE_ADD, /**< Add (sum) modulator amounts */
- FLUID_VOICE_DEFAULT /**< For default modulators only, no need to check for duplicates */
+enum fluid_voice_add_mod
+{
+ FLUID_VOICE_OVERWRITE, /**< Overwrite any existing matching modulator */
+ FLUID_VOICE_ADD, /**< Add (sum) modulator amounts */
+ FLUID_VOICE_DEFAULT /**< For default modulators only, no need to check for duplicates */
};
-FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t* voice, fluid_mod_t* mod, int mode);
-FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t* voice, int gen, float val);
-FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t* voice, int gen);
-FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t* voice, int gen, float val);
+FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode);
+FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t *voice, int gen);
+FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t *voice, int gen, float val);
+FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t *voice, int gen, float val);
+
+FLUIDSYNTH_API unsigned int fluid_voice_get_id(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_get_channel(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_get_key(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_get_actual_key(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_get_velocity(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_get_actual_velocity(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_is_playing(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_is_on(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_is_sustained(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_is_sostenuto(const fluid_voice_t *voice);
+FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t *s);
+FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t *voice, int gen);
-FLUIDSYNTH_API unsigned int fluid_voice_get_id(fluid_voice_t* voice);
-FLUIDSYNTH_API int fluid_voice_is_playing(fluid_voice_t* voice);
-FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t* s);
-
#ifdef __cplusplus
}
diff --git a/libs/fluidsynth/src/fluid_adsr_env.c b/libs/fluidsynth/src/fluid_adsr_env.c
index 1d31fdb5e6..00bdd40f22 100644
--- a/libs/fluidsynth/src/fluid_adsr_env.c
+++ b/libs/fluidsynth/src/fluid_adsr_env.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -20,19 +20,20 @@
#include "fluid_adsr_env.h"
-void
-fluid_adsr_env_set_data(fluid_adsr_env_t* env,
- fluid_adsr_env_section_t section,
- unsigned int count,
- fluid_real_t coeff,
- fluid_real_t increment,
- fluid_real_t min,
- fluid_real_t max)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data)
{
- env->data[section].count = count;
- env->data[section].coeff = coeff;
- env->data[section].increment = increment;
- env->data[section].min = min;
- env->data[section].max = max;
+ fluid_adsr_env_t *env = obj;
+ fluid_adsr_env_section_t section = param[0].i;
+ unsigned int count = param[1].i;
+ fluid_real_t coeff = param[2].real;
+ fluid_real_t increment = param[3].real;
+ fluid_real_t min = param[4].real;
+ fluid_real_t max = param[5].real;
+
+ env->data[section].count = count;
+ env->data[section].coeff = coeff;
+ env->data[section].increment = increment;
+ env->data[section].min = min;
+ env->data[section].max = max;
}
diff --git a/libs/fluidsynth/src/fluid_adsr_env.h b/libs/fluidsynth/src/fluid_adsr_env.h
index 31303a9ce9..9ed652d0b1 100644
--- a/libs/fluidsynth/src/fluid_adsr_env.h
+++ b/libs/fluidsynth/src/fluid_adsr_env.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -27,135 +27,141 @@
/*
* envelope data
*/
-struct _fluid_env_data_t {
- unsigned int count;
- fluid_real_t coeff;
- fluid_real_t increment;
- fluid_real_t min;
- fluid_real_t max;
+struct _fluid_env_data_t
+{
+ unsigned int count;
+ fluid_real_t coeff;
+ fluid_real_t increment;
+ fluid_real_t min;
+ fluid_real_t max;
};
/* Indices for envelope tables */
-enum fluid_voice_envelope_index_t{
- FLUID_VOICE_ENVDELAY,
- FLUID_VOICE_ENVATTACK,
- FLUID_VOICE_ENVHOLD,
- FLUID_VOICE_ENVDECAY,
- FLUID_VOICE_ENVSUSTAIN,
- FLUID_VOICE_ENVRELEASE,
- FLUID_VOICE_ENVFINISHED,
- FLUID_VOICE_ENVLAST
+enum fluid_voice_envelope_index_t
+{
+ FLUID_VOICE_ENVDELAY,
+ FLUID_VOICE_ENVATTACK,
+ FLUID_VOICE_ENVHOLD,
+ FLUID_VOICE_ENVDECAY,
+ FLUID_VOICE_ENVSUSTAIN,
+ FLUID_VOICE_ENVRELEASE,
+ FLUID_VOICE_ENVFINISHED,
+ FLUID_VOICE_ENVLAST
};
typedef enum fluid_voice_envelope_index_t fluid_adsr_env_section_t;
typedef struct _fluid_adsr_env_t fluid_adsr_env_t;
-struct _fluid_adsr_env_t {
- fluid_env_data_t data[FLUID_VOICE_ENVLAST];
- unsigned int count;
- int section;
- fluid_real_t val; /* the current value of the envelope */
+struct _fluid_adsr_env_t
+{
+ fluid_env_data_t data[FLUID_VOICE_ENVLAST];
+ unsigned int count;
+ int section;
+ fluid_real_t val; /* the current value of the envelope */
};
/* For performance, all functions are inlined */
-static FLUID_INLINE void
-fluid_adsr_env_calc(fluid_adsr_env_t* env, int is_volenv)
+static FLUID_INLINE void
+fluid_adsr_env_calc(fluid_adsr_env_t *env, int is_volenv)
{
- fluid_env_data_t* env_data;
- fluid_real_t x;
-
- env_data = &env->data[env->section];
-
- /* skip to the next section of the envelope if necessary */
- while (env->count >= env_data->count)
- {
- // If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage
- // Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH]
- if (env->section == FLUID_VOICE_ENVDECAY && is_volenv)
- env->val = env_data->min * env_data->coeff;
-
- env_data = &env->data[++env->section];
- env->count = 0;
- }
+ fluid_env_data_t *env_data;
+ fluid_real_t x;
+
+ env_data = &env->data[env->section];
+
+ /* skip to the next section of the envelope if necessary */
+ while(env->count >= env_data->count)
+ {
+ // If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage
+ // Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH]
+ if(env->section == FLUID_VOICE_ENVDECAY && is_volenv)
+ {
+ env->val = env_data->min * env_data->coeff;
+ }
+
+ env_data = &env->data[++env->section];
+ env->count = 0;
+ }
+
+ /* calculate the envelope value and check for valid range */
+ x = env_data->coeff * env->val + env_data->increment;
+
+ if(x < env_data->min)
+ {
+ x = env_data->min;
+ env->section++;
+ env->count = 0;
+ }
+ else if(x > env_data->max)
+ {
+ x = env_data->max;
+ env->section++;
+ env->count = 0;
+ }
+ else
+ {
+ env->count++;
+ }
+
+ env->val = x;
- /* calculate the envelope value and check for valid range */
- x = env_data->coeff * env->val + env_data->increment;
- if (x < env_data->min)
- {
- x = env_data->min;
- env->section++;
- env->count = 0;
- }
- else if (x > env_data->max)
- {
- x = env_data->max;
- env->section++;
- env->count = 0;
- }
-
- env->val = x;
- env->count++;
}
-/* This one cannot be inlined since it is referenced in
+/* This one cannot be inlined since it is referenced in
the event queue */
-void
-fluid_adsr_env_set_data(fluid_adsr_env_t* env,
- fluid_adsr_env_section_t section,
- unsigned int count,
- fluid_real_t coeff,
- fluid_real_t increment,
- fluid_real_t min,
- fluid_real_t max);
-
-static inline void
-fluid_adsr_env_reset(fluid_adsr_env_t* env)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data);
+
+static FLUID_INLINE void
+fluid_adsr_env_reset(fluid_adsr_env_t *env)
{
- env->count = 0;
- env->section = 0;
- env->val = 0.0f;
+ env->count = 0;
+ env->section = 0;
+ env->val = 0.0f;
}
-static inline fluid_real_t
-fluid_adsr_env_get_val(fluid_adsr_env_t* env)
+static FLUID_INLINE fluid_real_t
+fluid_adsr_env_get_val(fluid_adsr_env_t *env)
{
- return env->val;
+ return env->val;
}
-static inline void
-fluid_adsr_env_set_val(fluid_adsr_env_t* env, fluid_real_t val)
+static FLUID_INLINE void
+fluid_adsr_env_set_val(fluid_adsr_env_t *env, fluid_real_t val)
{
- env->val = val;
+ env->val = val;
}
-static inline fluid_adsr_env_section_t
-fluid_adsr_env_get_section(fluid_adsr_env_t* env)
+static FLUID_INLINE fluid_adsr_env_section_t
+fluid_adsr_env_get_section(fluid_adsr_env_t *env)
{
- return env->section;
+ return env->section;
}
-static inline void
-fluid_adsr_env_set_section(fluid_adsr_env_t* env,
+static FLUID_INLINE void
+fluid_adsr_env_set_section(fluid_adsr_env_t *env,
fluid_adsr_env_section_t section)
{
- env->section = section;
- env->count = 0;
+ env->section = section;
+ env->count = 0;
}
-/* Used for determining which voice to kill.
+/* Used for determining which voice to kill.
Returns max amplitude from now, and forward in time.
*/
-static inline fluid_real_t
-fluid_adsr_env_get_max_val(fluid_adsr_env_t* env)
+static FLUID_INLINE fluid_real_t
+fluid_adsr_env_get_max_val(fluid_adsr_env_t *env)
{
- if (env->section > FLUID_VOICE_ENVATTACK){
- return env->val * 1000;
- } else {
- return env->data[FLUID_VOICE_ENVATTACK].max;
- }
+ if(env->section > FLUID_VOICE_ENVATTACK)
+ {
+ return env->val * 1000;
+ }
+ else
+ {
+ return env->data[FLUID_VOICE_ENVATTACK].max;
+ }
}
#endif
diff --git a/libs/fluidsynth/src/fluid_chan.c b/libs/fluidsynth/src/fluid_chan.c
index c6eb723146..49ef99ecbe 100644
--- a/libs/fluidsynth/src/fluid_chan.c
+++ b/libs/fluidsynth/src/fluid_chan.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -36,256 +36,677 @@
#define SFONT_MASKVAL 0xFFC00000
-static void fluid_channel_init(fluid_channel_t* chan);
+static void fluid_channel_init(fluid_channel_t *chan);
-fluid_channel_t*
-new_fluid_channel(fluid_synth_t* synth, int num)
+fluid_channel_t *
+new_fluid_channel(fluid_synth_t *synth, int num)
{
- fluid_channel_t* chan;
+ fluid_channel_t *chan;
- chan = FLUID_NEW(fluid_channel_t);
- if (chan == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
+ chan = FLUID_NEW(fluid_channel_t);
- chan->synth = synth;
- chan->channum = num;
- chan->preset = NULL;
- chan->tuning = NULL;
+ if(chan == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ chan->synth = synth;
+ chan->channum = num;
+ chan->preset = NULL;
+ chan->tuning = NULL;
- fluid_channel_init(chan);
- fluid_channel_init_ctrl(chan, 0);
+ fluid_channel_init(chan);
+ fluid_channel_init_ctrl(chan, 0);
- return chan;
+ return chan;
}
static void
-fluid_channel_init(fluid_channel_t* chan)
+fluid_channel_init(fluid_channel_t *chan)
{
- fluid_preset_t *newpreset;
- int prognum, banknum;
-
- chan->sostenuto_orderid = 0;
-
- chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
- prognum = 0;
- banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
-
- chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
- | prognum << PROG_SHIFTVAL;
-
- newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
- fluid_channel_set_preset(chan, newpreset);
-
- chan->interp_method = FLUID_INTERP_DEFAULT;
- chan->tuning_bank = 0;
- chan->tuning_prog = 0;
- chan->nrpn_select = 0;
- chan->nrpn_active = 0;
+ fluid_preset_t *newpreset;
+ int i, prognum, banknum;
+
+ chan->sostenuto_orderid = 0;
+ /*--- Init poly/mono modes variables --------------------------------------*/
+ chan->mode = 0;
+ chan->mode_val = 0;
+
+ /* monophonic list initialization */
+ for(i = 0; i < FLUID_CHANNEL_SIZE_MONOLIST; i++)
+ {
+ chan->monolist[i].next = i + 1;
+ }
- if (chan->tuning)
- {
- fluid_tuning_unref (chan->tuning, 1);
- chan->tuning = NULL;
- }
+ chan->monolist[FLUID_CHANNEL_SIZE_MONOLIST - 1].next = 0; /* ending element chained to the 1st */
+ chan->i_last = chan->n_notes = 0; /* clears the list */
+ chan->i_first = chan->monolist[chan->i_last].next; /* first note index in the list */
+ fluid_channel_clear_prev_note(chan); /* Mark previous note invalid */
+ /*---*/
+ chan->key_mono_sustained = INVALID_NOTE; /* No previous mono note sustained */
+ chan->legatomode = FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER; /* Default mode */
+ chan->portamentomode = FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY; /* Default mode */
+ /*--- End of poly/mono initialization --------------------------------------*/
+
+ chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
+ prognum = 0;
+ banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
+
+ chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
+ | prognum << PROG_SHIFTVAL;
+
+ newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
+ fluid_channel_set_preset(chan, newpreset);
+
+ chan->interp_method = FLUID_INTERP_DEFAULT;
+ chan->tuning_bank = 0;
+ chan->tuning_prog = 0;
+ chan->nrpn_select = 0;
+ chan->nrpn_active = 0;
+
+ if(chan->tuning)
+ {
+ fluid_tuning_unref(chan->tuning, 1);
+ chan->tuning = NULL;
+ }
}
/*
- @param is_all_ctrl_off if nonzero, only resets some controllers, according to
- http://www.midi.org/techspecs/rp15.php
+ @param is_all_ctrl_off if nonzero, only resets some controllers, according to
+ http://www.midi.org/techspecs/rp15.php
*/
void
-fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
+fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off)
{
- int i;
-
- chan->key_pressure = 0;
- chan->channel_pressure = 0;
- chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
-
- for (i = 0; i < GEN_LAST; i++) {
- chan->gen[i] = 0.0f;
- chan->gen_abs[i] = 0;
- }
-
- if (is_all_ctrl_off) {
- for (i = 0; i < ALL_SOUND_OFF; i++) {
- if (i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5) {
- continue;
- }
- if (i >= SOUND_CTRL1 && i <= SOUND_CTRL10) {
- continue;
- }
- if (i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
- i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB) {
- continue;
- }
-
- fluid_channel_set_cc (chan, i, 0);
- }
- }
- else {
- for (i = 0; i < 128; i++) {
- fluid_channel_set_cc (chan, i, 0);
- }
- }
-
- /* Set RPN controllers to NULL state */
- fluid_channel_set_cc (chan, RPN_LSB, 127);
- fluid_channel_set_cc (chan, RPN_MSB, 127);
-
- /* Set NRPN controllers to NULL state */
- fluid_channel_set_cc (chan, NRPN_LSB, 127);
- fluid_channel_set_cc (chan, NRPN_MSB, 127);
-
- /* Expression (MSB & LSB) */
- fluid_channel_set_cc (chan, EXPRESSION_MSB, 127);
- fluid_channel_set_cc (chan, EXPRESSION_LSB, 127);
-
- if (!is_all_ctrl_off) {
-
- chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
-
- /* Just like panning, a value of 64 indicates no change for sound ctrls */
- for (i = SOUND_CTRL1; i <= SOUND_CTRL10; i++) {
- fluid_channel_set_cc (chan, i, 64);
- }
-
- /* Volume / initial attenuation (MSB & LSB) */
- fluid_channel_set_cc (chan, VOLUME_MSB, 100);
- fluid_channel_set_cc (chan, VOLUME_LSB, 0);
-
- /* Pan (MSB & LSB) */
- fluid_channel_set_cc (chan, PAN_MSB, 64);
- fluid_channel_set_cc (chan, PAN_LSB, 0);
-
- /* Reverb */
- /* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */
- /* Note: although XG standard specifies the default amount of reverb to
- be 40, most people preferred having it at zero.
- See http://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
- }
+ int i;
+
+ chan->channel_pressure = 0;
+ chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
+
+ for(i = 0; i < GEN_LAST; i++)
+ {
+ chan->gen[i] = 0.0f;
+ chan->gen_abs[i] = 0;
+ }
+
+ if(is_all_ctrl_off)
+ {
+ for(i = 0; i < ALL_SOUND_OFF; i++)
+ {
+ if(i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5)
+ {
+ continue;
+ }
+
+ if(i >= SOUND_CTRL1 && i <= SOUND_CTRL10)
+ {
+ continue;
+ }
+
+ if(i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
+ i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB ||
+ i == BALANCE_MSB || i == BALANCE_LSB
+ )
+ {
+ continue;
+ }
+
+ fluid_channel_set_cc(chan, i, 0);
+ }
+ }
+ else
+ {
+ for(i = 0; i < 128; i++)
+ {
+ fluid_channel_set_cc(chan, i, 0);
+ }
+
+ fluid_channel_clear_portamento(chan); /* Clear PTC receive */
+ chan->previous_cc_breath = 0;/* Reset previous breath */
+ }
+
+ /* Reset polyphonic key pressure on all voices */
+ for(i = 0; i < 128; i++)
+ {
+ fluid_channel_set_key_pressure(chan, i, 0);
+ }
+
+ /* Set RPN controllers to NULL state */
+ fluid_channel_set_cc(chan, RPN_LSB, 127);
+ fluid_channel_set_cc(chan, RPN_MSB, 127);
+
+ /* Set NRPN controllers to NULL state */
+ fluid_channel_set_cc(chan, NRPN_LSB, 127);
+ fluid_channel_set_cc(chan, NRPN_MSB, 127);
+
+ /* Expression (MSB & LSB) */
+ fluid_channel_set_cc(chan, EXPRESSION_MSB, 127);
+ fluid_channel_set_cc(chan, EXPRESSION_LSB, 127);
+
+ if(!is_all_ctrl_off)
+ {
+
+ chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
+
+ /* Just like panning, a value of 64 indicates no change for sound ctrls */
+ for(i = SOUND_CTRL1; i <= SOUND_CTRL10; i++)
+ {
+ fluid_channel_set_cc(chan, i, 64);
+ }
+
+ /* Volume / initial attenuation (MSB & LSB) */
+ fluid_channel_set_cc(chan, VOLUME_MSB, 100);
+ fluid_channel_set_cc(chan, VOLUME_LSB, 0);
+
+ /* Pan (MSB & LSB) */
+ fluid_channel_set_cc(chan, PAN_MSB, 64);
+ fluid_channel_set_cc(chan, PAN_LSB, 0);
+
+ /* Balance (MSB & LSB) */
+ fluid_channel_set_cc(chan, BALANCE_MSB, 64);
+ fluid_channel_set_cc(chan, BALANCE_LSB, 0);
+
+ /* Reverb */
+ /* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */
+ /* Note: although XG standard specifies the default amount of reverb to
+ be 40, most people preferred having it at zero.
+ See http://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
+ }
}
/* Only called by delete_fluid_synth(), so no need to queue a preset free event */
-int
-delete_fluid_channel(fluid_channel_t* chan)
+void
+delete_fluid_channel(fluid_channel_t *chan)
{
- if (chan->preset) delete_fluid_preset (chan->preset);
- FLUID_FREE(chan);
- return FLUID_OK;
+ fluid_return_if_fail(chan != NULL);
+
+ FLUID_FREE(chan);
}
/* FIXME - Calls fluid_channel_init() potentially in synthesis context */
void
-fluid_channel_reset(fluid_channel_t* chan)
+fluid_channel_reset(fluid_channel_t *chan)
{
- fluid_channel_init(chan);
- fluid_channel_init_ctrl(chan, 0);
+ fluid_channel_init(chan);
+ fluid_channel_init_ctrl(chan, 0);
}
/* Should only be called from synthesis context */
int
-fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
+fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset)
{
+ fluid_sfont_t *sfont;
- fluid_preset_notify (chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
+ if(chan->preset == preset)
+ {
+ return FLUID_OK;
+ }
- if (chan->preset) {
- fluid_sfont_t *sfont;
- sfont = chan->preset->sfont;
- delete_fluid_preset (chan->preset);
- fluid_synth_sfont_unref (chan->synth, sfont); /* -- unref preset's SoundFont */
- }
-
- chan->preset = preset;
+ if(chan->preset)
+ {
+ sfont = chan->preset->sfont;
+ sfont->refcount--;
+ }
+
+ fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
- fluid_preset_notify (preset, FLUID_PRESET_SELECTED, chan->channum);
+ chan->preset = preset;
+
+ if(preset)
+ {
+ sfont = preset->sfont;
+ sfont->refcount++;
+ }
- return FLUID_OK;
+ fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);
+
+ return FLUID_OK;
}
/* Set SoundFont ID, MIDI bank and/or program. Use -1 to use current value. */
void
-fluid_channel_set_sfont_bank_prog(fluid_channel_t* chan, int sfontnum,
+fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfontnum,
int banknum, int prognum)
{
- int oldval, newval, oldmask;
+ int oldval, newval, oldmask;
- newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)
- | ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)
- | ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);
+ newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)
+ | ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)
+ | ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);
- oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)
- | ((banknum != -1) ? 0 : BANK_MASKVAL)
- | ((prognum != -1) ? 0 : PROG_MASKVAL);
+ oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)
+ | ((banknum != -1) ? 0 : BANK_MASKVAL)
+ | ((prognum != -1) ? 0 : PROG_MASKVAL);
- oldval = chan->sfont_bank_prog;
- newval = (newval & ~oldmask) | (oldval & oldmask);
- chan->sfont_bank_prog = newval;
+ oldval = chan->sfont_bank_prog;
+ newval = (newval & ~oldmask) | (oldval & oldmask);
+ chan->sfont_bank_prog = newval;
}
/* Set bank LSB 7 bits */
void
-fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb)
+fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb)
{
- int oldval, newval, style;
-
- style = chan->synth->bank_select;
- if (style == FLUID_BANK_STYLE_GM ||
- style == FLUID_BANK_STYLE_GS)
- return; /* ignored */
-
- oldval = chan->sfont_bank_prog;
- if (style == FLUID_BANK_STYLE_XG)
- newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL);
- else /* style == FLUID_BANK_STYLE_MMA */
- newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);
- chan->sfont_bank_prog = newval;
+ int oldval, newval, style;
+
+ style = chan->synth->bank_select;
+
+ if(style == FLUID_BANK_STYLE_GM ||
+ style == FLUID_BANK_STYLE_GS)
+ {
+ return; /* ignored */
+ }
+
+ oldval = chan->sfont_bank_prog;
+
+ if(style == FLUID_BANK_STYLE_XG)
+ {
+ newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL);
+ }
+ else /* style == FLUID_BANK_STYLE_MMA */
+ {
+ newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);
+ }
+
+ chan->sfont_bank_prog = newval;
}
/* Set bank MSB 7 bits */
void
-fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb)
+fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb)
{
- int oldval, newval, style;
-
- style = chan->synth->bank_select;
-
- if (style == FLUID_BANK_STYLE_XG)
- {
- /* XG bank, do drum-channel auto-switch */
- /* The number "120" was based on several keyboards having drums at 120 - 127,
- reference: http://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
- chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
- return;
- }
-
- if (style == FLUID_BANK_STYLE_GM ||
- chan->channel_type == CHANNEL_TYPE_DRUM)
- return; /* ignored */
-
- oldval = chan->sfont_bank_prog;
- if (style == FLUID_BANK_STYLE_GS)
- newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL);
- else /* style == FLUID_BANK_STYLE_MMA */
- newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
- chan->sfont_bank_prog = newval;
+ int oldval, newval, style;
+
+ style = chan->synth->bank_select;
+
+ if(style == FLUID_BANK_STYLE_XG)
+ {
+ /* XG bank, do drum-channel auto-switch */
+ /* The number "120" was based on several keyboards having drums at 120 - 127,
+ reference: http://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
+ chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
+ return;
+ }
+
+ if(style == FLUID_BANK_STYLE_GM ||
+ chan->channel_type == CHANNEL_TYPE_DRUM)
+ {
+ return; /* ignored */
+ }
+
+ oldval = chan->sfont_bank_prog;
+
+ if(style == FLUID_BANK_STYLE_GS)
+ {
+ newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL);
+ }
+ else /* style == FLUID_BANK_STYLE_MMA */
+ {
+ newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
+ }
+
+ chan->sfont_bank_prog = newval;
}
/* Get SoundFont ID, MIDI bank and/or program. Use NULL to ignore a value. */
void
-fluid_channel_get_sfont_bank_prog(fluid_channel_t* chan, int *sfont,
+fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,
int *bank, int *prog)
{
- int sfont_bank_prog;
+ int sfont_bank_prog;
- sfont_bank_prog = chan->sfont_bank_prog;
+ sfont_bank_prog = chan->sfont_bank_prog;
+
+ if(sfont)
+ {
+ *sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL;
+ }
+
+ if(bank)
+ {
+ *bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;
+ }
+
+ if(prog)
+ {
+ *prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;
+ }
+}
+
+/**
+ * Updates legato/ staccato playing state
+ * The function is called:
+ * - on noteon before adding a note into the monolist.
+ * - on noteoff after removing a note out of the monolist.
+ * @param chan fluid_channel_t.
+*/
+static void
+fluid_channel_update_legato_staccato_state(fluid_channel_t *chan)
+{
+ /* Updates legato/ staccato playing state */
+ if(chan->n_notes)
+ {
+ chan->mode |= FLUID_CHANNEL_LEGATO_PLAYING; /* Legato state */
+ }
+ else
+ {
+ chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */
+ }
+}
+
+/**
+ * Adds a note into the monophonic list. The function is part of the legato
+ * detector. fluid_channel_add_monolist() is intended to be called by
+ * fluid_synth_noteon_mono_LOCAL().
+ *
+ * When a note is added at noteOn each element is use in the forward direction
+ * and indexed by i_last variable.
+ *
+ * @param chan fluid_channel_t.
+ * @param key MIDI note number (0-127).
+ * @param vel MIDI velocity (0-127, 0=noteoff).
+ * @param onenote. When 1 the function adds the note but the monophonic list
+ * keeps only one note (used on noteOn poly).
+ * Note: i_last index keeps a trace of the most recent note added.
+ * prev_note keeps a trace of the note prior i_last note.
+ * FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing state.
+ *
+ * More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
+*/
+void
+fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key,
+ unsigned char vel, unsigned char onenote)
+{
+ unsigned char i_last = chan->i_last;
+ /* Updates legato/ staccato playing state */
+ fluid_channel_update_legato_staccato_state(chan);
+
+ if(chan->n_notes)
+ {
+ /* keeps trace of the note prior last note */
+ chan->prev_note = chan->monolist[i_last].note;
+ }
+
+ /* moves i_last forward before writing new note */
+ i_last = chan->monolist[i_last].next;
+ chan->i_last = i_last; /* now ilast indexes the last note */
+ chan->monolist[i_last].note = key; /* we save note and velocity */
+ chan->monolist[i_last].vel = vel;
+
+ if(onenote)
+ {
+ /* clears monolist before one note addition */
+ chan->i_first = i_last;
+ chan->n_notes = 0;
+ }
+
+ if(chan->n_notes < FLUID_CHANNEL_SIZE_MONOLIST)
+ {
+ chan->n_notes++; /* updates n_notes */
+ }
+ else
+ {
+ /* The end of buffer is reach. So circular motion for i_first */
+ /* i_first index is moved forward */
+ chan->i_first = chan->monolist[i_last].next;
+ }
+}
+
+/**
+ * Searching a note in the monophonic list. The function is part of the legato
+ * detector. fluid_channel_search_monolist() is intended to be called by
+ * fluid_synth_noteoff_mono_LOCAL().
+ *
+ * The search starts from the first note in the list indexed by i_first
+
+ * @param chan fluid_channel_t.
+ * @param key MIDI note number (0-127) to search.
+ * @param i_prev pointer on returned index of the note prior the note to search.
+ * @return index of the note if find, FLUID_FAILED otherwise.
+ *
+ */
+int
+fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev)
+{
+ short n = chan->n_notes; /* number of notes in monophonic list */
+ short j, i = chan->i_first; /* searching starts from i_first included */
+
+ for(j = 0 ; j < n ; j++)
+ {
+ if(chan->monolist[i].note == key)
+ {
+ if(i == chan->i_first)
+ {
+ /* tracking index of the previous note (i_prev) */
+ for(j = chan->i_last ; n < FLUID_CHANNEL_SIZE_MONOLIST; n++)
+ {
+ j = chan->monolist[j].next;
+ }
+
+ * i_prev = j; /* returns index of the previous note */
+ }
+
+ return i; /* returns index of the note to search */
+ }
+
+ * i_prev = i; /* tracking index of the previous note (i_prev) */
+ i = chan->monolist[i].next; /* next element */
+ }
+
+ return FLUID_FAILED; /* not found */
+}
+
+/**
+ * removes a note from the monophonic list. The function is part of
+ * the legato detector.
+ * fluid_channel_remove_monolist() is intended to be called by
+ * fluid_synth_noteoff_mono_LOCAL().
+ *
+ * When a note is removed at noteOff the element concerned is fast unlinked
+ * and relinked after the i_last element.
+ *
+ * @param chan fluid_channel_t.
+ * @param
+ * i, index of the note to remove. If i is invalid or the list is
+ * empty, the function do nothing and returns FLUID_FAILED.
+ * @param
+ * On input, i_prev is a pointer on index of the note previous i.
+ * On output i_prev is a pointer on index of the note previous i if i is the last note
+ * in the list,FLUID_FAILED otherwise. When the returned index is valid it means
+ * a legato detection on noteoff.
+ *
+ * Note: the following variables in Channel keeps trace of the situation.
+ * - i_last index keeps a trace of the most recent note played even if
+ * the list is empty.
+ * - prev_note keeps a trace of the note removed if it is i_last.
+ * - FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing state.
+ *
+ * More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
+ */
+void
+fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev)
+{
+ unsigned char i_last = chan->i_last;
+
+ /* checks if index is valid */
+ if(i < 0 || i >= FLUID_CHANNEL_SIZE_MONOLIST || !chan->n_notes)
+ {
+ * i_prev = FLUID_FAILED;
+ }
+
+ /* The element is about to be removed and inserted between i_last and next */
+ /* Note: when i is egal to i_last or egal to i_first, removing/inserting
+ isn't necessary */
+ if(i == i_last)
+ {
+ /* Removing/Inserting isn't necessary */
+ /* keeps trace of the note prior last note */
+ chan->prev_note = chan->monolist[i_last].note;
+ /* moves i_last backward to the previous */
+ chan->i_last = *i_prev; /* i_last index is moved backward */
+ }
+ else
+ {
+ /* i is before i_last */
+ if(i == chan->i_first)
+ {
+ /* Removing/inserting isn't necessary */
+ /* i_first index is moved forward to the next element*/
+ chan->i_first = chan->monolist[i].next;
+ }
+ else
+ {
+ /* i is between i_first and i_last */
+ /* Unlinks element i and inserts after i_last */
+ chan->monolist[* i_prev].next = chan->monolist[i].next; /* unlinks i */
+ /*inserts i after i_last */
+ chan->monolist[i].next = chan->monolist[i_last].next;
+ chan->monolist[i_last].next = i;
+ }
+
+ * i_prev = FLUID_FAILED;
+ }
+
+ chan->n_notes--; /* updates the number of note in the list */
+ /* Updates legato/ staccato playing state */
+ fluid_channel_update_legato_staccato_state(chan);
+}
+
+/**
+ * On noteOff on a polyphonic channel,the monophonic list is fully flushed.
+ *
+ * @param chan fluid_channel_t.
+ * Note: i_last index keeps a trace of the most recent note played even if
+ * the list is empty.
+ * prev_note keeps a trace of the note i_last .
+ * FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing.
+ */
+void fluid_channel_clear_monolist(fluid_channel_t *chan)
+{
+ /* keeps trace off the most recent note played */
+ chan->prev_note = chan->monolist[chan->i_last].note;
+
+ /* flushes the monolist */
+ chan->i_first = chan->monolist[chan->i_last].next;
+ chan->n_notes = 0;
+ /* Update legato/ sataccato playing state */
+ chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */
+}
+
+/**
+ * On noteOn on a polyphonic channel,adds the note into the monophonic list
+ * keeping only this note.
+ * @param
+ * chan fluid_channel_t.
+ * key, vel, note and velocity added in the monolist
+ * Note: i_last index keeps a trace of the most recent note inserted.
+ * prev_note keeps a trace of the note prior i_last note.
+ * FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.
+ */
+void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key,
+ unsigned char vel)
+{
+ fluid_channel_add_monolist(chan, key, vel, 1);
+}
+
+/**
+ * The function changes the state (Valid/Invalid) of the previous note played in
+ * a staccato manner (fluid_channel_prev_note()).
+ * When potamento mode 'each note' or 'staccato only' is selected, on next
+ * noteOn a portamento will be started from the most recent note played
+ * staccato.
+ * It will be possible that it isn't appropriate. To give the musician the
+ * possibility to choose a portamento from this note , prev_note will be forced
+ * to invalid state on noteOff if portamento pedal is Off.
+ *
+ * The function is intended to be called when the following event occurs:
+ * - On noteOff (in poly or mono mode), to mark prev_note invalid.
+ * - On Portamento Off(in poly or mono mode), to mark prev_note invalid.
+ * @param chan fluid_channel_t.
+ */
+void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan)
+{
+ /* checks if the playing is staccato */
+ if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))
+ {
+
+ /* checks if portamento pedal is off */
+ if(! fluid_channel_portamento(chan))
+ {
+ /* forces prev_note invalid */
+ fluid_channel_clear_prev_note(chan);
+ }
+ }
+
+ /* else prev_note still remains valid for next fromkey portamento */
+}
+
+/**
+ * The function handles poly/mono commutation on legato pedal On/Off.
+ * @param chan fluid_channel_t.
+ * @param value, value of the CC legato.
+ */
+void fluid_channel_cc_legato(fluid_channel_t *chan, int value)
+{
+ /* Special handling of the monophonic list */
+ if(!(chan->mode & FLUID_CHANNEL_POLY_OFF) && chan->n_notes) /* The monophonic list have notes */
+ {
+ if(value < 64) /* legato is released */
+ {
+ /* returns from monophonic to polyphonic with notes in the monophonic list */
+
+ /* The monophonic list is flushed keeping last note only
+ Note: i_last index keeps a trace of the most recent note played.
+ prev_note keeps a trace of the note i_last.
+ FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.
+ */
+ chan->i_first = chan->i_last;
+ chan->n_notes = 1;
+ }
+ else /* legato is depressed */
+ {
+ /* Inters in monophonic from polyphonic with note in monophonic list */
+ /* Stops the running note to remain coherent with Breath Sync mode */
+ if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && !fluid_channel_breath_msb(chan))
+ {
+ fluid_synth_noteoff_monopoly(chan->synth, chan->channum,
+ fluid_channel_last_note(chan), 1);
+ }
+ }
+ }
+}
+
+/**
+ * The function handles CC Breath On/Off detection. When a channel is in
+ * Breath Sync mode and in monophonic playing, the breath controller allows
+ * to trigger noteon/noteoff note when the musician starts to breath (noteon) and
+ * stops to breath (noteoff).
+ * @param chan fluid_channel_t.
+ * @param value, value of the CC Breath..
+ */
+void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value)
+{
+ if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && fluid_channel_is_playing_mono(chan) &&
+ (chan->n_notes))
+ {
+ /* The monophonic list isn't empty */
+ if((value > 0) && (chan->previous_cc_breath == 0))
+ {
+ /* CC Breath On detection */
+ fluid_synth_noteon_mono_staccato(chan->synth, chan->channum,
+ fluid_channel_last_note(chan),
+ fluid_channel_last_vel(chan));
+ }
+ else if((value == 0) && (chan->previous_cc_breath > 0))
+ {
+ /* CC Breath Off detection */
+ fluid_synth_noteoff_monopoly(chan->synth, chan->channum,
+ fluid_channel_last_note(chan), 1);
+ }
+ }
- if (sfont) *sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL;
- if (bank) *bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;
- if (prog) *prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;
+ chan->previous_cc_breath = value;
}
diff --git a/libs/fluidsynth/src/fluid_chan.h b/libs/fluidsynth/src/fluid_chan.h
index 85aa1ef00c..42d73df7b5 100644
--- a/libs/fluidsynth/src/fluid_chan.h
+++ b/libs/fluidsynth/src/fluid_chan.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -25,6 +25,50 @@
#include "fluid_midi.h"
#include "fluid_tuning.h"
+/* The mononophonic list is part of the legato detector for monophonic mode */
+/* see fluid_synth_monopoly.c about a description of the legato detector device */
+/* Size of the monophonic list
+ - 1 is the minimum. it allows playing legato passage of any number
+ of notes on noteon only.
+ - Size above 1 allows playing legato on noteon but also on noteOff.
+ This allows the musician to play fast trills.
+ This feature is particularly usful when the MIDI input device is a keyboard.
+ Choosing a size of 10 is sufficient (because most musicians have only 10
+ fingers when playing a monophonic instrument).
+*/
+#define FLUID_CHANNEL_SIZE_MONOLIST 10
+
+/*
+
+ The monophonic list
+ +------------------------------------------------+
+ | +----+ +----+ +----+ +----+ |
+ | |note| |note| |note| |note| |
+ +--->|vel |-->|vel |-->....-->|vel |-->|vel |----+
+ +----+ +----+ +----+ +----+
+ /|\ /|\
+ | |
+ i_first i_last
+
+ The monophonic list is a circular buffer of FLUID_CHANNEL_SIZE_MONOLIST elements.
+ Each element is linked forward at initialisation time.
+ - when a note is added at noteOn (see fluid_channel_add_monolist()) each
+ element is use in the forward direction and indexed by i_last variable.
+ - when a note is removed at noteOff (see fluid_channel_remove_monolist()),
+ the element concerned is fast unlinked and relinked after the i_last element.
+
+ The most recent note added is indexed by i_last.
+ The most ancient note added is the first note indexed by i_first. i_first is
+ moving in the forward direction in a circular manner.
+
+*/
+struct mononote
+{
+ unsigned char next; /* next note */
+ unsigned char note; /* note */
+ unsigned char vel; /* velocity */
+};
+
/*
* fluid_channel_t
*
@@ -33,83 +77,93 @@
*/
struct _fluid_channel_t
{
- fluid_mutex_t mutex; /* Lock for thread sensitive parameters */
-
- fluid_synth_t* synth; /**< Parent synthesizer instance */
- int channum; /**< MIDI channel number */
-
- int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
- fluid_preset_t* preset; /**< Selected preset */
-
- int key_pressure; /**< MIDI key pressure */
- int channel_pressure; /**< MIDI channel pressure */
- int pitch_bend; /**< Current pitch bend value */
- int pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
-
- int cc[128]; /**< MIDI controller values */
-
- /* Sostenuto order id gives the order of SostenutoOn event.
- This value is useful to known when the sostenuto pedal is depressed
- (before or after a key note). We need to compare SostenutoOrderId with voice id.
- */
- unsigned int sostenuto_orderid;
- int interp_method; /**< Interpolation method (enum fluid_interp) */
- fluid_tuning_t* tuning; /**< Micro tuning */
- int tuning_bank; /**< Current tuning bank number */
- int tuning_prog; /**< Current tuning program number */
-
- /* NRPN system */
- int nrpn_select; /* Generator ID of SoundFont NRPN message */
- int nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
-
- /* The values of the generators, set by NRPN messages, or by
- * fluid_synth_set_gen(), are cached in the channel so they can be
- * applied to future notes. They are copied to a voice's generators
- * in fluid_voice_init(), which calls fluid_gen_init(). */
- fluid_real_t gen[GEN_LAST];
-
- /* By default, the NRPN values are relative to the values of the
- * generators set in the SoundFont. For example, if the NRPN
- * specifies an attack of 100 msec then 100 msec will be added to the
- * combined attack time of the sound font and the modulators.
- *
- * However, it is useful to be able to specify the generator value
- * absolutely, completely ignoring the generators of the SoundFont
- * and the values of modulators. The gen_abs field, is a boolean
- * flag indicating whether the NRPN value is absolute or not.
- */
- char gen_abs[GEN_LAST];
-
- /* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
- int channel_type;
+ fluid_synth_t *synth; /**< Parent synthesizer instance */
+ int channum; /**< MIDI channel number */
+
+ /* Poly Mono variables see macro access description */
+ int mode; /**< Poly Mono mode */
+ int mode_val; /**< number of channel in basic channel group */
+
+ /* monophonic list - legato detector */
+ unsigned char i_first; /**< First note index */
+ unsigned char i_last; /**< most recent note index since the most recent add */
+ unsigned char prev_note; /**< previous note of the most recent add/remove */
+ unsigned char n_notes; /**< actual number of notes in the list */
+ struct mononote monolist[FLUID_CHANNEL_SIZE_MONOLIST]; /**< monophonic list */
+
+ unsigned char key_mono_sustained; /**< previous sustained monophonic note */
+ unsigned char previous_cc_breath; /**< Previous Breath */
+ enum fluid_channel_legato_mode legatomode; /**< legato mode */
+ enum fluid_channel_portamento_mode portamentomode; /**< portamento mode */
+ /*- End of Poly/mono variables description */
+
+ unsigned char cc[128]; /**< MIDI controller values from [0;127] */
+ unsigned char key_pressure[128]; /**< MIDI polyphonic key pressure from [0;127] */
+
+ /* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
+ enum fluid_midi_channel_type channel_type;
+ enum fluid_interp interp_method; /**< Interpolation method (enum fluid_interp) */
+
+ unsigned char channel_pressure; /**< MIDI channel pressure from [0;127] */
+ unsigned char pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
+ short pitch_bend; /**< Current pitch bend value */
+ /* Sostenuto order id gives the order of SostenutoOn event.
+ * This value is useful to known when the sostenuto pedal is depressed
+ * (before or after a key note). We need to compare SostenutoOrderId with voice id.
+ */
+ unsigned int sostenuto_orderid;
+
+ int tuning_bank; /**< Current tuning bank number */
+ int tuning_prog; /**< Current tuning program number */
+ fluid_tuning_t *tuning; /**< Micro tuning */
+
+ fluid_preset_t *preset; /**< Selected preset */
+ int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
+
+ /* NRPN system */
+ enum fluid_gen_type nrpn_select; /* Generator ID of SoundFont NRPN message */
+ char nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
+ /* The values of the generators, set by NRPN messages, or by
+ * fluid_synth_set_gen(), are cached in the channel so they can be
+ * applied to future notes. They are copied to a voice's generators
+ * in fluid_voice_init(), which calls fluid_gen_init(). */
+ fluid_real_t gen[GEN_LAST];
+
+ /* By default, the NRPN values are relative to the values of the
+ * generators set in the SoundFont. For example, if the NRPN
+ * specifies an attack of 100 msec then 100 msec will be added to the
+ * combined attack time of the sound font and the modulators.
+ *
+ * However, it is useful to be able to specify the generator value
+ * absolutely, completely ignoring the generators of the SoundFont
+ * and the values of modulators. The gen_abs field, is a boolean
+ * flag indicating whether the NRPN value is absolute or not.
+ */
+ char gen_abs[GEN_LAST];
};
-fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
-void fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off);
-int delete_fluid_channel(fluid_channel_t* chan);
-void fluid_channel_reset(fluid_channel_t* chan);
-int fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset);
-fluid_preset_t* fluid_channel_get_preset(fluid_channel_t* chan);
-void fluid_channel_set_sfont_bank_prog(fluid_channel_t* chan, int sfont,
+fluid_channel_t *new_fluid_channel(fluid_synth_t *synth, int num);
+void fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off);
+void delete_fluid_channel(fluid_channel_t *chan);
+void fluid_channel_reset(fluid_channel_t *chan);
+int fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset);
+void fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfont,
int bank, int prog);
-void fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb);
-void fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb);
-void fluid_channel_get_sfont_bank_prog(fluid_channel_t* chan, int *sfont,
+void fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb);
+void fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb);
+void fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,
int *bank, int *prog);
-int fluid_channel_get_num(fluid_channel_t* chan);
-void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method);
-int fluid_channel_get_interp_method(fluid_channel_t* chan);
#define fluid_channel_get_preset(chan) ((chan)->preset)
#define fluid_channel_set_cc(chan, num, val) \
((chan)->cc[num] = (val))
#define fluid_channel_get_cc(chan, num) \
((chan)->cc[num])
-#define fluid_channel_get_key_pressure(chan) \
- ((chan)->key_pressure)
-#define fluid_channel_set_key_pressure(chan, val) \
- ((chan)->key_pressure = (val))
+#define fluid_channel_get_key_pressure(chan, key) \
+ ((chan)->key_pressure[key])
+#define fluid_channel_set_key_pressure(chan, key, val) \
+ ((chan)->key_pressure[key] = (val))
#define fluid_channel_get_channel_pressure(chan) \
((chan)->channel_pressure)
#define fluid_channel_set_channel_pressure(chan, val) \
@@ -138,6 +192,12 @@ int fluid_channel_get_interp_method(fluid_channel_t* chan);
((chan)->tuning_prog)
#define fluid_channel_set_tuning_prog(chan, prog) \
((chan)->tuning_prog = (prog))
+#define fluid_channel_portamentotime(_c) \
+ ((_c)->cc[PORTAMENTO_TIME_MSB] * 128 + (_c)->cc[PORTAMENTO_TIME_LSB])
+#define fluid_channel_portamento(_c) ((_c)->cc[PORTAMENTO_SWITCH] >= 64)
+#define fluid_channel_breath_msb(_c) ((_c)->cc[BREATH_MSB] > 0)
+#define fluid_channel_clear_portamento(_c) ((_c)->cc[PORTAMENTO_CTRL] = INVALID_NOTE)
+#define fluid_channel_legato(_c) ((_c)->cc[LEGATO_SWITCH] >= 64)
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
#define fluid_channel_sostenuto(_c) ((_c)->cc[SOSTENUTO_SWITCH] >= 64)
#define fluid_channel_set_gen(_c, _n, _v, _a) { (_c)->gen[_n] = _v; (_c)->gen_abs[_n] = _a; }
@@ -146,4 +206,83 @@ int fluid_channel_get_interp_method(fluid_channel_t* chan);
#define fluid_channel_get_min_note_length_ticks(chan) \
((chan)->synth->min_note_length_ticks)
+/* Macros interface to poly/mono mode variables */
+#define MASK_BASICCHANINFOS (FLUID_CHANNEL_MODE_MASK|FLUID_CHANNEL_BASIC|FLUID_CHANNEL_ENABLED)
+/* Set the basic channel infos for a MIDI basic channel */
+#define fluid_channel_set_basic_channel_info(chan,Infos) \
+ (chan->mode = (chan->mode & ~MASK_BASICCHANINFOS) | (Infos & MASK_BASICCHANINFOS))
+/* Reset the basic channel infos for a MIDI basic channel */
+#define fluid_channel_reset_basic_channel_info(chan) (chan->mode &= ~MASK_BASICCHANINFOS)
+
+/* Macros interface to breath variables */
+#define FLUID_CHANNEL_BREATH_MASK (FLUID_CHANNEL_BREATH_POLY|FLUID_CHANNEL_BREATH_MONO|FLUID_CHANNEL_BREATH_SYNC)
+/* Set the breath infos for a MIDI channel */
+#define fluid_channel_set_breath_info(chan,BreathInfos) \
+(chan->mode = (chan->mode & ~FLUID_CHANNEL_BREATH_MASK) | (BreathInfos & FLUID_CHANNEL_BREATH_MASK))
+/* Get the breath infos for a MIDI channel */
+#define fluid_channel_get_breath_info(chan) (chan->mode & FLUID_CHANNEL_BREATH_MASK)
+
+/* Returns true when channel is mono or legato is on */
+#define fluid_channel_is_playing_mono(chan) ((chan->mode & FLUID_CHANNEL_POLY_OFF) ||\
+ fluid_channel_legato(chan))
+
+/* Macros interface to monophonic list variables */
+#define INVALID_NOTE (255)
+/* Returns true when a note is a valid note */
+#define fluid_channel_is_valid_note(n) (n != INVALID_NOTE)
+/* Marks prev_note as invalid. */
+#define fluid_channel_clear_prev_note(chan) (chan->prev_note = INVALID_NOTE)
+
+/* Returns the most recent note from i_last entry of the monophonic list */
+#define fluid_channel_last_note(chan) (chan->monolist[chan->i_last].note)
+
+/* Returns the most recent velocity from i_last entry of the monophonic list */
+#define fluid_channel_last_vel(chan) (chan->monolist[chan->i_last].vel)
+
+/*
+ prev_note is used to determine fromkey_portamento as well as
+ fromkey_legato (see fluid_synth_get_fromkey_portamento_legato()).
+
+ prev_note is updated on noteOn/noteOff mono by the legato detector as this:
+ - On noteOn mono, before adding a new note into the monolist,the most
+ recent note in the list (i.e at i_last position) is kept in prev_note.
+ - Similarly, on noteOff mono , before removing a note out of the monolist,
+ the most recent note (i.e those at i_last position) is kept in prev_note.
+*/
+#define fluid_channel_prev_note(chan) (chan->prev_note)
+
+/* Interface to poly/mono mode variables */
+enum fluid_channel_mode_flags_internal
+{
+ FLUID_CHANNEL_BASIC = 0x04, /**< if flag set the corresponding midi channel is a basic channel */
+ FLUID_CHANNEL_ENABLED = 0x08, /**< if flag set the corresponding midi channel is enabled, else disabled, i.e. channel ignores any MIDI messages */
+
+ /*
+ FLUID_CHANNEL_LEGATO_PLAYING bit of channel mode keeps trace of the legato /staccato
+ state playing.
+ FLUID_CHANNEL_LEGATO_PLAYING bit is updated on noteOn/noteOff mono by the legato detector:
+ - On noteOn, before inserting a new note into the monolist.
+ - On noteOff, after removing a note out of the monolist.
+
+ - On noteOn, this state is used by fluid_synth_noteon_mono_LOCAL()
+ to play the current note legato or staccato.
+ - On noteOff, this state is used by fluid_synth_noteoff_mono_LOCAL()
+ to play the current noteOff legato with the most recent note.
+ */
+ /* bit7, 1: means legato playing , 0: means staccato playing */
+ FLUID_CHANNEL_LEGATO_PLAYING = 0x80
+};
+
+/* End of interface to monophonic list variables */
+
+void fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key, unsigned char vel, unsigned char onenote);
+int fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev);
+void fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev);
+void fluid_channel_clear_monolist(fluid_channel_t *chan);
+void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key, unsigned char vel);
+void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan);
+void fluid_channel_cc_legato(fluid_channel_t *chan, int value);
+void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value);
+
+
#endif /* _FLUID_CHAN_H */
diff --git a/libs/fluidsynth/src/fluid_chorus.c b/libs/fluidsynth/src/fluid_chorus.c
index 4bead5ce2d..83a88d3826 100644
--- a/libs/fluidsynth/src/fluid_chorus.c
+++ b/libs/fluidsynth/src/fluid_chorus.c
@@ -1,13 +1,25 @@
-/*
- * August 24, 1998
- * Copyright (C) 1998 Juergen Mueller And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose. This copyright notice must be maintained.
- * Juergen Mueller And Sundry Contributors are not responsible for
- * the consequences of using this software.
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe, Markus Nentwig and others.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
*/
/*
+ based on a chrous implementation made by Juergen Mueller And Sundry Contributors in 1998
CHANGES
@@ -78,8 +90,8 @@
* Set through MAX_SAMPLES_LN2.
* For example:
* MAX_SAMPLES_LN2=12
- * => MAX_SAMPLES=pow(2,12)=4096
- * => MAX_SAMPLES_ANDMASK=4095
+ * => MAX_SAMPLES=pow(2,12-1)=2048
+ * => MAX_SAMPLES_ANDMASK=2047
*/
#define MAX_SAMPLES_LN2 12
@@ -103,131 +115,136 @@
#define INTERPOLATION_SAMPLES 5
/* Private data for SKEL file */
-struct _fluid_chorus_t {
- int type;
- fluid_real_t depth_ms;
- fluid_real_t level;
- fluid_real_t speed_Hz;
- int number_blocks;
-
- fluid_real_t *chorusbuf;
- int counter;
- long phase[MAX_CHORUS];
- long modulation_period_samples;
- int *lookup_tab;
- fluid_real_t sample_rate;
-
- /* sinc lookup table */
- fluid_real_t sinc_table[INTERPOLATION_SAMPLES][INTERPOLATION_SUBSAMPLES];
+struct _fluid_chorus_t
+{
+ int type;
+ fluid_real_t depth_ms;
+ fluid_real_t level;
+ fluid_real_t speed_Hz;
+ int number_blocks;
+
+ fluid_real_t *chorusbuf;
+ int counter;
+ long phase[MAX_CHORUS];
+ long modulation_period_samples;
+ int *lookup_tab;
+ fluid_real_t sample_rate;
+
+ /* sinc lookup table */
+ fluid_real_t sinc_table[INTERPOLATION_SAMPLES][INTERPOLATION_SUBSAMPLES];
};
static void fluid_chorus_triangle(int *buf, int len, int depth);
static void fluid_chorus_sine(int *buf, int len, int depth);
-fluid_chorus_t*
+fluid_chorus_t *
new_fluid_chorus(fluid_real_t sample_rate)
{
- int i; int ii;
- fluid_chorus_t* chorus;
-
- chorus = FLUID_NEW(fluid_chorus_t);
- if (chorus == NULL) {
- fluid_log(FLUID_PANIC, "chorus: Out of memory");
- return NULL;
- }
+ int i;
+ int ii;
+ fluid_chorus_t *chorus;
+
+ chorus = FLUID_NEW(fluid_chorus_t);
+
+ if(chorus == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
+
+ chorus->sample_rate = sample_rate;
+
+ /* Lookup table for the SI function (impulse response of an ideal low pass) */
+
+ /* i: Offset in terms of whole samples */
+ for(i = 0; i < INTERPOLATION_SAMPLES; i++)
+ {
+
+ /* ii: Offset in terms of fractional samples ('subsamples') */
+ for(ii = 0; ii < INTERPOLATION_SUBSAMPLES; ii++)
+ {
+ /* Move the origin into the center of the table */
+ double i_shifted = ((double) i - ((double) INTERPOLATION_SAMPLES) / 2.
+ + (double) ii / (double) INTERPOLATION_SUBSAMPLES);
+
+ if(fabs(i_shifted) < 0.000001)
+ {
+ /* sinc(0) cannot be calculated straightforward (limit needed
+ for 0/0) */
+ chorus->sinc_table[i][ii] = (fluid_real_t)1.;
+
+ }
+ else
+ {
+ chorus->sinc_table[i][ii] = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
+ /* Hamming window */
+ chorus->sinc_table[i][ii] *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)INTERPOLATION_SAMPLES));
+ };
+ };
+ };
- FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
+ /* allocate lookup tables */
+ chorus->lookup_tab = FLUID_ARRAY(int, (int)(chorus->sample_rate / MIN_SPEED_HZ));
- chorus->sample_rate = sample_rate;
+ if(chorus->lookup_tab == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
+ goto error_recovery;
+ }
- /* Lookup table for the SI function (impulse response of an ideal low pass) */
+ /* allocate sample buffer */
- /* i: Offset in terms of whole samples */
- for (i = 0; i < INTERPOLATION_SAMPLES; i++){
+ chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
- /* ii: Offset in terms of fractional samples ('subsamples') */
- for (ii = 0; ii < INTERPOLATION_SUBSAMPLES; ii++){
- /* Move the origin into the center of the table */
- double i_shifted = ((double) i- ((double) INTERPOLATION_SAMPLES) / 2.
- + (double) ii / (double) INTERPOLATION_SUBSAMPLES);
- if (fabs(i_shifted) < 0.000001) {
- /* sinc(0) cannot be calculated straightforward (limit needed
- for 0/0) */
- chorus->sinc_table[i][ii] = (fluid_real_t)1.;
+ if(chorus->chorusbuf == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
+ goto error_recovery;
+ }
- } else {
- chorus->sinc_table[i][ii] = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
- /* Hamming window */
- chorus->sinc_table[i][ii] *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)INTERPOLATION_SAMPLES));
- };
+ if(fluid_chorus_init(chorus) != FLUID_OK)
+ {
+ goto error_recovery;
};
- };
-
- /* allocate lookup tables */
- chorus->lookup_tab = FLUID_ARRAY(int, (int) (chorus->sample_rate / MIN_SPEED_HZ));
- if (chorus->lookup_tab == NULL) {
- fluid_log(FLUID_PANIC, "chorus: Out of memory");
- goto error_recovery;
- }
-
- /* allocate sample buffer */
-
- chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
- if (chorus->chorusbuf == NULL) {
- fluid_log(FLUID_PANIC, "chorus: Out of memory");
- goto error_recovery;
- }
- if (fluid_chorus_init(chorus) != FLUID_OK){
- goto error_recovery;
- };
+ return chorus;
- return chorus;
+error_recovery:
+ delete_fluid_chorus(chorus);
- error_recovery:
- delete_fluid_chorus(chorus);
- return NULL;
+ return NULL;
}
void
-delete_fluid_chorus(fluid_chorus_t* chorus)
+delete_fluid_chorus(fluid_chorus_t *chorus)
{
- if (chorus == NULL) {
- return;
- }
+ fluid_return_if_fail(chorus != NULL);
- if (chorus->chorusbuf != NULL) {
FLUID_FREE(chorus->chorusbuf);
- }
-
- if (chorus->lookup_tab != NULL) {
FLUID_FREE(chorus->lookup_tab);
- }
-
- FLUID_FREE(chorus);
+ FLUID_FREE(chorus);
}
int
-fluid_chorus_init(fluid_chorus_t* chorus)
+fluid_chorus_init(fluid_chorus_t *chorus)
{
- int i;
+ int i;
- for (i = 0; i < MAX_SAMPLES; i++) {
- chorus->chorusbuf[i] = 0.0;
- }
+ for(i = 0; i < MAX_SAMPLES; i++)
+ {
+ chorus->chorusbuf[i] = 0.0;
+ }
- /* initialize the chorus with the default settings */
- fluid_chorus_set (chorus, FLUID_CHORUS_SET_ALL, FLUID_CHORUS_DEFAULT_N,
- FLUID_CHORUS_DEFAULT_LEVEL, FLUID_CHORUS_DEFAULT_SPEED,
- FLUID_CHORUS_DEFAULT_DEPTH, FLUID_CHORUS_MOD_SINE);
- return FLUID_OK;
+ return FLUID_OK;
}
void
-fluid_chorus_reset(fluid_chorus_t* chorus)
+fluid_chorus_reset(fluid_chorus_t *chorus)
{
- fluid_chorus_init(chorus);
+ fluid_chorus_init(chorus);
}
/**
@@ -243,223 +260,272 @@ fluid_chorus_reset(fluid_chorus_t* chorus)
* @param type Chorus waveform type (#fluid_chorus_mod)
*/
void
-fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
- float speed, float depth_ms, int type)
+fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
+ fluid_real_t speed, fluid_real_t depth_ms, int type)
{
- int modulation_depth_samples;
- int i;
-
- if (set & FLUID_CHORUS_SET_NR) chorus->number_blocks = nr;
- if (set & FLUID_CHORUS_SET_LEVEL) chorus->level = level;
- if (set & FLUID_CHORUS_SET_SPEED) chorus->speed_Hz = speed;
- if (set & FLUID_CHORUS_SET_DEPTH) chorus->depth_ms = depth_ms;
- if (set & FLUID_CHORUS_SET_TYPE) chorus->type = type;
-
- if (chorus->number_blocks < 0) {
- fluid_log(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0.");
- chorus->number_blocks = 0;
- } else if (chorus->number_blocks > MAX_CHORUS) {
- fluid_log(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.",
- MAX_CHORUS);
- chorus->number_blocks = MAX_CHORUS;
- }
-
- if (chorus->speed_Hz < MIN_SPEED_HZ) {
- fluid_log(FLUID_WARN, "chorus: speed is too low (min %f)! Setting value to min.",
- (double) MIN_SPEED_HZ);
- chorus->speed_Hz = MIN_SPEED_HZ;
- } else if (chorus->speed_Hz > MAX_SPEED_HZ) {
- fluid_log(FLUID_WARN, "chorus: speed must be below %f Hz! Setting value to max.",
- (double) MAX_SPEED_HZ);
- chorus->speed_Hz = MAX_SPEED_HZ;
- }
-
- if (chorus->depth_ms < 0.0) {
- fluid_log(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
- chorus->depth_ms = 0.0;
- }
- /* Depth: Check for too high value through modulation_depth_samples. */
-
- if (chorus->level < 0.0) {
- fluid_log(FLUID_WARN, "chorus: level must be positive! Setting value to 0.");
- chorus->level = 0.0;
- } else if (chorus->level > 10) {
- fluid_log(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! "
- "Setting it to 0.1.");
- chorus->level = 0.1;
- }
-
- /* The modulating LFO goes through a full period every x samples: */
- chorus->modulation_period_samples = chorus->sample_rate / chorus->speed_Hz;
-
- /* The variation in delay time is x: */
- modulation_depth_samples = (int)
- (chorus->depth_ms / 1000.0 /* convert modulation depth in ms to s*/
- * chorus->sample_rate);
-
- if (modulation_depth_samples > MAX_SAMPLES) {
- fluid_log(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
- modulation_depth_samples = MAX_SAMPLES;
- }
-
- /* initialize LFO table */
- if (chorus->type == FLUID_CHORUS_MOD_SINE) {
- fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
- modulation_depth_samples);
- } else if (chorus->type == FLUID_CHORUS_MOD_TRIANGLE) {
- fluid_chorus_triangle(chorus->lookup_tab, chorus->modulation_period_samples,
- modulation_depth_samples);
- } else {
- fluid_log(FLUID_WARN, "chorus: Unknown modulation type. Using sinewave.");
- chorus->type = FLUID_CHORUS_MOD_SINE;
- fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
- modulation_depth_samples);
- }
-
- for (i = 0; i < chorus->number_blocks; i++) {
- /* Set the phase of the chorus blocks equally spaced */
- chorus->phase[i] = (int) ((double) chorus->modulation_period_samples
- * (double) i / (double) chorus->number_blocks);
- }
-
- /* Start of the circular buffer */
- chorus->counter = 0;
+ int modulation_depth_samples;
+ int i;
+
+ if(set & FLUID_CHORUS_SET_NR)
+ {
+ chorus->number_blocks = nr;
+ }
+
+ if(set & FLUID_CHORUS_SET_LEVEL)
+ {
+ chorus->level = level;
+ }
+
+ if(set & FLUID_CHORUS_SET_SPEED)
+ {
+ chorus->speed_Hz = speed;
+ }
+
+ if(set & FLUID_CHORUS_SET_DEPTH)
+ {
+ chorus->depth_ms = depth_ms;
+ }
+
+ if(set & FLUID_CHORUS_SET_TYPE)
+ {
+ chorus->type = type;
+ }
+
+ if(chorus->number_blocks < 0)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0.");
+ chorus->number_blocks = 0;
+ }
+ else if(chorus->number_blocks > MAX_CHORUS)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.",
+ MAX_CHORUS);
+ chorus->number_blocks = MAX_CHORUS;
+ }
+
+ if(chorus->speed_Hz < MIN_SPEED_HZ)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: speed is too low (min %f)! Setting value to min.",
+ (double) MIN_SPEED_HZ);
+ chorus->speed_Hz = MIN_SPEED_HZ;
+ }
+ else if(chorus->speed_Hz > MAX_SPEED_HZ)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: speed must be below %f Hz! Setting value to max.",
+ (double) MAX_SPEED_HZ);
+ chorus->speed_Hz = MAX_SPEED_HZ;
+ }
+
+ if(chorus->depth_ms < 0.0)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
+ chorus->depth_ms = 0.0;
+ }
+
+ /* Depth: Check for too high value through modulation_depth_samples. */
+
+ if(chorus->level < 0.0)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: level must be positive! Setting value to 0.");
+ chorus->level = 0.0;
+ }
+ else if(chorus->level > 10)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! "
+ "Setting it to 0.1.");
+ chorus->level = 0.1;
+ }
+
+ /* The modulating LFO goes through a full period every x samples: */
+ chorus->modulation_period_samples = chorus->sample_rate / chorus->speed_Hz;
+
+ /* The variation in delay time is x: */
+ modulation_depth_samples = (int)
+ (chorus->depth_ms / 1000.0 /* convert modulation depth in ms to s*/
+ * chorus->sample_rate);
+
+ if(modulation_depth_samples > MAX_SAMPLES)
+ {
+ FLUID_LOG(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
+ modulation_depth_samples = MAX_SAMPLES;
+ // set depth to maximum to avoid spamming console with above warning
+ chorus->depth_ms = (modulation_depth_samples * 1000) / chorus->sample_rate;
+ }
+
+ /* initialize LFO table */
+ switch(chorus->type)
+ {
+ default:
+ FLUID_LOG(FLUID_WARN, "chorus: Unknown modulation type. Using sinewave.");
+ chorus->type = FLUID_CHORUS_MOD_SINE;
+ /* fall-through */
+
+ case FLUID_CHORUS_MOD_SINE:
+ fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
+ modulation_depth_samples);
+ break;
+
+ case FLUID_CHORUS_MOD_TRIANGLE:
+ fluid_chorus_triangle(chorus->lookup_tab, chorus->modulation_period_samples,
+ modulation_depth_samples);
+ break;
+ }
+
+ for(i = 0; i < chorus->number_blocks; i++)
+ {
+ /* Set the phase of the chorus blocks equally spaced */
+ chorus->phase[i] = (int)((double) chorus->modulation_period_samples
+ * (double) i / (double) chorus->number_blocks);
+ }
+
+ /* Start of the circular buffer */
+ chorus->counter = 0;
}
-void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out)
+void fluid_chorus_processmix(fluid_chorus_t *chorus, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out)
{
- int sample_index;
- int i;
- fluid_real_t d_in, d_out;
+ int sample_index;
+ int i;
+ fluid_real_t d_in, d_out;
- for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
+ for(sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++)
+ {
- d_in = in[sample_index];
- d_out = 0.0f;
+ d_in = in[sample_index];
+ d_out = 0.0f;
# if 0
- /* Debug: Listen to the chorus signal only */
- left_out[sample_index]=0;
- right_out[sample_index]=0;
+ /* Debug: Listen to the chorus signal only */
+ left_out[sample_index] = 0;
+ right_out[sample_index] = 0;
#endif
- /* Write the current sample into the circular buffer */
- chorus->chorusbuf[chorus->counter] = d_in;
+ /* Write the current sample into the circular buffer */
+ chorus->chorusbuf[chorus->counter] = d_in;
- for (i = 0; i < chorus->number_blocks; i++) {
- int ii;
- /* Calculate the delay in subsamples for the delay line of chorus block nr. */
+ for(i = 0; i < chorus->number_blocks; i++)
+ {
+ int ii;
+ /* Calculate the delay in subsamples for the delay line of chorus block nr. */
- /* The value in the lookup table is so, that this expression
- * will always be positive. It will always include a number of
- * full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
- * remain positive at all times. */
- int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
- - chorus->lookup_tab[chorus->phase[i]]);
+ /* The value in the lookup table is so, that this expression
+ * will always be positive. It will always include a number of
+ * full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
+ * remain positive at all times. */
+ int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
+ - chorus->lookup_tab[chorus->phase[i]]);
- int pos_samples = pos_subsamples/INTERPOLATION_SUBSAMPLES;
+ int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
- /* modulo divide by INTERPOLATION_SUBSAMPLES */
- pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
+ /* modulo divide by INTERPOLATION_SUBSAMPLES */
+ pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
- for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
- /* Add the delayed signal to the chorus sum d_out Note: The
- * delay in the delay line moves backwards for increasing
- * delay!*/
+ for(ii = 0; ii < INTERPOLATION_SAMPLES; ii++)
+ {
+ /* Add the delayed signal to the chorus sum d_out Note: The
+ * delay in the delay line moves backwards for increasing
+ * delay!*/
- /* The & in chorusbuf[...] is equivalent to a division modulo
- MAX_SAMPLES, only faster. */
- d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
- * chorus->sinc_table[ii][pos_subsamples];
+ /* The & in chorusbuf[...] is equivalent to a division modulo
+ MAX_SAMPLES, only faster. */
+ d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
+ * chorus->sinc_table[ii][pos_subsamples];
- pos_samples--;
- };
- /* Cycle the phase of the modulating LFO */
- chorus->phase[i]++;
- chorus->phase[i] %= (chorus->modulation_period_samples);
- } /* foreach chorus block */
+ pos_samples--;
+ };
- d_out *= chorus->level;
+ /* Cycle the phase of the modulating LFO */
+ chorus->phase[i]++;
- /* Add the chorus sum d_out to output */
- left_out[sample_index] += d_out;
- right_out[sample_index] += d_out;
+ chorus->phase[i] %= (chorus->modulation_period_samples);
+ } /* foreach chorus block */
- /* Move forward in circular buffer */
- chorus->counter++;
- chorus->counter %= MAX_SAMPLES;
+ d_out *= chorus->level;
- } /* foreach sample */
+ /* Add the chorus sum d_out to output */
+ left_out[sample_index] += d_out;
+ right_out[sample_index] += d_out;
+
+ /* Move forward in circular buffer */
+ chorus->counter++;
+ chorus->counter %= MAX_SAMPLES;
+
+ } /* foreach sample */
}
/* Duplication of code ... (replaces sample data instead of mixing) */
-void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out)
+void fluid_chorus_processreplace(fluid_chorus_t *chorus, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out)
{
- int sample_index;
- int i;
- fluid_real_t d_in, d_out;
+ int sample_index;
+ int i;
+ fluid_real_t d_in, d_out;
- for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
+ for(sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++)
+ {
- d_in = in[sample_index];
- d_out = 0.0f;
+ d_in = in[sample_index];
+ d_out = 0.0f;
# if 0
- /* Debug: Listen to the chorus signal only */
- left_out[sample_index]=0;
- right_out[sample_index]=0;
+ /* Debug: Listen to the chorus signal only */
+ left_out[sample_index] = 0;
+ right_out[sample_index] = 0;
#endif
- /* Write the current sample into the circular buffer */
- chorus->chorusbuf[chorus->counter] = d_in;
+ /* Write the current sample into the circular buffer */
+ chorus->chorusbuf[chorus->counter] = d_in;
+
+ for(i = 0; i < chorus->number_blocks; i++)
+ {
+ int ii;
+ /* Calculate the delay in subsamples for the delay line of chorus block nr. */
+
+ /* The value in the lookup table is so, that this expression
+ * will always be positive. It will always include a number of
+ * full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
+ * remain positive at all times. */
+ int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
+ - chorus->lookup_tab[chorus->phase[i]]);
- for (i = 0; i < chorus->number_blocks; i++) {
- int ii;
- /* Calculate the delay in subsamples for the delay line of chorus block nr. */
+ int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
- /* The value in the lookup table is so, that this expression
- * will always be positive. It will always include a number of
- * full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
- * remain positive at all times. */
- int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
- - chorus->lookup_tab[chorus->phase[i]]);
+ /* modulo divide by INTERPOLATION_SUBSAMPLES */
+ pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
- int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
+ for(ii = 0; ii < INTERPOLATION_SAMPLES; ii++)
+ {
+ /* Add the delayed signal to the chorus sum d_out Note: The
+ * delay in the delay line moves backwards for increasing
+ * delay!*/
- /* modulo divide by INTERPOLATION_SUBSAMPLES */
- pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
+ /* The & in chorusbuf[...] is equivalent to a division modulo
+ MAX_SAMPLES, only faster. */
+ d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
+ * chorus->sinc_table[ii][pos_subsamples];
- for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
- /* Add the delayed signal to the chorus sum d_out Note: The
- * delay in the delay line moves backwards for increasing
- * delay!*/
+ pos_samples--;
+ };
- /* The & in chorusbuf[...] is equivalent to a division modulo
- MAX_SAMPLES, only faster. */
- d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
- * chorus->sinc_table[ii][pos_subsamples];
+ /* Cycle the phase of the modulating LFO */
+ chorus->phase[i]++;
- pos_samples--;
- };
- /* Cycle the phase of the modulating LFO */
- chorus->phase[i]++;
- chorus->phase[i] %= (chorus->modulation_period_samples);
- } /* foreach chorus block */
+ chorus->phase[i] %= (chorus->modulation_period_samples);
+ } /* foreach chorus block */
- d_out *= chorus->level;
+ d_out *= chorus->level;
- /* Store the chorus sum d_out to output */
- left_out[sample_index] = d_out;
- right_out[sample_index] = d_out;
+ /* Store the chorus sum d_out to output */
+ left_out[sample_index] = d_out;
+ right_out[sample_index] = d_out;
- /* Move forward in circular buffer */
- chorus->counter++;
- chorus->counter %= MAX_SAMPLES;
+ /* Move forward in circular buffer */
+ chorus->counter++;
+ chorus->counter %= MAX_SAMPLES;
- } /* foreach sample */
+ } /* foreach sample */
}
/* Purpose:
@@ -474,15 +540,25 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
static void
fluid_chorus_sine(int *buf, int len, int depth)
{
- int i;
- double val;
-
- for (i = 0; i < len; i++) {
- val = sin((double) i / (double)len * 2.0 * M_PI);
- buf[i] = (int) ((1.0 + val) * (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES);
- buf[i] -= 3* MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
- // printf("%i %i\n",i,buf[i]);
- }
+ int i;
+ double angle, incr, mult;
+
+ /* Pre-calculate increment between angles. */
+ incr = (2. * M_PI) / (double)len;
+
+ /* Pre-calculate 'depth' multiplier. */
+ mult = (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES;
+
+ /* Initialize to zero degrees. */
+ angle = 0.;
+
+ /* Build sine modulation waveform */
+ for(i = 0; i < len; i++)
+ {
+ buf[i] = (int)((1. + sin(angle)) * mult) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
+
+ angle += incr;
+ }
}
/* Purpose:
@@ -492,15 +568,26 @@ fluid_chorus_sine(int *buf, int len, int depth)
static void
fluid_chorus_triangle(int *buf, int len, int depth)
{
- int i=0;
- int ii=len-1;
- double val;
- double val2;
-
- while (i <= ii){
- val = i * 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
- val2= (int) (val + 0.5) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
- buf[i++] = (int) val2;
- buf[ii--] = (int) val2;
- }
+ int *il = buf;
+ int *ir = buf + len - 1;
+ int ival;
+ double val, incr;
+
+ /* Pre-calculate increment for the ramp. */
+ incr = 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
+
+ /* Initialize first value */
+ val = 0. - 3. * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
+
+ /* Build triangular modulation waveform */
+ while(il <= ir)
+ {
+ /* Assume 'val' to be always negative for rounding mode */
+ ival = (int)(val - 0.5);
+
+ *il++ = ival;
+ *ir-- = ival;
+
+ val += incr;
+ }
}
diff --git a/libs/fluidsynth/src/fluid_chorus.h b/libs/fluidsynth/src/fluid_chorus.h
index 3422fa94b2..8a6734aa0a 100644
--- a/libs/fluidsynth/src/fluid_chorus.h
+++ b/libs/fluidsynth/src/fluid_chorus.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -30,31 +30,35 @@ typedef struct _fluid_chorus_t fluid_chorus_t;
/** Flags for fluid_chorus_set() */
typedef enum
{
- FLUID_CHORUS_SET_NR = 1 << 0,
- FLUID_CHORUS_SET_LEVEL = 1 << 1,
- FLUID_CHORUS_SET_SPEED = 1 << 2,
- FLUID_CHORUS_SET_DEPTH = 1 << 3,
- FLUID_CHORUS_SET_TYPE = 1 << 4,
-} fluid_chorus_set_t;
+ FLUID_CHORUS_SET_NR = 1 << 0,
+ FLUID_CHORUS_SET_LEVEL = 1 << 1,
+ FLUID_CHORUS_SET_SPEED = 1 << 2,
+ FLUID_CHORUS_SET_DEPTH = 1 << 3,
+ FLUID_CHORUS_SET_TYPE = 1 << 4,
-/** Value for fluid_chorus_set() which sets all chorus parameters. */
-#define FLUID_CHORUS_SET_ALL 0x1F
+ /** Value for fluid_chorus_set() which sets all chorus parameters. */
+ FLUID_CHORUS_SET_ALL = FLUID_CHORUS_SET_NR
+ | FLUID_CHORUS_SET_LEVEL
+ | FLUID_CHORUS_SET_SPEED
+ | FLUID_CHORUS_SET_DEPTH
+ | FLUID_CHORUS_SET_TYPE,
+} fluid_chorus_set_t;
/*
* chorus
*/
-fluid_chorus_t* new_fluid_chorus(fluid_real_t sample_rate);
-void delete_fluid_chorus(fluid_chorus_t* chorus);
-int fluid_chorus_init(fluid_chorus_t* chorus);
-void fluid_chorus_reset(fluid_chorus_t* chorus);
-
-void fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
- float speed, float depth_ms, int type);
-
-void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out);
-void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out);
+fluid_chorus_t *new_fluid_chorus(fluid_real_t sample_rate);
+void delete_fluid_chorus(fluid_chorus_t *chorus);
+int fluid_chorus_init(fluid_chorus_t *chorus);
+void fluid_chorus_reset(fluid_chorus_t *chorus);
+
+void fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
+ fluid_real_t speed, fluid_real_t depth_ms, int type);
+
+void fluid_chorus_processmix(fluid_chorus_t *chorus, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out);
+void fluid_chorus_processreplace(fluid_chorus_t *chorus, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out);
diff --git a/libs/fluidsynth/src/fluid_conv.c b/libs/fluidsynth/src/fluid_conv.c
index 1a790cfbfb..555dd61367 100644
--- a/libs/fluidsynth/src/fluid_conv.c
+++ b/libs/fluidsynth/src/fluid_conv.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -20,15 +20,17 @@
#include "fluid_conv.h"
+#define FLUID_CENTS_HZ_SIZE 1200
+#define FLUID_VEL_CB_SIZE 128
+#define FLUID_CB_AMP_SIZE 1441
+#define FLUID_PAN_SIZE 1002
/* conversion tables */
-fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
-fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
-fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE];
-fluid_real_t fluid_posbp_tab[128];
-fluid_real_t fluid_concave_tab[128];
-fluid_real_t fluid_convex_tab[128];
-fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
+static fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
+static fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
+static fluid_real_t fluid_concave_tab[FLUID_VEL_CB_SIZE];
+static fluid_real_t fluid_convex_tab[FLUID_VEL_CB_SIZE];
+static fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
/*
* void fluid_synth_init
@@ -38,58 +40,52 @@ fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
void
fluid_conversion_config(void)
{
- int i;
- double x;
-
- for (i = 0; i < FLUID_CENTS_HZ_SIZE; i++) {
- fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0);
- }
-
- /* centibels to amplitude conversion
- * Note: SF2.01 section 8.1.3: Initial attenuation range is
- * between 0 and 144 dB. Therefore a negative attenuation is
- * not allowed.
- */
- for (i = 0; i < FLUID_CB_AMP_SIZE; i++) {
- fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
- }
-
- /* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont
- * specification in regards to volume attenuation. The below calculation
- * is an approx. equation for generating a table equivelant to the
- * cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told
- * was generated from device testing. By the spec this should be centibels.
- */
- for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) {
- fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR);
- }
-
- /* initialize the conversion tables (see fluid_mod.c
- fluid_mod_get_value cases 4 and 8) */
-
- /* concave unipolar positive transform curve */
- fluid_concave_tab[0] = 0.0;
- fluid_concave_tab[127] = 1.0;
-
- /* convex unipolar positive transform curve */
- fluid_convex_tab[0] = 0;
- fluid_convex_tab[127] = 1.0;
- x = log10(128.0 / 127.0);
-
- /* There seems to be an error in the specs. The equations are
- implemented according to the pictures on SF2.01 page 73. */
-
- for (i = 1; i < 127; i++) {
- x = -20.0 / 96.0 * log((i * i) / (127.0 * 127.0)) / log(10.0);
- fluid_convex_tab[i] = (fluid_real_t) (1.0 - x);
- fluid_concave_tab[127 - i] = (fluid_real_t) x;
- }
-
- /* initialize the pan conversion table */
- x = PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
- for (i = 0; i < FLUID_PAN_SIZE; i++) {
- fluid_pan_tab[i] = (fluid_real_t) sin(i * x);
- }
+ int i;
+ double x;
+
+ for(i = 0; i < FLUID_CENTS_HZ_SIZE; i++)
+ {
+ fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0);
+ }
+
+ /* centibels to amplitude conversion
+ * Note: SF2.01 section 8.1.3: Initial attenuation range is
+ * between 0 and 144 dB. Therefore a negative attenuation is
+ * not allowed.
+ */
+ for(i = 0; i < FLUID_CB_AMP_SIZE; i++)
+ {
+ fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
+ }
+
+ /* initialize the conversion tables (see fluid_mod.c
+ fluid_mod_get_value cases 4 and 8) */
+
+ /* concave unipolar positive transform curve */
+ fluid_concave_tab[0] = 0.0;
+ fluid_concave_tab[FLUID_VEL_CB_SIZE - 1] = 1.0;
+
+ /* convex unipolar positive transform curve */
+ fluid_convex_tab[0] = 0;
+ fluid_convex_tab[FLUID_VEL_CB_SIZE - 1] = 1.0;
+
+ /* There seems to be an error in the specs. The equations are
+ implemented according to the pictures on SF2.01 page 73. */
+
+ for(i = 1; i < FLUID_VEL_CB_SIZE - 1; i++)
+ {
+ x = (-200.0 / FLUID_PEAK_ATTENUATION) * log((i * i) / (fluid_real_t)((FLUID_VEL_CB_SIZE - 1) * (FLUID_VEL_CB_SIZE - 1))) / M_LN10;
+ fluid_convex_tab[i] = (fluid_real_t)(1.0 - x);
+ fluid_concave_tab[(FLUID_VEL_CB_SIZE - 1) - i] = (fluid_real_t) x;
+ }
+
+ /* initialize the pan conversion table */
+ x = M_PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
+
+ for(i = 0; i < FLUID_PAN_SIZE; i++)
+ {
+ fluid_pan_tab[i] = (fluid_real_t) sin(i * x);
+ }
}
/*
@@ -98,35 +94,62 @@ fluid_conversion_config(void)
fluid_real_t
fluid_ct2hz_real(fluid_real_t cents)
{
- if (cents < 0)
- return (fluid_real_t) 1.0;
- else if (cents < 900) {
- return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int) (cents + 300)];
- } else if (cents < 2100) {
- return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int) (cents - 900)];
- } else if (cents < 3300) {
- return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int) (cents - 2100)];
- } else if (cents < 4500) {
- return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int) (cents - 3300)];
- } else if (cents < 5700) {
- return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int) (cents - 4500)];
- } else if (cents < 6900) {
- return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int) (cents - 5700)];
- } else if (cents < 8100) {
- return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int) (cents - 6900)];
- } else if (cents < 9300) {
- return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int) (cents - 8100)];
- } else if (cents < 10500) {
- return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int) (cents - 9300)];
- } else if (cents < 11700) {
- return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int) (cents - 10500)];
- } else if (cents < 12900) {
- return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int) (cents - 11700)];
- } else if (cents < 14100) {
- return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int) (cents - 12900)];
- } else {
- return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
- }
+ if(cents < 0)
+ {
+ return (fluid_real_t) 1.0;
+ }
+ else if(cents < 900)
+ {
+ return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int)(cents + 300)];
+ }
+ else if(cents < 2100)
+ {
+ return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int)(cents - 900)];
+ }
+ else if(cents < 3300)
+ {
+ return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int)(cents - 2100)];
+ }
+ else if(cents < 4500)
+ {
+ return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int)(cents - 3300)];
+ }
+ else if(cents < 5700)
+ {
+ return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int)(cents - 4500)];
+ }
+ else if(cents < 6900)
+ {
+ return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int)(cents - 5700)];
+ }
+ else if(cents < 8100)
+ {
+ return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int)(cents - 6900)];
+ }
+ else if(cents < 9300)
+ {
+ return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int)(cents - 8100)];
+ }
+ else if(cents < 10500)
+ {
+ return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int)(cents - 9300)];
+ }
+ else if(cents < 11700)
+ {
+ return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int)(cents - 10500)];
+ }
+ else if(cents < 12900)
+ {
+ return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int)(cents - 11700)];
+ }
+ else if(cents < 14100)
+ {
+ return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int)(cents - 12900)];
+ }
+ else
+ {
+ return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
+ }
}
/*
@@ -135,55 +158,46 @@ fluid_ct2hz_real(fluid_real_t cents)
fluid_real_t
fluid_ct2hz(fluid_real_t cents)
{
- /* Filter fc limit: SF2.01 page 48 # 8 */
- if (cents >= 13500){
- cents = 13500; /* 20 kHz */
- } else if (cents < 1500){
- cents = 1500; /* 20 Hz */
- }
- return fluid_ct2hz_real(cents);
+ /* Filter fc limit: SF2.01 page 48 # 8 */
+ if(cents >= 13500)
+ {
+ cents = 13500; /* 20 kHz */
+ }
+ else if(cents < 1500)
+ {
+ cents = 1500; /* 20 Hz */
+ }
+
+ return fluid_ct2hz_real(cents);
}
/*
* fluid_cb2amp
*
- * in: a value between 0 and 960, 0 is no attenuation
+ * in: a value between 0 and 1440, 0 is no attenuation
* out: a value between 1 and 0
*/
fluid_real_t
fluid_cb2amp(fluid_real_t cb)
{
- /*
- * cb: an attenuation in 'centibels' (1/10 dB)
- * SF2.01 page 49 # 48 limits it to 144 dB.
- * 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
- */
-
- /* minimum attenuation: 0 dB */
- if (cb < 0) {
- return 1.0;
- }
- if (cb >= FLUID_CB_AMP_SIZE) {
- return 0.0;
- }
- return fluid_cb2amp_tab[(int) cb];
-}
+ /*
+ * cb: an attenuation in 'centibels' (1/10 dB)
+ * SF2.01 page 49 # 48 limits it to 144 dB.
+ * 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
+ */
-/*
- * fluid_atten2amp
- *
- * in: a value between 0 and 1440, 0 is no attenuation
- * out: a value between 1 and 0
- *
- * Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't
- * follow this. Thats the reason for separate fluid_cb2amp and fluid_atten2amp.
- */
-fluid_real_t
-fluid_atten2amp(fluid_real_t atten)
-{
- if (atten < 0) return 1.0;
- else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0;
- else return fluid_atten2amp_tab[(int) atten];
+ /* minimum attenuation: 0 dB */
+ if(cb < 0)
+ {
+ return 1.0;
+ }
+
+ if(cb >= FLUID_CB_AMP_SIZE)
+ {
+ return 0.0;
+ }
+
+ return fluid_cb2amp_tab[(int) cb];
}
/*
@@ -192,21 +206,27 @@ fluid_atten2amp(fluid_real_t atten)
fluid_real_t
fluid_tc2sec_delay(fluid_real_t tc)
{
- /* SF2.01 section 8.1.2 items 21, 23, 25, 33
- * SF2.01 section 8.1.3 items 21, 23, 25, 33
- *
- * The most negative number indicates a delay of 0. Range is limited
- * from -12000 to 5000 */
- if (tc <= -32768.0f) {
- return (fluid_real_t) 0.0f;
- };
- if (tc < -12000.) {
- tc = (fluid_real_t) -12000.0f;
- }
- if (tc > 5000.0f) {
- tc = (fluid_real_t) 5000.0f;
- }
- return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
+ /* SF2.01 section 8.1.2 items 21, 23, 25, 33
+ * SF2.01 section 8.1.3 items 21, 23, 25, 33
+ *
+ * The most negative number indicates a delay of 0. Range is limited
+ * from -12000 to 5000 */
+ if(tc <= -32768.0f)
+ {
+ return (fluid_real_t) 0.0f;
+ };
+
+ if(tc < -12000.)
+ {
+ tc = (fluid_real_t) -12000.0f;
+ }
+
+ if(tc > 5000.0f)
+ {
+ tc = (fluid_real_t) 5000.0f;
+ }
+
+ return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
@@ -215,14 +235,26 @@ fluid_tc2sec_delay(fluid_real_t tc)
fluid_real_t
fluid_tc2sec_attack(fluid_real_t tc)
{
- /* SF2.01 section 8.1.2 items 26, 34
- * SF2.01 section 8.1.3 items 26, 34
- * The most negative number indicates a delay of 0
- * Range is limited from -12000 to 8000 */
- if (tc<=-32768.){return (fluid_real_t) 0.0;};
- if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
- if (tc>8000.){tc=(fluid_real_t) 8000.0;};
- return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
+ /* SF2.01 section 8.1.2 items 26, 34
+ * SF2.01 section 8.1.3 items 26, 34
+ * The most negative number indicates a delay of 0
+ * Range is limited from -12000 to 8000 */
+ if(tc <= -32768.)
+ {
+ return (fluid_real_t) 0.0;
+ };
+
+ if(tc < -12000.)
+ {
+ tc = (fluid_real_t) -12000.0;
+ };
+
+ if(tc > 8000.)
+ {
+ tc = (fluid_real_t) 8000.0;
+ };
+
+ return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
@@ -231,8 +263,8 @@ fluid_tc2sec_attack(fluid_real_t tc)
fluid_real_t
fluid_tc2sec(fluid_real_t tc)
{
- /* No range checking here! */
- return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
+ /* No range checking here! */
+ return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
@@ -241,14 +273,26 @@ fluid_tc2sec(fluid_real_t tc)
fluid_real_t
fluid_tc2sec_release(fluid_real_t tc)
{
- /* SF2.01 section 8.1.2 items 30, 38
- * SF2.01 section 8.1.3 items 30, 38
- * No 'most negative number' rule here!
- * Range is limited from -12000 to 8000 */
- if (tc<=-32768.){return (fluid_real_t) 0.0;};
- if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
- if (tc>8000.){tc=(fluid_real_t) 8000.0;};
- return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
+ /* SF2.01 section 8.1.2 items 30, 38
+ * SF2.01 section 8.1.3 items 30, 38
+ * No 'most negative number' rule here!
+ * Range is limited from -12000 to 8000 */
+ if(tc <= -32768.)
+ {
+ return (fluid_real_t) 0.0;
+ };
+
+ if(tc < -12000.)
+ {
+ tc = (fluid_real_t) -12000.0;
+ };
+
+ if(tc > 8000.)
+ {
+ tc = (fluid_real_t) 8000.0;
+ };
+
+ return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
@@ -259,7 +303,7 @@ fluid_tc2sec_release(fluid_real_t tc)
fluid_real_t
fluid_act2hz(fluid_real_t c)
{
- return (fluid_real_t) (8.176 * pow(2.0, (double) c / 1200.0));
+ return (fluid_real_t)(8.176 * pow(2.0, (double) c / 1200.0));
}
/*
@@ -270,7 +314,7 @@ fluid_act2hz(fluid_real_t c)
fluid_real_t
fluid_hz2ct(fluid_real_t f)
{
- return (fluid_real_t) (6900 + 1200 * log(f / 440.0) / log(2.0));
+ return (fluid_real_t)(6900 + 1200 * log(f / 440.0) / M_LN2);
}
/*
@@ -279,16 +323,53 @@ fluid_hz2ct(fluid_real_t f)
fluid_real_t
fluid_pan(fluid_real_t c, int left)
{
- if (left) {
- c = -c;
- }
- if (c < -500) {
- return (fluid_real_t) 0.0;
- } else if (c > 500) {
- return (fluid_real_t) 1.0;
- } else {
- return fluid_pan_tab[(int) (c + 500)];
- }
+ if(left)
+ {
+ c = -c;
+ }
+
+ if(c <= -500)
+ {
+ return (fluid_real_t) 0.0;
+ }
+ else if(c >= 500)
+ {
+ return (fluid_real_t) 1.0;
+ }
+ else
+ {
+ return fluid_pan_tab[(int)(c + 500)];
+ }
+}
+
+/*
+ * Return the amount of attenuation based on the balance for the specified
+ * channel. If balance is negative (turned toward left channel, only the right
+ * channel is attenuated. If balance is positive, only the left channel is
+ * attenuated.
+ *
+ * @params balance left/right balance, range [-960;960] in absolute centibels
+ * @return amount of attenuation [0.0;1.0]
+ */
+fluid_real_t fluid_balance(fluid_real_t balance, int left)
+{
+ /* This is the most common case */
+ if(balance == 0)
+ {
+ return 1.0f;
+ }
+
+ if((left && balance < 0) || (!left && balance > 0))
+ {
+ return 1.0f;
+ }
+
+ if(balance < 0)
+ {
+ balance = -balance;
+ }
+
+ return fluid_cb2amp(balance);
}
/*
@@ -297,12 +378,16 @@ fluid_pan(fluid_real_t c, int left)
fluid_real_t
fluid_concave(fluid_real_t val)
{
- if (val < 0) {
- return 0;
- } else if (val > 127) {
- return 1;
- }
- return fluid_concave_tab[(int) val];
+ if(val < 0)
+ {
+ return 0;
+ }
+ else if(val >= FLUID_VEL_CB_SIZE)
+ {
+ return 1;
+ }
+
+ return fluid_concave_tab[(int) val];
}
/*
@@ -311,10 +396,14 @@ fluid_concave(fluid_real_t val)
fluid_real_t
fluid_convex(fluid_real_t val)
{
- if (val < 0) {
- return 0;
- } else if (val > 127) {
- return 1;
- }
- return fluid_convex_tab[(int) val];
+ if(val < 0)
+ {
+ return 0;
+ }
+ else if(val >= FLUID_VEL_CB_SIZE)
+ {
+ return 1;
+ }
+
+ return fluid_convex_tab[(int) val];
}
diff --git a/libs/fluidsynth/src/fluid_conv.h b/libs/fluidsynth/src/fluid_conv.h
index 29793c3359..d84a321c6c 100644
--- a/libs/fluidsynth/src/fluid_conv.h
+++ b/libs/fluidsynth/src/fluid_conv.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -23,24 +23,42 @@
#include "fluidsynth_priv.h"
-#define FLUID_CENTS_HZ_SIZE 1200
-#define FLUID_VEL_CB_SIZE 128
-#define FLUID_CB_AMP_SIZE 961
-#define FLUID_ATTEN_AMP_SIZE 1441
-#define FLUID_PAN_SIZE 1002
+/*
+ Attenuation range in centibels.
+ Attenuation range is the dynamic range of the volume envelope generator
+ from 0 to the end of attack segment.
+ fluidsynth is a 24 bit synth, it could (should??) be 144 dB of attenuation.
+ However the spec makes no distinction between 16 or 24 bit synths, so use
+ 96 dB here.
-/* EMU 8k/10k don't follow spec in regards to volume attenuation.
- * This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR).
- * By the standard this should be -200.0. */
-/* 07/11/2008 modified by S. Christian Collins for increased velocity sensitivity. Now it equals the response of EMU10K1 programming.*/
-#define FLUID_ATTEN_POWER_FACTOR (-200.0) /* was (-531.509)*/
+ Note about usefulness of 24 bits:
+ 1)Even fluidsynth is a 24 bit synth, this format is only relevant if
+ the sample format coming from the soundfont is 24 bits and the audio sample format
+ choosen by the application (audio.sample.format) is not 16 bits.
+
+ 2)When the sample soundfont is 16 bits, the internal 24 bits number have
+ 16 bits msb and lsb to 0. Consequently, at the DAC output, the dynamic range of
+ this 24 bit sample is reduced to the the dynamic of a 16 bits sample (ie 90 db)
+ even if this sample is produced by the audio driver using an audio sample format
+ compatible for a 24 bit DAC.
+
+ 3)When the audio sample format settings is 16 bits (audio.sample.format), the
+ audio driver will make use of a 16 bit DAC, and the dynamic will be reduced to 96 dB
+ even if the initial sample comes from a 24 bits soundfont.
+
+ In both cases (2) or (3), the real dynamic range is only 96 dB.
+
+ Other consideration for FLUID_NOISE_FLOOR related to case (1),(2,3):
+ - for case (1), FLUID_NOISE_FLOOR should be the noise floor for 24 bits (i.e -138 dB).
+ - for case (2) or (3), FLUID_NOISE_FLOOR should be the noise floor for 16 bits (i.e -90 dB).
+ */
+#define FLUID_PEAK_ATTENUATION 960.0f
void fluid_conversion_config(void);
fluid_real_t fluid_ct2hz_real(fluid_real_t cents);
fluid_real_t fluid_ct2hz(fluid_real_t cents);
fluid_real_t fluid_cb2amp(fluid_real_t cb);
-fluid_real_t fluid_atten2amp(fluid_real_t atten);
fluid_real_t fluid_tc2sec(fluid_real_t tc);
fluid_real_t fluid_tc2sec_delay(fluid_real_t tc);
fluid_real_t fluid_tc2sec_attack(fluid_real_t tc);
@@ -48,16 +66,8 @@ fluid_real_t fluid_tc2sec_release(fluid_real_t tc);
fluid_real_t fluid_act2hz(fluid_real_t c);
fluid_real_t fluid_hz2ct(fluid_real_t c);
fluid_real_t fluid_pan(fluid_real_t c, int left);
+fluid_real_t fluid_balance(fluid_real_t balance, int left);
fluid_real_t fluid_concave(fluid_real_t val);
fluid_real_t fluid_convex(fluid_real_t val);
-extern fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
-extern fluid_real_t fluid_vel2cb_tab[FLUID_VEL_CB_SIZE];
-extern fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
-extern fluid_real_t fluid_posbp_tab[128];
-extern fluid_real_t fluid_concave_tab[128];
-extern fluid_real_t fluid_convex_tab[128];
-extern fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
-
-
#endif /* _FLUID_CONV_H */
diff --git a/libs/fluidsynth/src/fluid_defsfont.c b/libs/fluidsynth/src/fluid_defsfont.c
index c395218411..6e19eb71af 100644
--- a/libs/fluidsynth/src/fluid_defsfont.c
+++ b/libs/fluidsynth/src/fluid_defsfont.c
@@ -6,16 +6,16 @@
* Copyright (C) 1999-2001 Josh Green
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -23,69 +23,92 @@
#include "fluid_defsfont.h"
-/* Todo: Get rid of that 'include' */
+#include "fluid_sfont.h"
#include "fluid_sys.h"
+#include "fluid_synth.h"
+#include "fluid_samplecache.h"
+
+/* EMU8k/10k hardware applies this factor to initial attenuation generator values set at preset and
+ * instrument level in a soundfont. We apply this factor when loading the generator values to stay
+ * compatible as most existing soundfonts expect exactly this (strange, non-standard) behaviour. */
+#define EMU_ATTENUATION_FACTOR (0.4f)
+
+/* Dynamic sample loading functions */
+static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);
+static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);
+static void unload_sample(fluid_sample_t *sample);
+static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan);
+static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason);
+static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone);
+static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx);
+
/***************************************************************
*
* SFONT LOADER
*/
-fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings)
+/**
+ * Creates a default soundfont2 loader that can be used with fluid_synth_add_sfloader().
+ * By default every synth instance has an initial default soundfont loader instance.
+ * Calling this function is usually only necessary to load a soundfont from memory, by providing custom callback functions via fluid_sfloader_set_callbacks().
+ *
+ * @param settings A settings instance obtained by new_fluid_settings()
+ * @return A default soundfont2 loader struct
+ */
+fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings)
{
- fluid_sfloader_t* loader;
+ fluid_sfloader_t *loader;
+ fluid_return_val_if_fail(settings != NULL, NULL);
- loader = FLUID_NEW(fluid_sfloader_t);
- if (loader == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
+ loader = new_fluid_sfloader(fluid_defsfloader_load, delete_fluid_sfloader);
- loader->data = settings;
- loader->free = delete_fluid_defsfloader;
- loader->load = fluid_defsfloader_load;
+ if(loader == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
- return loader;
-}
+ fluid_sfloader_set_data(loader, settings);
-int delete_fluid_defsfloader(fluid_sfloader_t* loader)
-{
- if (loader) {
- FLUID_FREE(loader);
- }
- return FLUID_OK;
+ return loader;
}
-fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename)
+fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *filename)
{
- fluid_defsfont_t* defsfont;
- fluid_sfont_t* sfont;
+ fluid_defsfont_t *defsfont;
+ fluid_sfont_t *sfont;
- defsfont = new_fluid_defsfont(loader->data);
+ defsfont = new_fluid_defsfont(fluid_sfloader_get_data(loader));
- if (defsfont == NULL) {
- return NULL;
- }
+ if(defsfont == NULL)
+ {
+ return NULL;
+ }
- if (fluid_defsfont_load(defsfont, filename) == FLUID_FAILED) {
- delete_fluid_defsfont(defsfont);
- return NULL;
- }
+ sfont = new_fluid_sfont(fluid_defsfont_sfont_get_name,
+ fluid_defsfont_sfont_get_preset,
+ fluid_defsfont_sfont_iteration_start,
+ fluid_defsfont_sfont_iteration_next,
+ fluid_defsfont_sfont_delete);
- sfont = FLUID_NEW(fluid_sfont_t);
- if (sfont == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
+ if(sfont == NULL)
+ {
+ delete_fluid_defsfont(defsfont);
+ return NULL;
+ }
- sfont->data = defsfont;
- sfont->free = fluid_defsfont_sfont_delete;
- sfont->get_name = fluid_defsfont_sfont_get_name;
- sfont->get_preset = fluid_defsfont_sfont_get_preset;
- sfont->iteration_start = fluid_defsfont_sfont_iteration_start;
- sfont->iteration_next = fluid_defsfont_sfont_iteration_next;
+ fluid_sfont_set_data(sfont, defsfont);
- return sfont;
+ defsfont->sfont = sfont;
+
+ if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED)
+ {
+ fluid_sfont_delete_internal(sfont);
+ return NULL;
+ }
+
+ return sfont;
}
@@ -95,621 +118,487 @@ fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* file
* PUBLIC INTERFACE
*/
-int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont)
+int fluid_defsfont_sfont_delete(fluid_sfont_t *sfont)
{
- if (delete_fluid_defsfont(sfont->data) != 0) {
- return -1;
- }
- FLUID_FREE(sfont);
- return 0;
-}
+ if(delete_fluid_defsfont(fluid_sfont_get_data(sfont)) != FLUID_OK)
+ {
+ return -1;
+ }
-char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont)
-{
- return fluid_defsfont_get_name((fluid_defsfont_t*) sfont->data);
+ delete_fluid_sfont(sfont);
+ return 0;
}
-#if 0
-fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s)
+const char *fluid_defsfont_sfont_get_name(fluid_sfont_t *sfont)
{
- /* This function is here just to avoid an ABI/SONAME bump, see ticket #98. Should never be used. */
- return NULL;
+ return fluid_defsfont_get_name(fluid_sfont_get_data(sfont));
}
-#endif
-fluid_preset_t*
-fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum)
+fluid_preset_t *
+fluid_defsfont_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum)
{
- fluid_preset_t* preset = NULL;
- fluid_defpreset_t* defpreset;
- fluid_defsfont_t* defsfont = sfont->data;
-
- defpreset = fluid_defsfont_get_preset(defsfont, bank, prenum);
-
- if (defpreset == NULL) {
- return NULL;
- }
-
- if (defsfont->preset_stack_size > 0) {
- defsfont->preset_stack_size--;
- preset = defsfont->preset_stack[defsfont->preset_stack_size];
- }
- if (!preset)
- preset = FLUID_NEW(fluid_preset_t);
- if (!preset) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- preset->sfont = sfont;
- preset->data = defpreset;
- preset->free = fluid_defpreset_preset_delete;
- preset->get_name = fluid_defpreset_preset_get_name;
- preset->get_banknum = fluid_defpreset_preset_get_banknum;
- preset->get_num = fluid_defpreset_preset_get_num;
- preset->noteon = fluid_defpreset_preset_noteon;
- preset->notify = NULL;
-
- return preset;
+ return fluid_defsfont_get_preset(fluid_sfont_get_data(sfont), bank, prenum);
}
-void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont)
+void fluid_defsfont_sfont_iteration_start(fluid_sfont_t *sfont)
{
- fluid_defsfont_iteration_start((fluid_defsfont_t*) sfont->data);
+ fluid_defsfont_iteration_start(fluid_sfont_get_data(sfont));
}
-int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset)
+fluid_preset_t *fluid_defsfont_sfont_iteration_next(fluid_sfont_t *sfont)
{
- preset->free = fluid_defpreset_preset_delete;
- preset->get_name = fluid_defpreset_preset_get_name;
- preset->get_banknum = fluid_defpreset_preset_get_banknum;
- preset->get_num = fluid_defpreset_preset_get_num;
- preset->noteon = fluid_defpreset_preset_noteon;
- preset->notify = NULL;
-
- return fluid_defsfont_iteration_next((fluid_defsfont_t*) sfont->data, preset);
+ return fluid_defsfont_iteration_next(fluid_sfont_get_data(sfont));
}
-int fluid_defpreset_preset_delete(fluid_preset_t* preset)
+void fluid_defpreset_preset_delete(fluid_preset_t *preset)
{
- fluid_defpreset_t* defpreset = preset ? preset->data : NULL;
- fluid_defsfont_t* sfont = defpreset ? defpreset->sfont : NULL;
+ fluid_defsfont_t *defsfont;
+ fluid_defpreset_t *defpreset;
+
+ defsfont = fluid_sfont_get_data(preset->sfont);
+ defpreset = fluid_preset_get_data(preset);
- if (sfont && sfont->preset_stack_size < sfont->preset_stack_capacity) {
- sfont->preset_stack[sfont->preset_stack_size] = preset;
- sfont->preset_stack_size++;
- }
- else
- FLUID_FREE(preset);
+ if(defsfont)
+ {
+ defsfont->preset = fluid_list_remove(defsfont->preset, defpreset);
+ }
- return 0;
+ delete_fluid_defpreset(defpreset);
+ delete_fluid_preset(preset);
}
-char* fluid_defpreset_preset_get_name(fluid_preset_t* preset)
+const char *fluid_defpreset_preset_get_name(fluid_preset_t *preset)
{
- return fluid_defpreset_get_name((fluid_defpreset_t*) preset->data);
+ return fluid_defpreset_get_name(fluid_preset_get_data(preset));
}
-int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset)
+int fluid_defpreset_preset_get_banknum(fluid_preset_t *preset)
{
- return fluid_defpreset_get_banknum((fluid_defpreset_t*) preset->data);
+ return fluid_defpreset_get_banknum(fluid_preset_get_data(preset));
}
-int fluid_defpreset_preset_get_num(fluid_preset_t* preset)
+int fluid_defpreset_preset_get_num(fluid_preset_t *preset)
{
- return fluid_defpreset_get_num((fluid_defpreset_t*) preset->data);
+ return fluid_defpreset_get_num(fluid_preset_get_data(preset));
}
-int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth,
- int chan, int key, int vel)
+int fluid_defpreset_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth,
+ int chan, int key, int vel)
{
- return fluid_defpreset_noteon((fluid_defpreset_t*) preset->data, synth, chan, key, vel);
+ return fluid_defpreset_noteon(fluid_preset_get_data(preset), synth, chan, key, vel);
}
-
-
/***************************************************************
*
- * CACHED SAMPLEDATA LOADER
+ * SFONT
*/
-typedef struct _fluid_cached_sampledata_t {
- struct _fluid_cached_sampledata_t *next;
-
- char* filename;
- time_t modification_time;
- int num_references;
- int mlock;
-
- const short* sampledata;
- unsigned int samplesize;
-} fluid_cached_sampledata_t;
+/*
+ * new_fluid_defsfont
+ */
+fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings)
+{
+ fluid_defsfont_t *defsfont;
-static fluid_cached_sampledata_t* all_cached_sampledata = NULL;
-static fluid_mutex_t cached_sampledata_mutex = FLUID_MUTEX_INIT;
+ defsfont = FLUID_NEW(fluid_defsfont_t);
-static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
-{
-#if defined(WIN32) || defined(__OS2__)
- *modification_time = 0;
- return FLUID_OK;
-#else
- struct stat buf;
+ if(defsfont == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
- if (stat(filename, &buf) == -1) {
- return FLUID_FAILED;
- }
+ FLUID_MEMSET(defsfont, 0, sizeof(*defsfont));
- *modification_time = buf.st_mtime;
- return FLUID_OK;
-#endif
-}
+ fluid_settings_getint(settings, "synth.lock-memory", &defsfont->mlock);
+ fluid_settings_getint(settings, "synth.dynamic-sample-loading", &defsfont->dynamic_samples);
-static int fluid_cached_sampledata_load(char *filename, unsigned int samplepos,
- unsigned int samplesize, short **sampledata, int try_mlock)
-{
- fluid_file fd = NULL;
- short *loaded_sampledata = NULL;
- fluid_cached_sampledata_t* cached_sampledata = NULL;
- time_t modification_time;
-
- fluid_mutex_lock(cached_sampledata_mutex);
-
- if (fluid_get_file_modification_time(filename, &modification_time) == FLUID_FAILED) {
- FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
- modification_time = 0;
- }
-
- for (cached_sampledata = all_cached_sampledata; cached_sampledata; cached_sampledata = cached_sampledata->next) {
- if (strcmp(filename, cached_sampledata->filename))
- continue;
- if (cached_sampledata->modification_time != modification_time)
- continue;
- if (cached_sampledata->samplesize != samplesize) {
- FLUID_LOG(FLUID_ERR, "Cached size of soundfont doesn't match actual size of soundfont (cached: %u. actual: %u)",
- cached_sampledata->samplesize, samplesize);
- continue;
- }
-
- if (try_mlock && !cached_sampledata->mlock) {
- if (fluid_mlock(cached_sampledata->sampledata, samplesize) != 0)
- FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
- else
- cached_sampledata->mlock = try_mlock;
- }
-
- cached_sampledata->num_references++;
- loaded_sampledata = (short*) cached_sampledata->sampledata;
- goto success_exit;
- }
-
- fd = FLUID_FOPEN(filename, "rb");
- if (fd == NULL) {
- FLUID_LOG(FLUID_ERR, "Can't open soundfont file");
- goto error_exit;
- }
- if (FLUID_FSEEK(fd, samplepos, SEEK_SET) == -1) {
- perror("error");
- FLUID_LOG(FLUID_ERR, "Failed to seek position in data file");
- goto error_exit;
- }
-
-
- loaded_sampledata = (short*) FLUID_MALLOC(samplesize);
- if (loaded_sampledata == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_exit;
- }
- if (FLUID_FREAD(loaded_sampledata, 1, samplesize, fd) < samplesize) {
- FLUID_LOG(FLUID_ERR, "Failed to read sample data");
- goto error_exit;
- }
-
- FLUID_FCLOSE(fd);
- fd = NULL;
-
-
- cached_sampledata = (fluid_cached_sampledata_t*) FLUID_MALLOC(sizeof(fluid_cached_sampledata_t));
- if (cached_sampledata == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory.");
- goto error_exit;
- }
-
- /* Lock the memory to disable paging. It's okay if this fails. It
- probably means that the user doesn't have to required permission. */
- cached_sampledata->mlock = 0;
- if (try_mlock) {
- if (fluid_mlock(loaded_sampledata, samplesize) != 0)
- FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
- else
- cached_sampledata->mlock = try_mlock;
- }
-
- /* If this machine is big endian, the sample have to byte swapped */
- if (FLUID_IS_BIG_ENDIAN) {
- unsigned char* cbuf;
- unsigned char hi, lo;
- unsigned int i, j;
- short s;
- cbuf = (unsigned char*)loaded_sampledata;
- for (i = 0, j = 0; j < samplesize; i++) {
- lo = cbuf[j++];
- hi = cbuf[j++];
- s = (hi << 8) | lo;
- loaded_sampledata[i] = s;
- }
- }
-
- cached_sampledata->filename = (char*) FLUID_MALLOC(strlen(filename) + 1);
- if (cached_sampledata->filename == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory.");
- goto error_exit;
- }
-
- sprintf(cached_sampledata->filename, "%s", filename);
- cached_sampledata->modification_time = modification_time;
- cached_sampledata->num_references = 1;
- cached_sampledata->sampledata = loaded_sampledata;
- cached_sampledata->samplesize = samplesize;
-
- cached_sampledata->next = all_cached_sampledata;
- all_cached_sampledata = cached_sampledata;
-
-
- success_exit:
- fluid_mutex_unlock(cached_sampledata_mutex);
- *sampledata = loaded_sampledata;
- return FLUID_OK;
-
- error_exit:
- if (fd != NULL) {
- FLUID_FCLOSE(fd);
- }
- if (loaded_sampledata != NULL) {
- FLUID_FREE(loaded_sampledata);
- }
-
- if (cached_sampledata != NULL) {
- if (cached_sampledata->filename != NULL) {
- FLUID_FREE(cached_sampledata->filename);
- }
- FLUID_FREE(cached_sampledata);
- }
-
- fluid_mutex_unlock(cached_sampledata_mutex);
- *sampledata = NULL;
- return FLUID_FAILED;
+ return defsfont;
}
-static int fluid_cached_sampledata_unload(const short *sampledata)
+/*
+ * delete_fluid_defsfont
+ */
+int delete_fluid_defsfont(fluid_defsfont_t *defsfont)
{
- fluid_cached_sampledata_t* prev = NULL;
- fluid_cached_sampledata_t* cached_sampledata;
-
- fluid_mutex_lock(cached_sampledata_mutex);
- cached_sampledata = all_cached_sampledata;
+ fluid_list_t *list;
+ fluid_preset_t *preset;
+ fluid_sample_t *sample;
- while (cached_sampledata != NULL) {
- if (sampledata == cached_sampledata->sampledata) {
+ fluid_return_val_if_fail(defsfont != NULL, FLUID_OK);
- cached_sampledata->num_references--;
-
- if (cached_sampledata->num_references == 0) {
- if (cached_sampledata->mlock)
- fluid_munlock(cached_sampledata->sampledata, cached_sampledata->samplesize);
- FLUID_FREE((short*) cached_sampledata->sampledata);
- FLUID_FREE(cached_sampledata->filename);
+ /* Check that no samples are currently used */
+ for(list = defsfont->sample; list; list = fluid_list_next(list))
+ {
+ sample = (fluid_sample_t *) fluid_list_get(list);
- if (prev != NULL) {
- prev->next = cached_sampledata->next;
- } else {
- all_cached_sampledata = cached_sampledata->next;
+ if(sample->refcount != 0)
+ {
+ return FLUID_FAILED;
}
+ }
- FLUID_FREE(cached_sampledata);
- }
+ if(defsfont->filename != NULL)
+ {
+ FLUID_FREE(defsfont->filename);
+ }
- goto success_exit;
+ for(list = defsfont->sample; list; list = fluid_list_next(list))
+ {
+ delete_fluid_sample((fluid_sample_t *) fluid_list_get(list));
}
- prev = cached_sampledata;
- cached_sampledata = cached_sampledata->next;
- }
+ if(defsfont->sample)
+ {
+ delete_fluid_list(defsfont->sample);
+ }
- FLUID_LOG(FLUID_ERR, "Trying to free sampledata not found in cache.");
- goto error_exit;
-
- success_exit:
- fluid_mutex_unlock(cached_sampledata_mutex);
- return FLUID_OK;
+ if(defsfont->sampledata != NULL)
+ {
+ fluid_samplecache_unload(defsfont->sampledata);
+ }
- error_exit:
- fluid_mutex_unlock(cached_sampledata_mutex);
- return FLUID_FAILED;
-}
+ for(list = defsfont->preset; list; list = fluid_list_next(list))
+ {
+ preset = (fluid_preset_t *)fluid_list_get(list);
+ fluid_defpreset_preset_delete(preset);
+ }
+ delete_fluid_list(defsfont->preset);
+ for(list = defsfont->inst; list; list = fluid_list_next(list))
+ {
+ delete_fluid_inst(fluid_list_get(list));
+ }
+ delete_fluid_list(defsfont->inst);
-/***************************************************************
- *
- * SFONT
- */
+ FLUID_FREE(defsfont);
+ return FLUID_OK;
+}
/*
- * new_fluid_defsfont
+ * fluid_defsfont_get_name
*/
-fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings)
+const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont)
{
- fluid_defsfont_t* sfont;
- int i;
+ return defsfont->filename;
+}
- sfont = FLUID_NEW(fluid_defsfont_t);
- if (sfont == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- sfont->filename = NULL;
- sfont->samplepos = 0;
- sfont->samplesize = 0;
- sfont->sample = NULL;
- sfont->sampledata = NULL;
- sfont->preset = NULL;
- fluid_settings_getint(settings, "synth.lock-memory", &sfont->mlock);
-
- /* Initialise preset cache, so we don't have to call malloc on program changes.
- Usually, we have at most one preset per channel plus one temporarily used,
- so optimise for that case. */
- fluid_settings_getint(settings, "synth.midi-channels", &sfont->preset_stack_capacity);
- sfont->preset_stack_capacity++;
- sfont->preset_stack_size = 0;
- sfont->preset_stack = FLUID_ARRAY(fluid_preset_t*, sfont->preset_stack_capacity);
- if (!sfont->preset_stack) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- FLUID_FREE(sfont);
- return NULL;
- }
+/* Load sample data for a single sample from the Soundfont file.
+ * Returns FLUID_OK on error, otherwise FLUID_FAILED
+ */
+int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample)
+{
+ int num_samples;
+ unsigned int source_end = sample->source_end;
+
+ /* For uncompressed samples we want to include the 46 zero sample word area following each sample
+ * in the Soundfont. Otherwise samples with loopend > end, which we have decided not to correct, would
+ * be corrected after all in fluid_sample_sanitize_loop */
+ if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))
+ {
+ source_end += 46; /* Length of zero sample word after each sample, according to SF specs */
- for (i = 0; i < sfont->preset_stack_capacity; i++) {
- sfont->preset_stack[i] = FLUID_NEW(fluid_preset_t);
- if (!sfont->preset_stack[i]) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- delete_fluid_defsfont(sfont);
- return NULL;
+ /* Safeguard against Soundfonts that are not quite valid and don't include 46 sample words after the
+ * last sample */
+ if(source_end >= (defsfont->samplesize / sizeof(short)))
+ {
+ source_end = defsfont->samplesize / sizeof(short);
+ }
}
- sfont->preset_stack_size++;
- }
- return sfont;
-}
+ num_samples = fluid_samplecache_load(
+ sfdata, sample->source_start, source_end, sample->sampletype,
+ defsfont->mlock, &sample->data, &sample->data24);
-/*
- * delete_fluid_defsfont
- */
-int delete_fluid_defsfont(fluid_defsfont_t* sfont)
-{
- fluid_list_t *list;
- fluid_defpreset_t* preset;
- fluid_sample_t* sample;
-
- /* Check that no samples are currently used */
- for (list = sfont->sample; list; list = fluid_list_next(list)) {
- sample = (fluid_sample_t*) fluid_list_get(list);
- if (fluid_sample_refcount(sample) != 0) {
- return -1;
- }
- }
-
- if (sfont->filename != NULL) {
- FLUID_FREE(sfont->filename);
- }
-
- for (list = sfont->sample; list; list = fluid_list_next(list)) {
- delete_fluid_sample((fluid_sample_t*) fluid_list_get(list));
- }
-
- if (sfont->sample) {
- delete_fluid_list(sfont->sample);
- }
-
- if (sfont->sampledata != NULL) {
- fluid_cached_sampledata_unload(sfont->sampledata);
- }
-
- while (sfont->preset_stack_size > 0)
- FLUID_FREE(sfont->preset_stack[--sfont->preset_stack_size]);
- FLUID_FREE(sfont->preset_stack);
-
- preset = sfont->preset;
- while (preset != NULL) {
- sfont->preset = preset->next;
- delete_fluid_defpreset(preset);
- preset = sfont->preset;
- }
-
- FLUID_FREE(sfont);
- return FLUID_OK;
+ if(num_samples < 0)
+ {
+ return FLUID_FAILED;
+ }
+
+ if(num_samples == 0)
+ {
+ sample->start = sample->end = 0;
+ sample->loopstart = sample->loopend = 0;
+ return FLUID_OK;
+ }
+
+ /* Ogg Vorbis samples already have loop pointers relative to the invididual decompressed sample,
+ * but SF2 samples are relative to sample chunk start, so they need to be adjusted */
+ if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))
+ {
+ sample->loopstart = sample->source_loopstart - sample->source_start;
+ sample->loopend = sample->source_loopend - sample->source_start;
+ }
+
+ /* As we've just loaded an individual sample into it's own buffer, we need to adjust the start
+ * and end pointers */
+ sample->start = 0;
+ sample->end = num_samples - 1;
+
+ return FLUID_OK;
}
-/*
- * fluid_defsfont_get_name
+/* Loads the sample data for all samples from the Soundfont file. For SF2 files, it loads the data in
+ * one large block. For SF3 files, each compressed sample gets loaded individually.
+ * Returns FLUID_OK on success, otherwise FLUID_FAILED
*/
-char* fluid_defsfont_get_name(fluid_defsfont_t* sfont)
+int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata)
{
- return sfont->filename;
-}
+ fluid_list_t *list;
+ fluid_sample_t *sample;
+ int sf3_file = (sfdata->version.major == 3);
+
+ /* For SF2 files, we load the sample data in one large block */
+ if(!sf3_file)
+ {
+ int read_samples;
+ int num_samples = sfdata->samplesize / sizeof(short);
+
+ read_samples = fluid_samplecache_load(sfdata, 0, num_samples - 1, 0, defsfont->mlock,
+ &defsfont->sampledata, &defsfont->sample24data);
+
+ if(read_samples != num_samples)
+ {
+ FLUID_LOG(FLUID_ERR, "Attempted to read %d words of sample data, but got %d instead",
+ num_samples, read_samples);
+ return FLUID_FAILED;
+ }
+ }
+
+ for(list = defsfont->sample; list; list = fluid_list_next(list))
+ {
+ sample = fluid_list_get(list);
+
+ if(sf3_file)
+ {
+ /* SF3 samples get loaded individually, as most (or all) of them are in Ogg Vorbis format
+ * anyway */
+ if(fluid_defsfont_load_sampledata(defsfont, sfdata, sample) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to load sample '%s'", sample->name);
+ return FLUID_FAILED;
+ }
+
+ fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));
+ }
+ else
+ {
+ /* Data pointers of SF2 samples point to large sample data block loaded above */
+ sample->data = defsfont->sampledata;
+ sample->data24 = defsfont->sample24data;
+ fluid_sample_sanitize_loop(sample, defsfont->samplesize);
+ }
+ fluid_voice_optimize_sample(sample);
+ }
+
+ return FLUID_OK;
+}
/*
* fluid_defsfont_load
*/
-int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file)
+int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *fcbs, const char *file)
{
- SFData* sfdata;
- fluid_list_t *p;
- SFPreset* sfpreset;
- SFSample* sfsample;
- fluid_sample_t* sample;
- fluid_defpreset_t* preset = NULL;
-
- sfont->filename = FLUID_MALLOC(1 + FLUID_STRLEN(file));
- if (sfont->filename == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return FLUID_FAILED;
- }
- FLUID_STRCPY(sfont->filename, file);
+ SFData *sfdata;
+ fluid_list_t *p;
+ SFPreset *sfpreset;
+ SFSample *sfsample;
+ fluid_sample_t *sample;
+ fluid_defpreset_t *defpreset = NULL;
- /* The actual loading is done in the sfont and sffile files */
- sfdata = sfload_file(file);
- if (sfdata == NULL) {
- FLUID_LOG(FLUID_ERR, "Couldn't load soundfont file");
- return FLUID_FAILED;
- }
+ defsfont->filename = FLUID_STRDUP(file);
+
+ if(defsfont->filename == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FLUID_FAILED;
+ }
+
+ defsfont->fcbs = fcbs;
+
+ /* The actual loading is done in the sfont and sffile files */
+ sfdata = fluid_sffile_open(file, fcbs);
+
+ if(sfdata == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Couldn't load soundfont file");
+ return FLUID_FAILED;
+ }
+
+ if(fluid_sffile_parse_presets(sfdata) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Couldn't parse presets from soundfont file");
+ goto err_exit;
+ }
- /* Keep track of the position and size of the sample data because
- it's loaded separately (and might be unoaded/reloaded in future) */
- sfont->samplepos = sfdata->samplepos;
- sfont->samplesize = sfdata->samplesize;
+ /* Keep track of the position and size of the sample data because
+ it's loaded separately (and might be unoaded/reloaded in future) */
+ defsfont->samplepos = sfdata->samplepos;
+ defsfont->samplesize = sfdata->samplesize;
+ defsfont->sample24pos = sfdata->sample24pos;
+ defsfont->sample24size = sfdata->sample24size;
- /* load sample data in one block */
- if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK)
- goto err_exit;
+ /* Create all samples from sample headers */
+ p = sfdata->sample;
- /* Create all the sample headers */
- p = sfdata->sample;
- while (p != NULL) {
- sfsample = (SFSample *) p->data;
+ while(p != NULL)
+ {
+ sfsample = (SFSample *)fluid_list_get(p);
+
+ sample = new_fluid_sample();
+
+ if(sample == NULL)
+ {
+ goto err_exit;
+ }
+
+ if(fluid_sample_import_sfont(sample, sfsample, defsfont) == FLUID_OK)
+ {
+ fluid_defsfont_add_sample(defsfont, sample);
+ }
+ else
+ {
+ delete_fluid_sample(sample);
+ sample = NULL;
+ }
+
+ /* Store reference to FluidSynth sample in SFSample for later IZone fixups */
+ sfsample->fluid_sample = sample;
+
+ p = fluid_list_next(p);
+ }
- sample = new_fluid_sample();
- if (sample == NULL) goto err_exit;
+ /* If dynamic sample loading is disabled, load all samples in the Soundfont */
+ if(!defsfont->dynamic_samples)
+ {
+ if(fluid_defsfont_load_all_sampledata(defsfont, sfdata) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Unable to load all sample data");
+ goto err_exit;
+ }
+ }
- if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK)
- goto err_exit;
+ /* Load all the presets */
+ p = sfdata->preset;
- /* Store reference to FluidSynth sample in SFSample for later IZone fixups */
- sfsample->fluid_sample = sample;
+ while(p != NULL)
+ {
+ sfpreset = (SFPreset *)fluid_list_get(p);
+ defpreset = new_fluid_defpreset(defsfont);
- fluid_defsfont_add_sample(sfont, sample);
- fluid_voice_optimize_sample(sample);
- p = fluid_list_next(p);
- }
+ if(defpreset == NULL)
+ {
+ goto err_exit;
+ }
- /* Load all the presets */
- p = sfdata->preset;
- while (p != NULL) {
- sfpreset = (SFPreset *) p->data;
- preset = new_fluid_defpreset(sfont);
- if (preset == NULL) goto err_exit;
+ if(fluid_defpreset_import_sfont(defpreset, sfpreset, defsfont) != FLUID_OK)
+ {
+ goto err_exit;
+ }
- if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK)
- goto err_exit;
+ if(fluid_defsfont_add_preset(defsfont, defpreset) == FLUID_FAILED)
+ {
+ goto err_exit;
+ }
- fluid_defsfont_add_preset(sfont, preset);
- p = fluid_list_next(p);
- }
- sfont_close (sfdata);
+ p = fluid_list_next(p);
+ }
- return FLUID_OK;
+ fluid_sffile_close(sfdata);
+
+ return FLUID_OK;
err_exit:
- sfont_close (sfdata);
- if (preset != NULL)
- delete_fluid_defpreset(preset);
- return FLUID_FAILED;
+ fluid_sffile_close(sfdata);
+ delete_fluid_defpreset(defpreset);
+ return FLUID_FAILED;
}
/* fluid_defsfont_add_sample
*
* Add a sample to the SoundFont
*/
-int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample)
+int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample)
{
- sfont->sample = fluid_list_append(sfont->sample, sample);
- return FLUID_OK;
+ defsfont->sample = fluid_list_append(defsfont->sample, sample);
+ return FLUID_OK;
}
/* fluid_defsfont_add_preset
*
* Add a preset to the SoundFont
*/
-int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset)
+int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset)
{
- fluid_defpreset_t *cur, *prev;
- if (sfont->preset == NULL) {
- preset->next = NULL;
- sfont->preset = preset;
- } else {
- /* sort them as we go along. very basic sorting trick. */
- cur = sfont->preset;
- prev = NULL;
- while (cur != NULL) {
- if ((preset->bank < cur->bank)
- || ((preset->bank == cur->bank) && (preset->num < cur->num))) {
- if (prev == NULL) {
- preset->next = cur;
- sfont->preset = preset;
- } else {
- preset->next = cur;
- prev->next = preset;
- }
- return FLUID_OK;
- }
- prev = cur;
- cur = cur->next;
- }
- preset->next = NULL;
- prev->next = preset;
- }
- return FLUID_OK;
-}
+ fluid_preset_t *preset;
-/*
- * fluid_defsfont_load_sampledata
- */
-int
-fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont)
-{
- return fluid_cached_sampledata_load(sfont->filename, sfont->samplepos,
- sfont->samplesize, &sfont->sampledata, sfont->mlock);
+ preset = new_fluid_preset(defsfont->sfont,
+ fluid_defpreset_preset_get_name,
+ fluid_defpreset_preset_get_banknum,
+ fluid_defpreset_preset_get_num,
+ fluid_defpreset_preset_noteon,
+ fluid_defpreset_preset_delete);
+
+ if(defsfont->dynamic_samples)
+ {
+ preset->notify = dynamic_samples_preset_notify;
+ }
+
+ if(preset == NULL)
+ {
+ return FLUID_FAILED;
+ }
+
+ fluid_preset_set_data(preset, defpreset);
+
+ defsfont->preset = fluid_list_append(defsfont->preset, preset);
+
+ return FLUID_OK;
}
/*
* fluid_defsfont_get_preset
*/
-fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int num)
+fluid_preset_t *fluid_defsfont_get_preset(fluid_defsfont_t *defsfont, int bank, int num)
{
- fluid_defpreset_t* preset = sfont->preset;
- while (preset != NULL) {
- if ((preset->bank == bank) && ((preset->num == num))) {
- return preset;
- }
- preset = preset->next;
- }
- return NULL;
+ fluid_preset_t *preset;
+ fluid_list_t *list;
+
+ for(list = defsfont->preset; list != NULL; list = fluid_list_next(list))
+ {
+ preset = (fluid_preset_t *)fluid_list_get(list);
+
+ if((fluid_preset_get_banknum(preset) == bank) && (fluid_preset_get_num(preset) == num))
+ {
+ return preset;
+ }
+ }
+
+ return NULL;
}
/*
* fluid_defsfont_iteration_start
*/
-void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont)
+void fluid_defsfont_iteration_start(fluid_defsfont_t *defsfont)
{
- sfont->iter_cur = sfont->preset;
+ defsfont->preset_iter_cur = defsfont->preset;
}
/*
* fluid_defsfont_iteration_next
*/
-int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset)
+fluid_preset_t *fluid_defsfont_iteration_next(fluid_defsfont_t *defsfont)
{
- if (sfont->iter_cur == NULL) {
- return 0;
- }
+ fluid_preset_t *preset = (fluid_preset_t *)fluid_list_get(defsfont->preset_iter_cur);
+
+ defsfont->preset_iter_cur = fluid_list_next(defsfont->preset_iter_cur);
- preset->data = (void*) sfont->iter_cur;
- sfont->iter_cur = fluid_defpreset_next(sfont->iter_cur);
- return 1;
+ return preset;
}
/***************************************************************
@@ -720,75 +609,77 @@ int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* prese
/*
* new_fluid_defpreset
*/
-fluid_defpreset_t*
-new_fluid_defpreset(fluid_defsfont_t* sfont)
+fluid_defpreset_t *
+new_fluid_defpreset(fluid_defsfont_t *defsfont)
{
- fluid_defpreset_t* preset = FLUID_NEW(fluid_defpreset_t);
- if (preset == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- preset->next = NULL;
- preset->sfont = sfont;
- preset->name[0] = 0;
- preset->bank = 0;
- preset->num = 0;
- preset->global_zone = NULL;
- preset->zone = NULL;
- return preset;
+ fluid_defpreset_t *defpreset = FLUID_NEW(fluid_defpreset_t);
+
+ if(defpreset == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ defpreset->next = NULL;
+ defpreset->defsfont = defsfont;
+ defpreset->name[0] = 0;
+ defpreset->bank = 0;
+ defpreset->num = 0;
+ defpreset->global_zone = NULL;
+ defpreset->zone = NULL;
+ return defpreset;
}
/*
* delete_fluid_defpreset
*/
-int
-delete_fluid_defpreset(fluid_defpreset_t* preset)
+void
+delete_fluid_defpreset(fluid_defpreset_t *defpreset)
{
- int err = FLUID_OK;
- fluid_preset_zone_t* zone;
- if (preset->global_zone != NULL) {
- if (delete_fluid_preset_zone(preset->global_zone) != FLUID_OK) {
- err = FLUID_FAILED;
- }
- preset->global_zone = NULL;
- }
- zone = preset->zone;
- while (zone != NULL) {
- preset->zone = zone->next;
- if (delete_fluid_preset_zone(zone) != FLUID_OK) {
- err = FLUID_FAILED;
- }
- zone = preset->zone;
- }
- FLUID_FREE(preset);
- return err;
+ fluid_preset_zone_t *zone;
+
+ fluid_return_if_fail(defpreset != NULL);
+
+ delete_fluid_preset_zone(defpreset->global_zone);
+ defpreset->global_zone = NULL;
+
+ zone = defpreset->zone;
+
+ while(zone != NULL)
+ {
+ defpreset->zone = zone->next;
+ delete_fluid_preset_zone(zone);
+ zone = defpreset->zone;
+ }
+
+ FLUID_FREE(defpreset);
}
int
-fluid_defpreset_get_banknum(fluid_defpreset_t* preset)
+fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset)
{
- return preset->bank;
+ return defpreset->bank;
}
int
-fluid_defpreset_get_num(fluid_defpreset_t* preset)
+fluid_defpreset_get_num(fluid_defpreset_t *defpreset)
{
- return preset->num;
+ return defpreset->num;
}
-char*
-fluid_defpreset_get_name(fluid_defpreset_t* preset)
+const char *
+fluid_defpreset_get_name(fluid_defpreset_t *defpreset)
{
- return preset->name;
+ return defpreset->name;
}
/*
* fluid_defpreset_next
*/
-fluid_defpreset_t*
-fluid_defpreset_next(fluid_defpreset_t* preset)
+fluid_defpreset_t *
+fluid_defpreset_next(fluid_defpreset_t *defpreset)
{
- return preset->next;
+ return defpreset->next;
}
@@ -796,580 +687,759 @@ fluid_defpreset_next(fluid_defpreset_t* preset)
* fluid_defpreset_noteon
*/
int
-fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel)
+fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int chan, int key, int vel)
{
- fluid_preset_zone_t *preset_zone, *global_preset_zone;
- fluid_inst_t* inst;
- fluid_inst_zone_t *inst_zone, *global_inst_zone;
- fluid_sample_t* sample;
- fluid_voice_t* voice;
- fluid_mod_t * mod;
- fluid_mod_t * mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */
- int mod_list_count;
- int i;
+ fluid_preset_zone_t *preset_zone, *global_preset_zone;
+ fluid_inst_t *inst;
+ fluid_inst_zone_t *inst_zone, *global_inst_zone;
+ fluid_voice_zone_t *voice_zone;
+ fluid_list_t *list;
+ fluid_voice_t *voice;
+ fluid_mod_t *mod;
+ fluid_mod_t *mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */
+ int mod_list_count;
+ int i;
- global_preset_zone = fluid_defpreset_get_global_zone(preset);
+ global_preset_zone = fluid_defpreset_get_global_zone(defpreset);
- /* run thru all the zones of this preset */
- preset_zone = fluid_defpreset_get_zone(preset);
- while (preset_zone != NULL) {
+ /* run thru all the zones of this preset */
+ preset_zone = fluid_defpreset_get_zone(defpreset);
- /* check if the note falls into the key and velocity range of this
- preset */
- if (fluid_preset_zone_inside_range(preset_zone, key, vel)) {
+ while(preset_zone != NULL)
+ {
- inst = fluid_preset_zone_get_inst(preset_zone);
- global_inst_zone = fluid_inst_get_global_zone(inst);
+ /* check if the note falls into the key and velocity range of this
+ preset */
+ if(fluid_zone_inside_range(&preset_zone->range, key, vel))
+ {
+
+ inst = fluid_preset_zone_get_inst(preset_zone);
+ global_inst_zone = fluid_inst_get_global_zone(inst);
+
+ /* run thru all the zones of this instrument that could start a voice */
+ for(list = preset_zone->voice_zone; list != NULL; list = fluid_list_next(list))
+ {
+ voice_zone = fluid_list_get(list);
- /* run thru all the zones of this instrument */
- inst_zone = fluid_inst_get_zone(inst);
- while (inst_zone != NULL) {
+ /* check if the instrument zone is ignored and the note falls into
+ the key and velocity range of this instrument zone.
+ An instrument zone must be ignored when its voice is already running
+ played by a legato passage (see fluid_synth_noteon_monopoly_legato()) */
+ if(fluid_zone_inside_range(&voice_zone->range, key, vel))
+ {
+
+ inst_zone = voice_zone->inst_zone;
- /* make sure this instrument zone has a valid sample */
- sample = fluid_inst_zone_get_sample(inst_zone);
- if ((sample == NULL) || fluid_sample_in_rom(sample)) {
- inst_zone = fluid_inst_zone_next(inst_zone);
- continue;
- }
+ /* this is a good zone. allocate a new synthesis process and initialize it */
+ voice = fluid_synth_alloc_voice_LOCAL(synth, inst_zone->sample, chan, key, vel, &voice_zone->range);
- /* check if the note falls into the key and velocity range of this
- instrument */
-
- if (fluid_inst_zone_inside_range(inst_zone, key, vel) && (sample != NULL)) {
-
- /* this is a good zone. allocate a new synthesis process and
- initialize it */
-
- voice = fluid_synth_alloc_voice(synth, sample, chan, key, vel);
- if (voice == NULL) {
- return FLUID_FAILED;
- }
-
-
- /* Instrument level, generators */
-
- for (i = 0; i < GEN_LAST; i++) {
-
- /* SF 2.01 section 9.4 'bullet' 4:
- *
- * A generator in a local instrument zone supersedes a
- * global instrument zone generator. Both cases supersede
- * the default generator -> voice_gen_set */
-
- if (inst_zone->gen[i].flags){
- fluid_voice_gen_set(voice, i, inst_zone->gen[i].val);
-
- } else if ((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags)) {
- fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val);
-
- } else {
- /* The generator has not been defined in this instrument.
- * Do nothing, leave it at the default.
- */
- }
-
- } /* for all generators */
-
- /* global instrument zone, modulators: Put them all into a
- * list. */
-
- mod_list_count = 0;
-
- if (global_inst_zone){
- mod = global_inst_zone->mod;
- while (mod){
- mod_list[mod_list_count++] = mod;
- mod = mod->next;
- }
- }
-
- /* local instrument zone, modulators.
- * Replace modulators with the same definition in the list:
- * SF 2.01 page 69, 'bullet' 8
- */
- mod = inst_zone->mod;
-
- while (mod){
-
- /* 'Identical' modulators will be deleted by setting their
- * list entry to NULL. The list length is known, NULL
- * entries will be ignored later. SF2.01 section 9.5.1
- * page 69, 'bullet' 3 defines 'identical'. */
-
- for (i = 0; i < mod_list_count; i++){
- if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){
- mod_list[i] = NULL;
- }
- }
-
- /* Finally add the new modulator to to the list. */
- mod_list[mod_list_count++] = mod;
- mod = mod->next;
- }
-
- /* Add instrument modulators (global / local) to the voice. */
- for (i = 0; i < mod_list_count; i++){
-
- mod = mod_list[i];
-
- if (mod != NULL){ /* disabled modulators CANNOT be skipped. */
-
- /* Instrument modulators -supersede- existing (default)
- * modulators. SF 2.01 page 69, 'bullet' 6 */
- fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE);
- }
- }
-
- /* Preset level, generators */
-
- for (i = 0; i < GEN_LAST; i++) {
-
- /* SF 2.01 section 8.5 page 58: If some generators are
- * encountered at preset level, they should be ignored */
- if ((i != GEN_STARTADDROFS)
- && (i != GEN_ENDADDROFS)
- && (i != GEN_STARTLOOPADDROFS)
- && (i != GEN_ENDLOOPADDROFS)
- && (i != GEN_STARTADDRCOARSEOFS)
- && (i != GEN_ENDADDRCOARSEOFS)
- && (i != GEN_STARTLOOPADDRCOARSEOFS)
- && (i != GEN_KEYNUM)
- && (i != GEN_VELOCITY)
- && (i != GEN_ENDLOOPADDRCOARSEOFS)
- && (i != GEN_SAMPLEMODE)
- && (i != GEN_EXCLUSIVECLASS)
- && (i != GEN_OVERRIDEROOTKEY)) {
-
- /* SF 2.01 section 9.4 'bullet' 9: A generator in a
- * local preset zone supersedes a global preset zone
- * generator. The effect is -added- to the destination
- * summing node -> voice_gen_incr */
-
- if (preset_zone->gen[i].flags) {
- fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val);
- } else if ((global_preset_zone != NULL) && global_preset_zone->gen[i].flags) {
- fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val);
- } else {
- /* The generator has not been defined in this preset
- * Do nothing, leave it unchanged.
- */
- }
- } /* if available at preset level */
- } /* for all generators */
-
-
- /* Global preset zone, modulators: put them all into a
- * list. */
- mod_list_count = 0;
- if (global_preset_zone){
- mod = global_preset_zone->mod;
- while (mod){
- mod_list[mod_list_count++] = mod;
- mod = mod->next;
- }
- }
-
- /* Process the modulators of the local preset zone. Kick
- * out all identical modulators from the global preset zone
- * (SF 2.01 page 69, second-last bullet) */
-
- mod = preset_zone->mod;
- while (mod){
- for (i = 0; i < mod_list_count; i++){
- if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){
- mod_list[i] = NULL;
- }
- }
-
- /* Finally add the new modulator to the list. */
- mod_list[mod_list_count++] = mod;
- mod = mod->next;
- }
-
- /* Add preset modulators (global / local) to the voice. */
- for (i = 0; i < mod_list_count; i++){
- mod = mod_list[i];
- if ((mod != NULL) && (mod->amount != 0)) { /* disabled modulators can be skipped. */
-
- /* Preset modulators -add- to existing instrument /
- * default modulators. SF2.01 page 70 first bullet on
- * page */
- fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD);
- }
- }
-
- /* add the synthesis process to the synthesis loop. */
- fluid_synth_start_voice(synth, voice);
-
- /* Store the ID of the first voice that was created by this noteon event.
- * Exclusive class may only terminate older voices.
- * That avoids killing voices, which have just been created.
- * (a noteon event can create several voice processes with the same exclusive
- * class - for example when using stereo samples)
- */
- }
-
- inst_zone = fluid_inst_zone_next(inst_zone);
- }
- }
- preset_zone = fluid_preset_zone_next(preset_zone);
- }
-
- return FLUID_OK;
+ if(voice == NULL)
+ {
+ return FLUID_FAILED;
+ }
+
+
+ /* Instrument level, generators */
+
+ for(i = 0; i < GEN_LAST; i++)
+ {
+
+ /* SF 2.01 section 9.4 'bullet' 4:
+ *
+ * A generator in a local instrument zone supersedes a
+ * global instrument zone generator. Both cases supersede
+ * the default generator -> voice_gen_set */
+
+ if(inst_zone->gen[i].flags)
+ {
+ fluid_voice_gen_set(voice, i, inst_zone->gen[i].val);
+
+ }
+ else if((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags))
+ {
+ fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val);
+
+ }
+ else
+ {
+ /* The generator has not been defined in this instrument.
+ * Do nothing, leave it at the default.
+ */
+ }
+
+ } /* for all generators */
+
+ /* global instrument zone, modulators: Put them all into a
+ * list. */
+
+ mod_list_count = 0;
+
+ if(global_inst_zone)
+ {
+ mod = global_inst_zone->mod;
+
+ while(mod)
+ {
+ mod_list[mod_list_count++] = mod;
+ mod = mod->next;
+ }
+ }
+
+ /* local instrument zone, modulators.
+ * Replace modulators with the same definition in the list:
+ * SF 2.01 page 69, 'bullet' 8
+ */
+ mod = inst_zone->mod;
+
+ while(mod)
+ {
+
+ /* 'Identical' modulators will be deleted by setting their
+ * list entry to NULL. The list length is known, NULL
+ * entries will be ignored later. SF2.01 section 9.5.1
+ * page 69, 'bullet' 3 defines 'identical'. */
+
+ for(i = 0; i < mod_list_count; i++)
+ {
+ if(mod_list[i] && fluid_mod_test_identity(mod, mod_list[i]))
+ {
+ mod_list[i] = NULL;
+ }
+ }
+
+ /* Finally add the new modulator to to the list. */
+ mod_list[mod_list_count++] = mod;
+ mod = mod->next;
+ }
+
+ /* Add instrument modulators (global / local) to the voice. */
+ for(i = 0; i < mod_list_count; i++)
+ {
+
+ mod = mod_list[i];
+
+ if(mod != NULL) /* disabled modulators CANNOT be skipped. */
+ {
+
+ /* Instrument modulators -supersede- existing (default)
+ * modulators. SF 2.01 page 69, 'bullet' 6 */
+ fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE);
+ }
+ }
+
+ /* Preset level, generators */
+
+ for(i = 0; i < GEN_LAST; i++)
+ {
+
+ /* SF 2.01 section 8.5 page 58: If some generators are
+ encountered at preset level, they should be ignored.
+ However this check is not necessary when the soundfont
+ loader has ignored invalid preset generators.
+ Actually load_pgen()has ignored these invalid preset
+ generators:
+ GEN_STARTADDROFS, GEN_ENDADDROFS,
+ GEN_STARTLOOPADDROFS, GEN_ENDLOOPADDROFS,
+ GEN_STARTADDRCOARSEOFS,GEN_ENDADDRCOARSEOFS,
+ GEN_STARTLOOPADDRCOARSEOFS,
+ GEN_KEYNUM, GEN_VELOCITY,
+ GEN_ENDLOOPADDRCOARSEOFS,
+ GEN_SAMPLEMODE, GEN_EXCLUSIVECLASS,GEN_OVERRIDEROOTKEY
+ */
+
+ /* SF 2.01 section 9.4 'bullet' 9: A generator in a
+ * local preset zone supersedes a global preset zone
+ * generator. The effect is -added- to the destination
+ * summing node -> voice_gen_incr */
+
+ if(preset_zone->gen[i].flags)
+ {
+ fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val);
+ }
+ else if((global_preset_zone != NULL) && global_preset_zone->gen[i].flags)
+ {
+ fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val);
+ }
+ else
+ {
+ /* The generator has not been defined in this preset
+ * Do nothing, leave it unchanged.
+ */
+ }
+ } /* for all generators */
+
+
+ /* Global preset zone, modulators: put them all into a
+ * list. */
+ mod_list_count = 0;
+
+ if(global_preset_zone)
+ {
+ mod = global_preset_zone->mod;
+
+ while(mod)
+ {
+ mod_list[mod_list_count++] = mod;
+ mod = mod->next;
+ }
+ }
+
+ /* Process the modulators of the local preset zone. Kick
+ * out all identical modulators from the global preset zone
+ * (SF 2.01 page 69, second-last bullet) */
+
+ mod = preset_zone->mod;
+
+ while(mod)
+ {
+ for(i = 0; i < mod_list_count; i++)
+ {
+ if(mod_list[i] && fluid_mod_test_identity(mod, mod_list[i]))
+ {
+ mod_list[i] = NULL;
+ }
+ }
+
+ /* Finally add the new modulator to the list. */
+ mod_list[mod_list_count++] = mod;
+ mod = mod->next;
+ }
+
+ /* Add preset modulators (global / local) to the voice. */
+ for(i = 0; i < mod_list_count; i++)
+ {
+ mod = mod_list[i];
+
+ if((mod != NULL) && (mod->amount != 0)) /* disabled modulators can be skipped. */
+ {
+
+ /* Preset modulators -add- to existing instrument /
+ * default modulators. SF2.01 page 70 first bullet on
+ * page */
+ fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD);
+ }
+ }
+
+ /* add the synthesis process to the synthesis loop. */
+ fluid_synth_start_voice(synth, voice);
+
+ /* Store the ID of the first voice that was created by this noteon event.
+ * Exclusive class may only terminate older voices.
+ * That avoids killing voices, which have just been created.
+ * (a noteon event can create several voice processes with the same exclusive
+ * class - for example when using stereo samples)
+ */
+ }
+
+ }
+ }
+
+ preset_zone = fluid_preset_zone_next(preset_zone);
+ }
+
+ return FLUID_OK;
}
/*
* fluid_defpreset_set_global_zone
*/
int
-fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone)
+fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone)
{
- preset->global_zone = zone;
- return FLUID_OK;
+ defpreset->global_zone = zone;
+ return FLUID_OK;
}
/*
* fluid_defpreset_import_sfont
*/
int
-fluid_defpreset_import_sfont(fluid_defpreset_t* preset,
- SFPreset* sfpreset,
- fluid_defsfont_t* sfont)
+fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset,
+ SFPreset *sfpreset,
+ fluid_defsfont_t *defsfont)
{
- fluid_list_t *p;
- SFZone* sfzone;
- fluid_preset_zone_t* zone;
- int count;
- char zone_name[256];
- if ((sfpreset->name != NULL) && (FLUID_STRLEN(sfpreset->name) > 0)) {
- FLUID_STRCPY(preset->name, sfpreset->name);
- } else {
- FLUID_SPRINTF(preset->name, "Bank%d,Preset%d", sfpreset->bank, sfpreset->prenum);
- }
- preset->bank = sfpreset->bank;
- preset->num = sfpreset->prenum;
- p = sfpreset->zone;
- count = 0;
- while (p != NULL) {
- sfzone = (SFZone *) p->data;
- FLUID_SPRINTF(zone_name, "%s/%d", preset->name, count);
- zone = new_fluid_preset_zone(zone_name);
- if (zone == NULL) {
- return FLUID_FAILED;
- }
- if (fluid_preset_zone_import_sfont(zone, sfzone, sfont) != FLUID_OK) {
- delete_fluid_preset_zone(zone);
- return FLUID_FAILED;
- }
- if ((count == 0) && (fluid_preset_zone_get_inst(zone) == NULL)) {
- fluid_defpreset_set_global_zone(preset, zone);
- } else if (fluid_defpreset_add_zone(preset, zone) != FLUID_OK) {
- return FLUID_FAILED;
- }
- p = fluid_list_next(p);
- count++;
- }
- return FLUID_OK;
+ fluid_list_t *p;
+ SFZone *sfzone;
+ fluid_preset_zone_t *zone;
+ int count;
+ char zone_name[256];
+
+ if(FLUID_STRLEN(sfpreset->name) > 0)
+ {
+ FLUID_STRCPY(defpreset->name, sfpreset->name);
+ }
+ else
+ {
+ FLUID_SNPRINTF(defpreset->name, sizeof(defpreset->name), "Bank%d,Pre%d", sfpreset->bank, sfpreset->prenum);
+ }
+
+ defpreset->bank = sfpreset->bank;
+ defpreset->num = sfpreset->prenum;
+ p = sfpreset->zone;
+ count = 0;
+
+ while(p != NULL)
+ {
+ sfzone = (SFZone *)fluid_list_get(p);
+ FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%d", defpreset->name, count);
+ zone = new_fluid_preset_zone(zone_name);
+
+ if(zone == NULL)
+ {
+ return FLUID_FAILED;
+ }
+
+ if(fluid_preset_zone_import_sfont(zone, sfzone, defsfont) != FLUID_OK)
+ {
+ delete_fluid_preset_zone(zone);
+ return FLUID_FAILED;
+ }
+
+ if((count == 0) && (fluid_preset_zone_get_inst(zone) == NULL))
+ {
+ fluid_defpreset_set_global_zone(defpreset, zone);
+ }
+ else if(fluid_defpreset_add_zone(defpreset, zone) != FLUID_OK)
+ {
+ return FLUID_FAILED;
+ }
+
+ p = fluid_list_next(p);
+ count++;
+ }
+
+ return FLUID_OK;
}
/*
* fluid_defpreset_add_zone
*/
int
-fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone)
+fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone)
{
- if (preset->zone == NULL) {
- zone->next = NULL;
- preset->zone = zone;
- } else {
- zone->next = preset->zone;
- preset->zone = zone;
- }
- return FLUID_OK;
+ if(defpreset->zone == NULL)
+ {
+ zone->next = NULL;
+ defpreset->zone = zone;
+ }
+ else
+ {
+ zone->next = defpreset->zone;
+ defpreset->zone = zone;
+ }
+
+ return FLUID_OK;
}
/*
* fluid_defpreset_get_zone
*/
-fluid_preset_zone_t*
-fluid_defpreset_get_zone(fluid_defpreset_t* preset)
+fluid_preset_zone_t *
+fluid_defpreset_get_zone(fluid_defpreset_t *defpreset)
{
- return preset->zone;
+ return defpreset->zone;
}
/*
* fluid_defpreset_get_global_zone
*/
-fluid_preset_zone_t*
-fluid_defpreset_get_global_zone(fluid_defpreset_t* preset)
+fluid_preset_zone_t *
+fluid_defpreset_get_global_zone(fluid_defpreset_t *defpreset)
{
- return preset->global_zone;
+ return defpreset->global_zone;
}
+/***************************************************************
+ *
+ * PRESET_ZONE
+ */
+
/*
* fluid_preset_zone_next
*/
-fluid_preset_zone_t*
-fluid_preset_zone_next(fluid_preset_zone_t* preset)
+fluid_preset_zone_t *
+fluid_preset_zone_next(fluid_preset_zone_t *zone)
{
- return preset->next;
+ return zone->next;
}
/*
* new_fluid_preset_zone
*/
-fluid_preset_zone_t*
+fluid_preset_zone_t *
new_fluid_preset_zone(char *name)
{
- int size;
- fluid_preset_zone_t* zone = NULL;
- zone = FLUID_NEW(fluid_preset_zone_t);
- if (zone == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- zone->next = NULL;
- size = 1 + FLUID_STRLEN(name);
- zone->name = FLUID_MALLOC(size);
- if (zone->name == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- FLUID_FREE(zone);
- return NULL;
- }
- FLUID_STRCPY(zone->name, name);
- zone->inst = NULL;
- zone->keylo = 0;
- zone->keyhi = 128;
- zone->vello = 0;
- zone->velhi = 128;
-
- /* Flag all generators as unused (default, they will be set when they are found
- * in the sound font).
- * This also sets the generator values to default, but that is of no concern here.*/
- fluid_gen_set_default_values(&zone->gen[0]);
- zone->mod = NULL; /* list of modulators */
- return zone;
-}
+ fluid_preset_zone_t *zone = NULL;
+ zone = FLUID_NEW(fluid_preset_zone_t);
-/***************************************************************
- *
- * PRESET_ZONE
- */
+ if(zone == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ zone->next = NULL;
+ zone->voice_zone = NULL;
+ zone->name = FLUID_STRDUP(name);
+
+ if(zone->name == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ FLUID_FREE(zone);
+ return NULL;
+ }
+
+ zone->inst = NULL;
+ zone->range.keylo = 0;
+ zone->range.keyhi = 128;
+ zone->range.vello = 0;
+ zone->range.velhi = 128;
+ zone->range.ignore = FALSE;
+
+ /* Flag all generators as unused (default, they will be set when they are found
+ * in the sound font).
+ * This also sets the generator values to default, but that is of no concern here.*/
+ fluid_gen_set_default_values(&zone->gen[0]);
+ zone->mod = NULL; /* list of modulators */
+ return zone;
+}
/*
* delete_fluid_preset_zone
*/
-int
-delete_fluid_preset_zone(fluid_preset_zone_t* zone)
+void
+delete_fluid_preset_zone(fluid_preset_zone_t *zone)
+{
+ fluid_mod_t *mod, *tmp;
+ fluid_list_t *list;
+
+ fluid_return_if_fail(zone != NULL);
+
+ mod = zone->mod;
+
+ while(mod) /* delete the modulators */
+ {
+ tmp = mod;
+ mod = mod->next;
+ delete_fluid_mod(tmp);
+ }
+
+ for(list = zone->voice_zone; list != NULL; list = fluid_list_next(list))
+ {
+ FLUID_FREE(fluid_list_get(list));
+ }
+
+ delete_fluid_list(zone->voice_zone);
+
+ FLUID_FREE(zone->name);
+ FLUID_FREE(zone);
+}
+
+static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone)
{
- fluid_mod_t *mod, *tmp;
+ fluid_inst_zone_t *inst_zone;
+ fluid_sample_t *sample;
+ fluid_voice_zone_t *voice_zone;
+ fluid_zone_range_t *irange;
+ fluid_zone_range_t *prange = &preset_zone->range;
+
+ fluid_return_val_if_fail(preset_zone->inst != NULL, FLUID_FAILED);
+
+ inst_zone = fluid_inst_get_zone(preset_zone->inst);
- mod = zone->mod;
- while (mod) /* delete the modulators */
+ while(inst_zone != NULL)
{
- tmp = mod;
- mod = mod->next;
- fluid_mod_delete (tmp);
+
+ /* We only create voice ranges for zones that could actually start a voice,
+ * i.e. that have a sample and don't point to ROM */
+ sample = fluid_inst_zone_get_sample(inst_zone);
+
+ if((sample == NULL) || fluid_sample_in_rom(sample))
+ {
+ inst_zone = fluid_inst_zone_next(inst_zone);
+ continue;
+ }
+
+ voice_zone = FLUID_NEW(fluid_voice_zone_t);
+
+ if(voice_zone == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FLUID_FAILED;
+ }
+
+ voice_zone->inst_zone = inst_zone;
+
+ irange = &inst_zone->range;
+
+ voice_zone->range.keylo = (prange->keylo > irange->keylo) ? prange->keylo : irange->keylo;
+ voice_zone->range.keyhi = (prange->keyhi < irange->keyhi) ? prange->keyhi : irange->keyhi;
+ voice_zone->range.vello = (prange->vello > irange->vello) ? prange->vello : irange->vello;
+ voice_zone->range.velhi = (prange->velhi < irange->velhi) ? prange->velhi : irange->velhi;
+ voice_zone->range.ignore = FALSE;
+
+ preset_zone->voice_zone = fluid_list_append(preset_zone->voice_zone, voice_zone);
+
+ inst_zone = fluid_inst_zone_next(inst_zone);
}
- if (zone->name) FLUID_FREE (zone->name);
- if (zone->inst) delete_fluid_inst (zone->inst);
- FLUID_FREE(zone);
- return FLUID_OK;
+ return FLUID_OK;
}
/*
* fluid_preset_zone_import_sfont
*/
int
-fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont)
+fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
{
- fluid_list_t *r;
- SFGen* sfgen;
- int count;
- for (count = 0, r = sfzone->gen; r != NULL; count++) {
- sfgen = (SFGen *) r->data;
- switch (sfgen->id) {
- case GEN_KEYRANGE:
- zone->keylo = (int) sfgen->amount.range.lo;
- zone->keyhi = (int) sfgen->amount.range.hi;
- break;
- case GEN_VELRANGE:
- zone->vello = (int) sfgen->amount.range.lo;
- zone->velhi = (int) sfgen->amount.range.hi;
- break;
- default:
- /* FIXME: some generators have an unsigne word amount value but i don't know which ones */
- zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
- zone->gen[sfgen->id].flags = GEN_SET;
- break;
- }
- r = fluid_list_next(r);
- }
- if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) {
- zone->inst = (fluid_inst_t*) new_fluid_inst();
- if (zone->inst == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return FLUID_FAILED;
- }
- if (fluid_inst_import_sfont(zone->inst, (SFInst *) sfzone->instsamp->data, sfont) != FLUID_OK) {
- return FLUID_FAILED;
- }
- }
-
- /* Import the modulators (only SF2.1 and higher) */
- for (count = 0, r = sfzone->mod; r != NULL; count++) {
-
- SFMod* mod_src = (SFMod *)r->data;
- fluid_mod_t * mod_dest = fluid_mod_new();
- int type;
-
- if (mod_dest == NULL){
- return FLUID_FAILED;
- }
- mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
-
- /* *** Amount *** */
- mod_dest->amount = mod_src->amount;
-
- /* *** Source *** */
- mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
- mod_dest->flags1 = 0;
-
- /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
- if (mod_src->src & (1<<7)){
- mod_dest->flags1 |= FLUID_MOD_CC;
- } else {
- mod_dest->flags1 |= FLUID_MOD_GC;
- }
-
- /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
- if (mod_src->src & (1<<8)){
- mod_dest->flags1 |= FLUID_MOD_NEGATIVE;
- } else {
- mod_dest->flags1 |= FLUID_MOD_POSITIVE;
- }
-
- /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
- if (mod_src->src & (1<<9)){
- mod_dest->flags1 |= FLUID_MOD_BIPOLAR;
- } else {
- mod_dest->flags1 |= FLUID_MOD_UNIPOLAR;
- }
-
- /* modulator source types: SF2.01 section 8.2.1 page 52 */
- type=(mod_src->src) >> 10;
- type &= 63; /* type is a 6-bit value */
- if (type == 0){
- mod_dest->flags1 |= FLUID_MOD_LINEAR;
- } else if (type == 1){
- mod_dest->flags1 |= FLUID_MOD_CONCAVE;
- } else if (type == 2){
- mod_dest->flags1 |= FLUID_MOD_CONVEX;
- } else if (type == 3){
- mod_dest->flags1 |= FLUID_MOD_SWITCH;
- } else {
- /* This shouldn't happen - unknown type!
- * Deactivate the modulator by setting the amount to 0. */
- mod_dest->amount=0;
- }
-
- /* *** Dest *** */
- mod_dest->dest = mod_src->dest; /* index of controlled generator */
-
- /* *** Amount source *** */
- mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, p.50 */
- mod_dest->flags2 = 0;
-
- /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
- if (mod_src->amtsrc & (1<<7)){
- mod_dest->flags2 |= FLUID_MOD_CC;
- } else {
- mod_dest->flags2 |= FLUID_MOD_GC;
- }
-
- /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
- if (mod_src->amtsrc & (1<<8)){
- mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
- } else {
- mod_dest->flags2 |= FLUID_MOD_POSITIVE;
- }
-
- /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
- if (mod_src->amtsrc & (1<<9)){
- mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
- } else {
- mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
- }
-
- /* modulator source types: SF2.01 section 8.2.1 page 52 */
- type = (mod_src->amtsrc) >> 10;
- type &= 63; /* type is a 6-bit value */
- if (type == 0){
- mod_dest->flags2 |= FLUID_MOD_LINEAR;
- } else if (type == 1){
- mod_dest->flags2 |= FLUID_MOD_CONCAVE;
- } else if (type == 2){
- mod_dest->flags2 |= FLUID_MOD_CONVEX;
- } else if (type == 3){
- mod_dest->flags2 |= FLUID_MOD_SWITCH;
- } else {
- /* This shouldn't happen - unknown type!
- * Deactivate the modulator by setting the amount to 0. */
- mod_dest->amount=0;
- }
-
- /* *** Transform *** */
- /* SF2.01 only uses the 'linear' transform (0).
- * Deactivate the modulator by setting the amount to 0 in any other case.
- */
- if (mod_src->trans !=0){
- mod_dest->amount = 0;
- }
-
- /* Store the new modulator in the zone The order of modulators
- * will make a difference, at least in an instrument context: The
- * second modulator overwrites the first one, if they only differ
- * in amount. */
- if (count == 0){
- zone->mod = mod_dest;
- } else {
- fluid_mod_t * last_mod = zone->mod;
-
- /* Find the end of the list */
- while (last_mod->next != NULL){
- last_mod=last_mod->next;
- }
-
- last_mod->next = mod_dest;
- }
-
- r = fluid_list_next(r);
- } /* foreach modulator */
-
- return FLUID_OK;
+ fluid_list_t *r;
+ SFGen *sfgen;
+ SFInst *sfinst;
+ int count;
+
+ for(count = 0, r = sfzone->gen; r != NULL; count++)
+ {
+ sfgen = (SFGen *)fluid_list_get(r);
+
+ switch(sfgen->id)
+ {
+ case GEN_KEYRANGE:
+ zone->range.keylo = sfgen->amount.range.lo;
+ zone->range.keyhi = sfgen->amount.range.hi;
+ break;
+
+ case GEN_VELRANGE:
+ zone->range.vello = sfgen->amount.range.lo;
+ zone->range.velhi = sfgen->amount.range.hi;
+ break;
+
+ case GEN_ATTENUATION:
+ /* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
+ * preset and instrument level */
+ zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
+ zone->gen[sfgen->id].flags = GEN_SET;
+ break;
+
+ default:
+ /* FIXME: some generators have an unsigne word amount value but i don't know which ones */
+ zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
+ zone->gen[sfgen->id].flags = GEN_SET;
+ break;
+ }
+
+ r = fluid_list_next(r);
+ }
+
+ if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
+ {
+ sfinst = sfzone->instsamp->data;
+
+ zone->inst = find_inst_by_idx(defsfont, sfinst->idx);
+
+ if(zone->inst == NULL)
+ {
+ zone->inst = fluid_inst_import_sfont(zone, sfinst, defsfont);
+ }
+
+ if(zone->inst == NULL)
+ {
+ return FLUID_FAILED;
+ }
+
+ if(fluid_preset_zone_create_voice_zones(zone) == FLUID_FAILED)
+ {
+ return FLUID_FAILED;
+ }
+ }
+
+ /* Import the modulators (only SF2.1 and higher) */
+ for(count = 0, r = sfzone->mod; r != NULL; count++)
+ {
+
+ SFMod *mod_src = (SFMod *)fluid_list_get(r);
+ fluid_mod_t *mod_dest = new_fluid_mod();
+ int type;
+
+ if(mod_dest == NULL)
+ {
+ return FLUID_FAILED;
+ }
+
+ mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
+
+ /* *** Amount *** */
+ mod_dest->amount = mod_src->amount;
+
+ /* *** Source *** */
+ mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
+ mod_dest->flags1 = 0;
+
+ /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
+ if(mod_src->src & (1 << 7))
+ {
+ mod_dest->flags1 |= FLUID_MOD_CC;
+ }
+ else
+ {
+ mod_dest->flags1 |= FLUID_MOD_GC;
+ }
+
+ /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
+ if(mod_src->src & (1 << 8))
+ {
+ mod_dest->flags1 |= FLUID_MOD_NEGATIVE;
+ }
+ else
+ {
+ mod_dest->flags1 |= FLUID_MOD_POSITIVE;
+ }
+
+ /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
+ if(mod_src->src & (1 << 9))
+ {
+ mod_dest->flags1 |= FLUID_MOD_BIPOLAR;
+ }
+ else
+ {
+ mod_dest->flags1 |= FLUID_MOD_UNIPOLAR;
+ }
+
+ /* modulator source types: SF2.01 section 8.2.1 page 52 */
+ type = (mod_src->src) >> 10;
+ type &= 63; /* type is a 6-bit value */
+
+ if(type == 0)
+ {
+ mod_dest->flags1 |= FLUID_MOD_LINEAR;
+ }
+ else if(type == 1)
+ {
+ mod_dest->flags1 |= FLUID_MOD_CONCAVE;
+ }
+ else if(type == 2)
+ {
+ mod_dest->flags1 |= FLUID_MOD_CONVEX;
+ }
+ else if(type == 3)
+ {
+ mod_dest->flags1 |= FLUID_MOD_SWITCH;
+ }
+ else
+ {
+ /* This shouldn't happen - unknown type!
+ * Deactivate the modulator by setting the amount to 0. */
+ mod_dest->amount = 0;
+ }
+
+ /* *** Dest *** */
+ mod_dest->dest = mod_src->dest; /* index of controlled generator */
+
+ /* *** Amount source *** */
+ mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, p.50 */
+ mod_dest->flags2 = 0;
+
+ /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
+ if(mod_src->amtsrc & (1 << 7))
+ {
+ mod_dest->flags2 |= FLUID_MOD_CC;
+ }
+ else
+ {
+ mod_dest->flags2 |= FLUID_MOD_GC;
+ }
+
+ /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
+ if(mod_src->amtsrc & (1 << 8))
+ {
+ mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
+ }
+ else
+ {
+ mod_dest->flags2 |= FLUID_MOD_POSITIVE;
+ }
+
+ /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
+ if(mod_src->amtsrc & (1 << 9))
+ {
+ mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
+ }
+ else
+ {
+ mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
+ }
+
+ /* modulator source types: SF2.01 section 8.2.1 page 52 */
+ type = (mod_src->amtsrc) >> 10;
+ type &= 63; /* type is a 6-bit value */
+
+ if(type == 0)
+ {
+ mod_dest->flags2 |= FLUID_MOD_LINEAR;
+ }
+ else if(type == 1)
+ {
+ mod_dest->flags2 |= FLUID_MOD_CONCAVE;
+ }
+ else if(type == 2)
+ {
+ mod_dest->flags2 |= FLUID_MOD_CONVEX;
+ }
+ else if(type == 3)
+ {
+ mod_dest->flags2 |= FLUID_MOD_SWITCH;
+ }
+ else
+ {
+ /* This shouldn't happen - unknown type!
+ * Deactivate the modulator by setting the amount to 0. */
+ mod_dest->amount = 0;
+ }
+
+ /* *** Transform *** */
+ /* SF2.01 only uses the 'linear' transform (0).
+ * Deactivate the modulator by setting the amount to 0 in any other case.
+ */
+ if(mod_src->trans != 0)
+ {
+ mod_dest->amount = 0;
+ }
+
+ /* Store the new modulator in the zone The order of modulators
+ * will make a difference, at least in an instrument context: The
+ * second modulator overwrites the first one, if they only differ
+ * in amount. */
+ if(count == 0)
+ {
+ zone->mod = mod_dest;
+ }
+ else
+ {
+ fluid_mod_t *last_mod = zone->mod;
+
+ /* Find the end of the list */
+ while(last_mod->next != NULL)
+ {
+ last_mod = last_mod->next;
+ }
+
+ last_mod->next = mod_dest;
+ }
+
+ r = fluid_list_next(r);
+ } /* foreach modulator */
+
+ return FLUID_OK;
}
/*
* fluid_preset_zone_get_inst
*/
-fluid_inst_t*
-fluid_preset_zone_get_inst(fluid_preset_zone_t* zone)
+fluid_inst_t *
+fluid_preset_zone_get_inst(fluid_preset_zone_t *zone)
{
- return zone->inst;
+ return zone->inst;
}
-/*
- * fluid_preset_zone_inside_range
- */
-int
-fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel)
-{
- return ((zone->keylo <= key) &&
- (zone->keyhi >= key) &&
- (zone->vello <= vel) &&
- (zone->velhi >= vel));
-}
/***************************************************************
*
@@ -1379,136 +1449,167 @@ fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel)
/*
* new_fluid_inst
*/
-fluid_inst_t*
+fluid_inst_t *
new_fluid_inst()
{
- fluid_inst_t* inst = FLUID_NEW(fluid_inst_t);
- if (inst == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- inst->name[0] = 0;
- inst->global_zone = NULL;
- inst->zone = NULL;
- return inst;
+ fluid_inst_t *inst = FLUID_NEW(fluid_inst_t);
+
+ if(inst == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ inst->name[0] = 0;
+ inst->global_zone = NULL;
+ inst->zone = NULL;
+ return inst;
}
/*
* delete_fluid_inst
*/
-int
-delete_fluid_inst(fluid_inst_t* inst)
+void
+delete_fluid_inst(fluid_inst_t *inst)
{
- fluid_inst_zone_t* zone;
- int err = FLUID_OK;
- if (inst->global_zone != NULL) {
- if (delete_fluid_inst_zone(inst->global_zone) != FLUID_OK) {
- err = FLUID_FAILED;
- }
+ fluid_inst_zone_t *zone;
+
+ fluid_return_if_fail(inst != NULL);
+
+ delete_fluid_inst_zone(inst->global_zone);
inst->global_zone = NULL;
- }
- zone = inst->zone;
- while (zone != NULL) {
- inst->zone = zone->next;
- if (delete_fluid_inst_zone(zone) != FLUID_OK) {
- err = FLUID_FAILED;
- }
+
zone = inst->zone;
- }
- FLUID_FREE(inst);
- return err;
+
+ while(zone != NULL)
+ {
+ inst->zone = zone->next;
+ delete_fluid_inst_zone(zone);
+ zone = inst->zone;
+ }
+
+ FLUID_FREE(inst);
}
/*
* fluid_inst_set_global_zone
*/
int
-fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone)
+fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone)
{
- inst->global_zone = zone;
- return FLUID_OK;
+ inst->global_zone = zone;
+ return FLUID_OK;
}
/*
* fluid_inst_import_sfont
*/
-int
-fluid_inst_import_sfont(fluid_inst_t* inst, SFInst *sfinst, fluid_defsfont_t* sfont)
+fluid_inst_t *
+fluid_inst_import_sfont(fluid_preset_zone_t *preset_zone, SFInst *sfinst, fluid_defsfont_t *defsfont)
{
- fluid_list_t *p;
- SFZone* sfzone;
- fluid_inst_zone_t* zone;
- char zone_name[256];
- int count;
+ fluid_list_t *p;
+ fluid_inst_t *inst;
+ SFZone *sfzone;
+ fluid_inst_zone_t *inst_zone;
+ char zone_name[256];
+ int count;
- p = sfinst->zone;
- if ((sfinst->name != NULL) && (FLUID_STRLEN(sfinst->name) > 0)) {
- FLUID_STRCPY(inst->name, sfinst->name);
- } else {
- FLUID_STRCPY(inst->name, "<untitled>");
- }
+ inst = (fluid_inst_t *) new_fluid_inst();
- count = 0;
- while (p != NULL) {
+ if(inst == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
- sfzone = (SFZone *) p->data;
- FLUID_SPRINTF(zone_name, "%s/%d", inst->name, count);
+ inst->source_idx = sfinst->idx;
- zone = new_fluid_inst_zone(zone_name);
- if (zone == NULL) {
- return FLUID_FAILED;
- }
+ p = sfinst->zone;
- if (fluid_inst_zone_import_sfont(zone, sfzone, sfont) != FLUID_OK) {
- delete_fluid_inst_zone(zone);
- return FLUID_FAILED;
+ if(FLUID_STRLEN(sfinst->name) > 0)
+ {
+ FLUID_STRCPY(inst->name, sfinst->name);
+ }
+ else
+ {
+ FLUID_STRCPY(inst->name, "<untitled>");
}
- if ((count == 0) && (fluid_inst_zone_get_sample(zone) == NULL)) {
- fluid_inst_set_global_zone(inst, zone);
+ count = 0;
+
+ while(p != NULL)
+ {
+
+ sfzone = (SFZone *)fluid_list_get(p);
+ FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%d", inst->name, count);
+
+ inst_zone = new_fluid_inst_zone(zone_name);
+
+ if(inst_zone == NULL)
+ {
+ return NULL;
+ }
+
+ if(fluid_inst_zone_import_sfont(inst_zone, sfzone, defsfont) != FLUID_OK)
+ {
+ delete_fluid_inst_zone(inst_zone);
+ return NULL;
+ }
+
+ if((count == 0) && (fluid_inst_zone_get_sample(inst_zone) == NULL))
+ {
+ fluid_inst_set_global_zone(inst, inst_zone);
+
+ }
+ else if(fluid_inst_add_zone(inst, inst_zone) != FLUID_OK)
+ {
+ return NULL;
+ }
- } else if (fluid_inst_add_zone(inst, zone) != FLUID_OK) {
- return FLUID_FAILED;
+ p = fluid_list_next(p);
+ count++;
}
- p = fluid_list_next(p);
- count++;
- }
- return FLUID_OK;
+ defsfont->inst = fluid_list_append(defsfont->inst, inst);
+ return inst;
}
/*
* fluid_inst_add_zone
*/
int
-fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone)
+fluid_inst_add_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone)
{
- if (inst->zone == NULL) {
- zone->next = NULL;
- inst->zone = zone;
- } else {
- zone->next = inst->zone;
- inst->zone = zone;
- }
- return FLUID_OK;
+ if(inst->zone == NULL)
+ {
+ zone->next = NULL;
+ inst->zone = zone;
+ }
+ else
+ {
+ zone->next = inst->zone;
+ inst->zone = zone;
+ }
+
+ return FLUID_OK;
}
/*
* fluid_inst_get_zone
*/
-fluid_inst_zone_t*
-fluid_inst_get_zone(fluid_inst_t* inst)
+fluid_inst_zone_t *
+fluid_inst_get_zone(fluid_inst_t *inst)
{
- return inst->zone;
+ return inst->zone;
}
/*
* fluid_inst_get_global_zone
*/
-fluid_inst_zone_t*
-fluid_inst_get_global_zone(fluid_inst_t* inst)
+fluid_inst_zone_t *
+fluid_inst_get_global_zone(fluid_inst_t *inst)
{
- return inst->global_zone;
+ return inst->global_zone;
}
/***************************************************************
@@ -1519,1914 +1620,572 @@ fluid_inst_get_global_zone(fluid_inst_t* inst)
/*
* new_fluid_inst_zone
*/
-fluid_inst_zone_t*
-new_fluid_inst_zone(char* name)
-{
- int size;
- fluid_inst_zone_t* zone = NULL;
- zone = FLUID_NEW(fluid_inst_zone_t);
- if (zone == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- zone->next = NULL;
- size = 1 + FLUID_STRLEN(name);
- zone->name = FLUID_MALLOC(size);
- if (zone->name == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- FLUID_FREE(zone);
- return NULL;
- }
- FLUID_STRCPY(zone->name, name);
- zone->sample = NULL;
- zone->keylo = 0;
- zone->keyhi = 128;
- zone->vello = 0;
- zone->velhi = 128;
-
- /* Flag the generators as unused.
- * This also sets the generator values to default, but they will be overwritten anyway, if used.*/
- fluid_gen_set_default_values(&zone->gen[0]);
- zone->mod=NULL; /* list of modulators */
- return zone;
-}
-
-/*
- * delete_fluid_inst_zone
- */
-int
-delete_fluid_inst_zone(fluid_inst_zone_t* zone)
+fluid_inst_zone_t *
+new_fluid_inst_zone(char *name)
{
- fluid_mod_t *mod, *tmp;
+ fluid_inst_zone_t *zone = NULL;
+ zone = FLUID_NEW(fluid_inst_zone_t);
- mod = zone->mod;
- while (mod) /* delete the modulators */
+ if(zone == NULL)
{
- tmp = mod;
- mod = mod->next;
- fluid_mod_delete (tmp);
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
}
- if (zone->name) FLUID_FREE (zone->name);
- FLUID_FREE(zone);
- return FLUID_OK;
-}
-
-/*
- * fluid_inst_zone_next
- */
-fluid_inst_zone_t*
-fluid_inst_zone_next(fluid_inst_zone_t* zone)
-{
- return zone->next;
-}
-
-/*
- * fluid_inst_zone_import_sfont
- */
-int
-fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont)
-{
- fluid_list_t *r;
- SFGen* sfgen;
- int count;
-
- for (count = 0, r = sfzone->gen; r != NULL; count++) {
- sfgen = (SFGen *) r->data;
- switch (sfgen->id) {
- case GEN_KEYRANGE:
- zone->keylo = (int) sfgen->amount.range.lo;
- zone->keyhi = (int) sfgen->amount.range.hi;
- break;
- case GEN_VELRANGE:
- zone->vello = (int) sfgen->amount.range.lo;
- zone->velhi = (int) sfgen->amount.range.hi;
- break;
- default:
- /* FIXME: some generators have an unsigned word amount value but
- i don't know which ones */
- zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
- zone->gen[sfgen->id].flags = GEN_SET;
- break;
- }
- r = fluid_list_next(r);
- }
-
- /* FIXME */
-/* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */
-/* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */
-/* } */
-
- /* fixup sample pointer */
- if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
- zone->sample = ((SFSample *)(sfzone->instsamp->data))->fluid_sample;
-
- /* Import the modulators (only SF2.1 and higher) */
- for (count = 0, r = sfzone->mod; r != NULL; count++) {
- SFMod* mod_src = (SFMod *) r->data;
- int type;
- fluid_mod_t* mod_dest;
-
- mod_dest = fluid_mod_new();
- if (mod_dest == NULL){
- return FLUID_FAILED;
- }
-
- mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
-
- /* *** Amount *** */
- mod_dest->amount = mod_src->amount;
-
- /* *** Source *** */
- mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
- mod_dest->flags1 = 0;
-
- /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
- if (mod_src->src & (1<<7)){
- mod_dest->flags1 |= FLUID_MOD_CC;
- } else {
- mod_dest->flags1 |= FLUID_MOD_GC;
- }
-
- /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
- if (mod_src->src & (1<<8)){
- mod_dest->flags1 |= FLUID_MOD_NEGATIVE;
- } else {
- mod_dest->flags1 |= FLUID_MOD_POSITIVE;
- }
-
- /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
- if (mod_src->src & (1<<9)){
- mod_dest->flags1 |= FLUID_MOD_BIPOLAR;
- } else {
- mod_dest->flags1 |= FLUID_MOD_UNIPOLAR;
- }
-
- /* modulator source types: SF2.01 section 8.2.1 page 52 */
- type = (mod_src->src) >> 10;
- type &= 63; /* type is a 6-bit value */
- if (type == 0){
- mod_dest->flags1 |= FLUID_MOD_LINEAR;
- } else if (type == 1){
- mod_dest->flags1 |= FLUID_MOD_CONCAVE;
- } else if (type == 2){
- mod_dest->flags1 |= FLUID_MOD_CONVEX;
- } else if (type == 3){
- mod_dest->flags1 |= FLUID_MOD_SWITCH;
- } else {
- /* This shouldn't happen - unknown type!
- * Deactivate the modulator by setting the amount to 0. */
- mod_dest->amount = 0;
- }
-
- /* *** Dest *** */
- mod_dest->dest=mod_src->dest; /* index of controlled generator */
-
- /* *** Amount source *** */
- mod_dest->src2=mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, page 50 */
- mod_dest->flags2 = 0;
-
- /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
- if (mod_src->amtsrc & (1<<7)){
- mod_dest->flags2 |= FLUID_MOD_CC;
- } else {
- mod_dest->flags2 |= FLUID_MOD_GC;
- }
-
- /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
- if (mod_src->amtsrc & (1<<8)){
- mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
- } else {
- mod_dest->flags2 |= FLUID_MOD_POSITIVE;
- }
-
- /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
- if (mod_src->amtsrc & (1<<9)){
- mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
- } else {
- mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
- }
-
- /* modulator source types: SF2.01 section 8.2.1 page 52 */
- type=(mod_src->amtsrc) >> 10;
- type &= 63; /* type is a 6-bit value */
- if (type == 0){
- mod_dest->flags2 |= FLUID_MOD_LINEAR;
- } else if (type == 1){
- mod_dest->flags2 |= FLUID_MOD_CONCAVE;
- } else if (type == 2){
- mod_dest->flags2 |= FLUID_MOD_CONVEX;
- } else if (type == 3){
- mod_dest->flags2 |= FLUID_MOD_SWITCH;
- } else {
- /* This shouldn't happen - unknown type!
- * Deactivate the modulator by setting the amount to 0. */
- mod_dest->amount = 0;
- }
-
- /* *** Transform *** */
- /* SF2.01 only uses the 'linear' transform (0).
- * Deactivate the modulator by setting the amount to 0 in any other case.
- */
- if (mod_src->trans !=0){
- mod_dest->amount = 0;
- }
-
- /* Store the new modulator in the zone
- * The order of modulators will make a difference, at least in an instrument context:
- * The second modulator overwrites the first one, if they only differ in amount. */
- if (count == 0){
- zone->mod=mod_dest;
- } else {
- fluid_mod_t * last_mod=zone->mod;
- /* Find the end of the list */
- while (last_mod->next != NULL){
- last_mod=last_mod->next;
- }
- last_mod->next=mod_dest;
- }
-
- r = fluid_list_next(r);
- } /* foreach modulator */
- return FLUID_OK;
-}
+ zone->next = NULL;
+ zone->name = FLUID_STRDUP(name);
-/*
- * fluid_inst_zone_get_sample
- */
-fluid_sample_t*
-fluid_inst_zone_get_sample(fluid_inst_zone_t* zone)
-{
- return zone->sample;
-}
+ if(zone->name == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ FLUID_FREE(zone);
+ return NULL;
+ }
-/*
- * fluid_inst_zone_inside_range
- */
-int
-fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel)
-{
- return ((zone->keylo <= key) &&
- (zone->keyhi >= key) &&
- (zone->vello <= vel) &&
- (zone->velhi >= vel));
+ zone->sample = NULL;
+ zone->range.keylo = 0;
+ zone->range.keyhi = 128;
+ zone->range.vello = 0;
+ zone->range.velhi = 128;
+ zone->range.ignore = FALSE;
+ /* Flag the generators as unused.
+ * This also sets the generator values to default, but they will be overwritten anyway, if used.*/
+ fluid_gen_set_default_values(&zone->gen[0]);
+ zone->mod = NULL; /* list of modulators */
+ return zone;
}
-/***************************************************************
- *
- * SAMPLE
- */
-
/*
- * new_fluid_sample
+ * delete_fluid_inst_zone
*/
-fluid_sample_t*
-new_fluid_sample()
+void
+delete_fluid_inst_zone(fluid_inst_zone_t *zone)
{
- fluid_sample_t* sample = NULL;
+ fluid_mod_t *mod, *tmp;
- sample = FLUID_NEW(fluid_sample_t);
- if (sample == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
+ fluid_return_if_fail(zone != NULL);
- memset(sample, 0, sizeof(fluid_sample_t));
- sample->valid = 1;
+ mod = zone->mod;
- return sample;
-}
+ while(mod) /* delete the modulators */
+ {
+ tmp = mod;
+ mod = mod->next;
+ delete_fluid_mod(tmp);
+ }
-/*
- * delete_fluid_sample
- */
-int
-delete_fluid_sample(fluid_sample_t* sample)
-{
- FLUID_FREE(sample);
- return FLUID_OK;
+ FLUID_FREE(zone->name);
+ FLUID_FREE(zone);
}
/*
- * fluid_sample_in_rom
+ * fluid_inst_zone_next
*/
-int
-fluid_sample_in_rom(fluid_sample_t* sample)
+fluid_inst_zone_t *
+fluid_inst_zone_next(fluid_inst_zone_t *zone)
{
- return (sample->sampletype & FLUID_SAMPLETYPE_ROM);
+ return zone->next;
}
/*
- * fluid_sample_import_sfont
+ * fluid_inst_zone_import_sfont
*/
int
-fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont)
+fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
{
- FLUID_STRCPY(sample->name, sfsample->name);
- sample->data = sfont->sampledata;
- sample->start = sfsample->start;
- sample->end = sfsample->start + sfsample->end;
- sample->loopstart = sfsample->start + sfsample->loopstart;
- sample->loopend = sfsample->start + sfsample->loopend;
- sample->samplerate = sfsample->samplerate;
- sample->origpitch = sfsample->origpitch;
- sample->pitchadj = sfsample->pitchadj;
- sample->sampletype = sfsample->sampletype;
-
- if (sample->sampletype & FLUID_SAMPLETYPE_ROM) {
- sample->valid = 0;
- FLUID_LOG(FLUID_WARN, "Ignoring sample %s: can't use ROM samples", sample->name);
- }
- if (sample->end - sample->start < 8) {
- sample->valid = 0;
- FLUID_LOG(FLUID_WARN, "Ignoring sample %s: too few sample data points", sample->name);
- } else {
-/* if (sample->loopstart < sample->start + 8) { */
-/* FLUID_LOG(FLUID_WARN, "Fixing sample %s: at least 8 data points required before loop start", sample->name); */
-/* sample->loopstart = sample->start + 8; */
-/* } */
-/* if (sample->loopend > sample->end - 8) { */
-/* FLUID_LOG(FLUID_WARN, "Fixing sample %s: at least 8 data points required after loop end", sample->name); */
-/* sample->loopend = sample->end - 8; */
-/* } */
- }
- return FLUID_OK;
-}
-
+ fluid_list_t *r;
+ SFGen *sfgen;
+ int count;
+ for(count = 0, r = sfzone->gen; r != NULL; count++)
+ {
+ sfgen = (SFGen *)fluid_list_get(r);
+
+ switch(sfgen->id)
+ {
+ case GEN_KEYRANGE:
+ inst_zone->range.keylo = sfgen->amount.range.lo;
+ inst_zone->range.keyhi = sfgen->amount.range.hi;
+ break;
+
+ case GEN_VELRANGE:
+ inst_zone->range.vello = sfgen->amount.range.lo;
+ inst_zone->range.velhi = sfgen->amount.range.hi;
+ break;
+
+ case GEN_ATTENUATION:
+ /* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
+ * preset and instrument level */
+ inst_zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
+ inst_zone->gen[sfgen->id].flags = GEN_SET;
+ break;
+
+ default:
+ /* FIXME: some generators have an unsigned word amount value but
+ i don't know which ones */
+ inst_zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
+ inst_zone->gen[sfgen->id].flags = GEN_SET;
+ break;
+ }
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
+ r = fluid_list_next(r);
+ }
+ /* FIXME */
+ /* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */
+ /* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */
+ /* } */
+ /* fixup sample pointer */
+ if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
+ {
+ inst_zone->sample = ((SFSample *)(sfzone->instsamp->data))->fluid_sample;
+ }
-/*=================================sfload.c========================
- Borrowed from Smurf SoundFont Editor by Josh Green
- =================================================================*/
+ /* Import the modulators (only SF2.1 and higher) */
+ for(count = 0, r = sfzone->mod; r != NULL; count++)
+ {
+ SFMod *mod_src = (SFMod *)fluid_list_get(r);
+ int type;
+ fluid_mod_t *mod_dest;
-/*
- functions for loading data from sfont files, with appropriate byte swapping
- on big endian machines. Sfont IDs are not swapped because the ID read is
- equivalent to the matching ID list in memory regardless of LE/BE machine
-*/
-
-#if FLUID_IS_BIG_ENDIAN
-
-#define READCHUNK(var,fd) G_STMT_START { \
- if (!safe_fread(var, 8, fd)) \
- return(FAIL); \
- ((SFChunk *)(var))->size = GUINT32_FROM_LE(((SFChunk *)(var))->size); \
-} G_STMT_END
-
-#define READD(var,fd) G_STMT_START { \
- unsigned int _temp; \
- if (!safe_fread(&_temp, 4, fd)) \
- return(FAIL); \
- var = GINT32_FROM_LE(_temp); \
-} G_STMT_END
-
-#define READW(var,fd) G_STMT_START { \
- unsigned short _temp; \
- if (!safe_fread(&_temp, 2, fd)) \
- return(FAIL); \
- var = GINT16_FROM_LE(_temp); \
-} G_STMT_END
-
-#else
-
-#define READCHUNK(var,fd) G_STMT_START { \
- if (!safe_fread(var, 8, fd)) \
- return(FAIL); \
- ((SFChunk *)(var))->size = GUINT32_FROM_LE(((SFChunk *)(var))->size); \
-} G_STMT_END
-
-#define READD(var,fd) G_STMT_START { \
- unsigned int _temp; \
- if (!safe_fread(&_temp, 4, fd)) \
- return(FAIL); \
- var = GINT32_FROM_LE(_temp); \
-} G_STMT_END
-
-#define READW(var,fd) G_STMT_START { \
- unsigned short _temp; \
- if (!safe_fread(&_temp, 2, fd)) \
- return(FAIL); \
- var = GINT16_FROM_LE(_temp); \
-} G_STMT_END
-
-#endif
-
-
-#define READID(var,fd) G_STMT_START { \
- if (!safe_fread(var, 4, fd)) \
- return(FAIL); \
-} G_STMT_END
-
-#define READSTR(var,fd) G_STMT_START { \
- if (!safe_fread(var, 20, fd)) \
- return(FAIL); \
- (*var)[20] = '\0'; \
-} G_STMT_END
-
-#define READB(var,fd) G_STMT_START { \
- if (!safe_fread(&var, 1, fd)) \
- return(FAIL); \
-} G_STMT_END
-
-#define FSKIP(size,fd) G_STMT_START { \
- if (!safe_fseek(fd, size, SEEK_CUR)) \
- return(FAIL); \
-} G_STMT_END
-
-#define FSKIPW(fd) G_STMT_START { \
- if (!safe_fseek(fd, 2, SEEK_CUR)) \
- return(FAIL); \
-} G_STMT_END
-
-/* removes and advances a fluid_list_t pointer */
-#define SLADVREM(list, item) G_STMT_START { \
- fluid_list_t *_temp = item; \
- item = fluid_list_next(item); \
- list = fluid_list_remove_link(list, _temp); \
- delete1_fluid_list(_temp); \
-} G_STMT_END
-
-static int chunkid (unsigned int id);
-static int load_body (unsigned int size, SFData * sf, FILE * fd);
-static int read_listchunk (SFChunk * chunk, FILE * fd);
-static int process_info (int size, SFData * sf, FILE * fd);
-static int process_sdta (unsigned int size, SFData * sf, FILE * fd);
-static int pdtahelper (unsigned int expid, unsigned int reclen, SFChunk * chunk,
- int * size, FILE * fd);
-static int process_pdta (int size, SFData * sf, FILE * fd);
-static int load_phdr (int size, SFData * sf, FILE * fd);
-static int load_pbag (int size, SFData * sf, FILE * fd);
-static int load_pmod (int size, SFData * sf, FILE * fd);
-static int load_pgen (int size, SFData * sf, FILE * fd);
-static int load_ihdr (int size, SFData * sf, FILE * fd);
-static int load_ibag (int size, SFData * sf, FILE * fd);
-static int load_imod (int size, SFData * sf, FILE * fd);
-static int load_igen (int size, SFData * sf, FILE * fd);
-static int load_shdr (unsigned int size, SFData * sf, FILE * fd);
-static int fixup_pgen (SFData * sf);
-static int fixup_igen (SFData * sf);
-static int fixup_sample (SFData * sf);
-
-char idlist[] = {
- "RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD"
- "ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdr"
-};
-
-static unsigned int sdtachunk_size;
-
-/* sound font file load functions */
-static int
-chunkid (unsigned int id)
-{
- unsigned int i;
- unsigned int *p;
+ mod_dest = new_fluid_mod();
- p = (unsigned int *) & idlist;
- for (i = 0; i < sizeof (idlist) / sizeof (int); i++, p += 1)
- if (*p == id)
- return (i + 1);
+ if(mod_dest == NULL)
+ {
+ return FLUID_FAILED;
+ }
- return (UNKN_ID);
-}
+ mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
-SFData *
-sfload_file (const char * fname)
-{
- SFData *sf = NULL;
- FILE *fd;
- int fsize = 0;
- int err = FALSE;
+ /* *** Amount *** */
+ mod_dest->amount = mod_src->amount;
- if (!(fd = fopen (fname, "rb")))
- {
- FLUID_LOG (FLUID_ERR, _("Unable to open file \"%s\""), fname);
- return (NULL);
- }
+ /* *** Source *** */
+ mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */
+ mod_dest->flags1 = 0;
- if (!(sf = FLUID_NEW (SFData)))
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- fclose(fd);
- err = TRUE;
- }
+ /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
+ if(mod_src->src & (1 << 7))
+ {
+ mod_dest->flags1 |= FLUID_MOD_CC;
+ }
+ else
+ {
+ mod_dest->flags1 |= FLUID_MOD_GC;
+ }
- if (!err)
- {
- memset (sf, 0, sizeof (SFData)); /* zero sfdata */
- sf->fname = FLUID_STRDUP (fname); /* copy file name */
- sf->sffd = fd;
- }
+ /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
+ if(mod_src->src & (1 << 8))
+ {
+ mod_dest->flags1 |= FLUID_MOD_NEGATIVE;
+ }
+ else
+ {
+ mod_dest->flags1 |= FLUID_MOD_POSITIVE;
+ }
- /* get size of file */
- if (!err && fseek (fd, 0L, SEEK_END) == -1)
- { /* seek to end of file */
- err = TRUE;
- FLUID_LOG (FLUID_ERR, _("Seek to end of file failed"));
- }
- if (!err && (fsize = ftell (fd)) == -1)
- { /* position = size */
- err = TRUE;
- FLUID_LOG (FLUID_ERR, _("Get end of file position failed"));
- }
- if (!err)
- rewind (fd);
+ /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
+ if(mod_src->src & (1 << 9))
+ {
+ mod_dest->flags1 |= FLUID_MOD_BIPOLAR;
+ }
+ else
+ {
+ mod_dest->flags1 |= FLUID_MOD_UNIPOLAR;
+ }
- if (!err && !load_body (fsize, sf, fd))
- err = TRUE; /* load the sfont */
+ /* modulator source types: SF2.01 section 8.2.1 page 52 */
+ type = (mod_src->src) >> 10;
+ type &= 63; /* type is a 6-bit value */
- if (err)
- {
- if (sf)
- sfont_close (sf);
- return (NULL);
- }
+ if(type == 0)
+ {
+ mod_dest->flags1 |= FLUID_MOD_LINEAR;
+ }
+ else if(type == 1)
+ {
+ mod_dest->flags1 |= FLUID_MOD_CONCAVE;
+ }
+ else if(type == 2)
+ {
+ mod_dest->flags1 |= FLUID_MOD_CONVEX;
+ }
+ else if(type == 3)
+ {
+ mod_dest->flags1 |= FLUID_MOD_SWITCH;
+ }
+ else
+ {
+ /* This shouldn't happen - unknown type!
+ * Deactivate the modulator by setting the amount to 0. */
+ mod_dest->amount = 0;
+ }
- return (sf);
-}
+ /* *** Dest *** */
+ mod_dest->dest = mod_src->dest; /* index of controlled generator */
-static int
-load_body (unsigned int size, SFData * sf, FILE * fd)
-{
- SFChunk chunk;
-
- READCHUNK (&chunk, fd); /* load RIFF chunk */
- if (chunkid (chunk.id) != RIFF_ID) { /* error if not RIFF */
- FLUID_LOG (FLUID_ERR, _("Not a RIFF file"));
- return (FAIL);
- }
-
- READID (&chunk.id, fd); /* load file ID */
- if (chunkid (chunk.id) != SFBK_ID) { /* error if not SFBK_ID */
- FLUID_LOG (FLUID_ERR, _("Not a SoundFont file"));
- return (FAIL);
- }
-
- if (chunk.size != size - 8) {
- gerr (ErrCorr, _("SoundFont file size mismatch"));
- return (FAIL);
- }
-
- /* Process INFO block */
- if (!read_listchunk (&chunk, fd))
- return (FAIL);
- if (chunkid (chunk.id) != INFO_ID)
- return (gerr (ErrCorr, _("Invalid ID found when expecting INFO chunk")));
- if (!process_info (chunk.size, sf, fd))
- return (FAIL);
-
- /* Process sample chunk */
- if (!read_listchunk (&chunk, fd))
- return (FAIL);
- if (chunkid (chunk.id) != SDTA_ID)
- return (gerr (ErrCorr,
- _("Invalid ID found when expecting SAMPLE chunk")));
- if (!process_sdta (chunk.size, sf, fd))
- return (FAIL);
-
- /* process HYDRA chunk */
- if (!read_listchunk (&chunk, fd))
- return (FAIL);
- if (chunkid (chunk.id) != PDTA_ID)
- return (gerr (ErrCorr, _("Invalid ID found when expecting HYDRA chunk")));
- if (!process_pdta (chunk.size, sf, fd))
- return (FAIL);
-
- if (!fixup_pgen (sf))
- return (FAIL);
- if (!fixup_igen (sf))
- return (FAIL);
- if (!fixup_sample (sf))
- return (FAIL);
-
- /* sort preset list by bank, preset # */
- sf->preset = fluid_list_sort (sf->preset,
- (fluid_compare_func_t) sfont_preset_compare_func);
-
- return (OK);
-}
+ /* *** Amount source *** */
+ mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, page 50 */
+ mod_dest->flags2 = 0;
-static int
-read_listchunk (SFChunk * chunk, FILE * fd)
-{
- READCHUNK (chunk, fd); /* read list chunk */
- if (chunkid (chunk->id) != LIST_ID) /* error if ! list chunk */
- return (gerr (ErrCorr, _("Invalid chunk id in level 0 parse")));
- READID (&chunk->id, fd); /* read id string */
- chunk->size -= 4;
- return (OK);
-}
+ /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
+ if(mod_src->amtsrc & (1 << 7))
+ {
+ mod_dest->flags2 |= FLUID_MOD_CC;
+ }
+ else
+ {
+ mod_dest->flags2 |= FLUID_MOD_GC;
+ }
-static int
-process_info (int size, SFData * sf, FILE * fd)
-{
- SFChunk chunk;
- unsigned char id;
- char *item;
- unsigned short ver;
-
- while (size > 0)
- {
- READCHUNK (&chunk, fd);
- size -= 8;
-
- id = chunkid (chunk.id);
-
- if (id == IFIL_ID)
- { /* sound font version chunk? */
- if (chunk.size != 4)
- return (gerr (ErrCorr,
- _("Sound font version info chunk has invalid size")));
-
- READW (ver, fd);
- sf->version.major = ver;
- READW (ver, fd);
- sf->version.minor = ver;
-
- if (sf->version.major < 2) {
- FLUID_LOG (FLUID_ERR,
- _("Sound font version is %d.%d which is not"
- " supported, convert to version 2.0x"),
- sf->version.major,
- sf->version.minor);
- return (FAIL);
- }
-
- if (sf->version.major > 2) {
- FLUID_LOG (FLUID_WARN,
- _("Sound font version is %d.%d which is newer than"
- " what this version of FLUID Synth was designed for (v2.0x)"),
- sf->version.major,
- sf->version.minor);
- return (FAIL);
- }
- }
- else if (id == IVER_ID)
- { /* ROM version chunk? */
- if (chunk.size != 4)
- return (gerr (ErrCorr,
- _("ROM version info chunk has invalid size")));
-
- READW (ver, fd);
- sf->romver.major = ver;
- READW (ver, fd);
- sf->romver.minor = ver;
- }
- else if (id != UNKN_ID)
- {
- if ((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536)
- || (chunk.size % 2))
- return (gerr (ErrCorr,
- _("INFO sub chunk %.4s has invalid chunk size"
- " of %d bytes"), &chunk.id, chunk.size));
-
- /* alloc for chunk id and da chunk */
- if (!(item = FLUID_MALLOC (chunk.size + 1)))
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return (FAIL);
- }
-
- /* attach to INFO list, sfont_close will cleanup if FAIL occurs */
- sf->info = fluid_list_append (sf->info, item);
-
- *(unsigned char *) item = id;
- if (!safe_fread (&item[1], chunk.size, fd))
- return (FAIL);
-
- /* force terminate info item (don't forget uint8 info ID) */
- *(item + chunk.size) = '\0';
- }
- else
- return (gerr (ErrCorr, _("Invalid chunk id in INFO chunk")));
- size -= chunk.size;
- }
-
- if (size < 0)
- return (gerr (ErrCorr, _("INFO chunk size mismatch")));
-
- return (OK);
-}
+ /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/
+ if(mod_src->amtsrc & (1 << 8))
+ {
+ mod_dest->flags2 |= FLUID_MOD_NEGATIVE;
+ }
+ else
+ {
+ mod_dest->flags2 |= FLUID_MOD_POSITIVE;
+ }
-static int
-process_sdta (unsigned int size, SFData * sf, FILE * fd)
-{
- SFChunk chunk;
+ /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/
+ if(mod_src->amtsrc & (1 << 9))
+ {
+ mod_dest->flags2 |= FLUID_MOD_BIPOLAR;
+ }
+ else
+ {
+ mod_dest->flags2 |= FLUID_MOD_UNIPOLAR;
+ }
- if (size == 0)
- return (OK); /* no sample data? */
+ /* modulator source types: SF2.01 section 8.2.1 page 52 */
+ type = (mod_src->amtsrc) >> 10;
+ type &= 63; /* type is a 6-bit value */
- /* read sub chunk */
- READCHUNK (&chunk, fd);
- size -= 8;
+ if(type == 0)
+ {
+ mod_dest->flags2 |= FLUID_MOD_LINEAR;
+ }
+ else if(type == 1)
+ {
+ mod_dest->flags2 |= FLUID_MOD_CONCAVE;
+ }
+ else if(type == 2)
+ {
+ mod_dest->flags2 |= FLUID_MOD_CONVEX;
+ }
+ else if(type == 3)
+ {
+ mod_dest->flags2 |= FLUID_MOD_SWITCH;
+ }
+ else
+ {
+ /* This shouldn't happen - unknown type!
+ * Deactivate the modulator by setting the amount to 0. */
+ mod_dest->amount = 0;
+ }
- if (chunkid (chunk.id) != SMPL_ID)
- return (gerr (ErrCorr,
- _("Expected SMPL chunk found invalid id instead")));
+ /* *** Transform *** */
+ /* SF2.01 only uses the 'linear' transform (0).
+ * Deactivate the modulator by setting the amount to 0 in any other case.
+ */
+ if(mod_src->trans != 0)
+ {
+ mod_dest->amount = 0;
+ }
- /* SDTA chunk may also contain sm24 chunk for 24 bit samples
- * (not yet supported), only an error if SMPL chunk size is
- * greater than SDTA. */
- if (chunk.size > size)
- return (gerr (ErrCorr, _("SDTA chunk size mismatch")));
+ /* Store the new modulator in the zone
+ * The order of modulators will make a difference, at least in an instrument context:
+ * The second modulator overwrites the first one, if they only differ in amount. */
+ if(count == 0)
+ {
+ inst_zone->mod = mod_dest;
+ }
+ else
+ {
+ fluid_mod_t *last_mod = inst_zone->mod;
- /* sample data follows */
- sf->samplepos = ftell (fd);
+ /* Find the end of the list */
+ while(last_mod->next != NULL)
+ {
+ last_mod = last_mod->next;
+ }
- /* used in fixup_sample() to check validity of sample headers */
- sdtachunk_size = chunk.size;
- sf->samplesize = chunk.size;
+ last_mod->next = mod_dest;
+ }
- FSKIP (size, fd);
+ r = fluid_list_next(r);
+ } /* foreach modulator */
- return (OK);
+ return FLUID_OK;
}
-static int
-pdtahelper (unsigned int expid, unsigned int reclen, SFChunk * chunk,
- int * size, FILE * fd)
+/*
+ * fluid_inst_zone_get_sample
+ */
+fluid_sample_t *
+fluid_inst_zone_get_sample(fluid_inst_zone_t *zone)
{
- unsigned int id;
- char *expstr;
-
- expstr = CHNKIDSTR (expid); /* in case we need it */
-
- READCHUNK (chunk, fd);
- *size -= 8;
-
- if ((id = chunkid (chunk->id)) != expid)
- return (gerr (ErrCorr, _("Expected"
- " PDTA sub-chunk \"%.4s\" found invalid id instead"), expstr));
-
- if (chunk->size % reclen) /* valid chunk size? */
- return (gerr (ErrCorr,
- _("\"%.4s\" chunk size is not a multiple of %d bytes"), expstr,
- reclen));
- if ((*size -= chunk->size) < 0)
- return (gerr (ErrCorr,
- _("\"%.4s\" chunk size exceeds remaining PDTA chunk size"), expstr));
- return (OK);
+ return zone->sample;
}
-static int
-process_pdta (int size, SFData * sf, FILE * fd)
-{
- SFChunk chunk;
-
- if (!pdtahelper (PHDR_ID, SFPHDRSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_phdr (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (PBAG_ID, SFBAGSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_pbag (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (PMOD_ID, SFMODSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_pmod (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (PGEN_ID, SFGENSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_pgen (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (IHDR_ID, SFIHDRSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_ihdr (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (IBAG_ID, SFBAGSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_ibag (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (IMOD_ID, SFMODSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_imod (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (IGEN_ID, SFGENSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_igen (chunk.size, sf, fd))
- return (FAIL);
-
- if (!pdtahelper (SHDR_ID, SFSHDRSIZE, &chunk, &size, fd))
- return (FAIL);
- if (!load_shdr (chunk.size, sf, fd))
- return (FAIL);
-
- return (OK);
-}
-/* preset header loader */
-static int
-load_phdr (int size, SFData * sf, FILE * fd)
+int
+fluid_zone_inside_range(fluid_zone_range_t *range, int key, int vel)
{
- int i, i2;
- SFPreset *p, *pr = NULL; /* ptr to current & previous preset */
- unsigned short zndx, pzndx = 0;
-
- if (size % SFPHDRSIZE || size == 0)
- return (gerr (ErrCorr, _("Preset header chunk size is invalid")));
-
- i = size / SFPHDRSIZE - 1;
- if (i == 0)
- { /* at least one preset + term record */
- FLUID_LOG (FLUID_WARN, _("File contains no presets"));
- FSKIP (SFPHDRSIZE, fd);
- return (OK);
- }
-
- for (; i > 0; i--)
- { /* load all preset headers */
- p = FLUID_NEW (SFPreset);
- sf->preset = fluid_list_append (sf->preset, p);
- p->zone = NULL; /* In case of failure, sfont_close can cleanup */
- READSTR (&p->name, fd); /* possible read failure ^ */
- READW (p->prenum, fd);
- READW (p->bank, fd);
- READW (zndx, fd);
- READD (p->libr, fd);
- READD (p->genre, fd);
- READD (p->morph, fd);
-
- if (pr)
- { /* not first preset? */
- if (zndx < pzndx)
- return (gerr (ErrCorr, _("Preset header indices not monotonic")));
- i2 = zndx - pzndx;
- while (i2--)
- {
- pr->zone = fluid_list_prepend (pr->zone, NULL);
- }
- }
- else if (zndx > 0) /* 1st preset, warn if ofs >0 */
- FLUID_LOG (FLUID_WARN, _("%d preset zones not referenced, discarding"), zndx);
- pr = p; /* update preset ptr */
- pzndx = zndx;
- }
-
- FSKIP (24, fd);
- READW (zndx, fd); /* Read terminal generator index */
- FSKIP (12, fd);
-
- if (zndx < pzndx)
- return (gerr (ErrCorr, _("Preset header indices not monotonic")));
- i2 = zndx - pzndx;
- while (i2--)
- {
- pr->zone = fluid_list_prepend (pr->zone, NULL);
- }
-
- return (OK);
-}
+ /* ignoreInstrumentZone is set in mono legato playing */
+ int ignore_zone = range->ignore;
-/* preset bag loader */
-static int
-load_pbag (int size, SFData * sf, FILE * fd)
-{
- fluid_list_t *p, *p2;
- SFZone *z, *pz = NULL;
- unsigned short genndx, modndx;
- unsigned short pgenndx = 0, pmodndx = 0;
- unsigned short i;
-
- if (size % SFBAGSIZE || size == 0) /* size is multiple of SFBAGSIZE? */
- return (gerr (ErrCorr, _("Preset bag chunk size is invalid")));
-
- p = sf->preset;
- while (p)
- { /* traverse through presets */
- p2 = ((SFPreset *) (p->data))->zone;
- while (p2)
- { /* traverse preset's zones */
- if ((size -= SFBAGSIZE) < 0)
- return (gerr (ErrCorr, _("Preset bag chunk size mismatch")));
- z = FLUID_NEW (SFZone);
- p2->data = z;
- z->gen = NULL; /* Init gen and mod before possible failure, */
- z->mod = NULL; /* to ensure proper cleanup (sfont_close) */
- READW (genndx, fd); /* possible read failure ^ */
- READW (modndx, fd);
- z->instsamp = NULL;
-
- if (pz)
- { /* if not first zone */
- if (genndx < pgenndx)
- return (gerr (ErrCorr,
- _("Preset bag generator indices not monotonic")));
- if (modndx < pmodndx)
- return (gerr (ErrCorr,
- _("Preset bag modulator indices not monotonic")));
- i = genndx - pgenndx;
- while (i--)
- pz->gen = fluid_list_prepend (pz->gen, NULL);
- i = modndx - pmodndx;
- while (i--)
- pz->mod = fluid_list_prepend (pz->mod, NULL);
- }
- pz = z; /* update previous zone ptr */
- pgenndx = genndx; /* update previous zone gen index */
- pmodndx = modndx; /* update previous zone mod index */
- p2 = fluid_list_next (p2);
- }
- p = fluid_list_next (p);
- }
-
- size -= SFBAGSIZE;
- if (size != 0)
- return (gerr (ErrCorr, _("Preset bag chunk size mismatch")));
-
- READW (genndx, fd);
- READW (modndx, fd);
-
- if (!pz)
- {
- if (genndx > 0)
- FLUID_LOG (FLUID_WARN, _("No preset generators and terminal index not 0"));
- if (modndx > 0)
- FLUID_LOG (FLUID_WARN, _("No preset modulators and terminal index not 0"));
- return (OK);
- }
-
- if (genndx < pgenndx)
- return (gerr (ErrCorr, _("Preset bag generator indices not monotonic")));
- if (modndx < pmodndx)
- return (gerr (ErrCorr, _("Preset bag modulator indices not monotonic")));
- i = genndx - pgenndx;
- while (i--)
- pz->gen = fluid_list_prepend (pz->gen, NULL);
- i = modndx - pmodndx;
- while (i--)
- pz->mod = fluid_list_prepend (pz->mod, NULL);
-
- return (OK);
-}
+ /* Reset the 'ignore' request */
+ range->ignore = FALSE;
-/* preset modulator loader */
-static int
-load_pmod (int size, SFData * sf, FILE * fd)
-{
- fluid_list_t *p, *p2, *p3;
- SFMod *m;
-
- p = sf->preset;
- while (p)
- { /* traverse through all presets */
- p2 = ((SFPreset *) (p->data))->zone;
- while (p2)
- { /* traverse this preset's zones */
- p3 = ((SFZone *) (p2->data))->mod;
- while (p3)
- { /* load zone's modulators */
- if ((size -= SFMODSIZE) < 0)
- return (gerr (ErrCorr,
- _("Preset modulator chunk size mismatch")));
- m = FLUID_NEW (SFMod);
- p3->data = m;
- READW (m->src, fd);
- READW (m->dest, fd);
- READW (m->amount, fd);
- READW (m->amtsrc, fd);
- READW (m->trans, fd);
- p3 = fluid_list_next (p3);
- }
- p2 = fluid_list_next (p2);
- }
- p = fluid_list_next (p);
- }
-
- /*
- If there isn't even a terminal record
- Hmmm, the specs say there should be one, but..
- */
- if (size == 0)
- return (OK);
-
- size -= SFMODSIZE;
- if (size != 0)
- return (gerr (ErrCorr, _("Preset modulator chunk size mismatch")));
- FSKIP (SFMODSIZE, fd); /* terminal mod */
-
- return (OK);
+ return !ignore_zone && ((range->keylo <= key) &&
+ (range->keyhi >= key) &&
+ (range->vello <= vel) &&
+ (range->velhi >= vel));
}
-/* -------------------------------------------------------------------
- * preset generator loader
- * generator (per preset) loading rules:
- * Zones with no generators or modulators shall be annihilated
- * Global zone must be 1st zone, discard additional ones (instrumentless zones)
+/***************************************************************
*
- * generator (per zone) loading rules (in order of decreasing precedence):
- * KeyRange is 1st in list (if exists), else discard
- * if a VelRange exists only preceded by a KeyRange, else discard
- * if a generator follows an instrument discard it
- * if a duplicate generator exists replace previous one
- * ------------------------------------------------------------------- */
-static int
-load_pgen (int size, SFData * sf, FILE * fd)
-{
- fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
- SFZone *z;
- SFGen *g;
- SFGenAmount genval;
- unsigned short genid;
- int level, skip, drop, gzone, discarded;
-
- p = sf->preset;
- while (p)
- { /* traverse through all presets */
- gzone = FALSE;
- discarded = FALSE;
- p2 = ((SFPreset *) (p->data))->zone;
- if (p2)
- hz = &p2;
- while (p2)
- { /* traverse preset's zones */
- level = 0;
- z = (SFZone *) (p2->data);
- p3 = z->gen;
- while (p3)
- { /* load zone's generators */
- dup = NULL;
- skip = FALSE;
- drop = FALSE;
- if ((size -= SFGENSIZE) < 0)
- return (gerr (ErrCorr,
- _("Preset generator chunk size mismatch")));
-
- READW (genid, fd);
-
- if (genid == Gen_KeyRange)
- { /* nothing precedes */
- if (level == 0)
- {
- level = 1;
- READB (genval.range.lo, fd);
- READB (genval.range.hi, fd);
- }
- else
- skip = TRUE;
- }
- else if (genid == Gen_VelRange)
- { /* only KeyRange precedes */
- if (level <= 1)
- {
- level = 2;
- READB (genval.range.lo, fd);
- READB (genval.range.hi, fd);
- }
- else
- skip = TRUE;
- }
- else if (genid == Gen_Instrument)
- { /* inst is last gen */
- level = 3;
- READW (genval.uword, fd);
- ((SFZone *) (p2->data))->instsamp = GINT_TO_POINTER (genval.uword + 1);
- break; /* break out of generator loop */
- }
- else
- {
- level = 2;
- if (gen_validp (genid))
- { /* generator valid? */
- READW (genval.sword, fd);
- dup = gen_inlist (genid, z->gen);
- }
- else
- skip = TRUE;
- }
-
- if (!skip)
- {
- if (!dup)
- { /* if gen ! dup alloc new */
- g = FLUID_NEW (SFGen);
- p3->data = g;
- g->id = genid;
- }
- else
- {
- g = (SFGen *) (dup->data); /* ptr to orig gen */
- drop = TRUE;
- }
- g->amount = genval;
- }
- else
- { /* Skip this generator */
- discarded = TRUE;
- drop = TRUE;
- FSKIPW (fd);
- }
-
- if (!drop)
- p3 = fluid_list_next (p3); /* next gen */
- else
- SLADVREM (z->gen, p3); /* drop place holder */
-
- } /* generator loop */
-
- if (level == 3)
- SLADVREM (z->gen, p3); /* zone has inst? */
- else
- { /* congratulations its a global zone */
- if (!gzone)
- { /* Prior global zones? */
- gzone = TRUE;
-
- /* if global zone is not 1st zone, relocate */
- if (*hz != p2)
- {
- void* save = p2->data;
- FLUID_LOG (FLUID_WARN,
- _("Preset \"%s\": Global zone is not first zone"),
- ((SFPreset *) (p->data))->name);
- SLADVREM (*hz, p2);
- *hz = fluid_list_prepend (*hz, save);
- continue;
- }
- }
- else
- { /* previous global zone exists, discard */
- FLUID_LOG (FLUID_WARN,
- _("Preset \"%s\": Discarding invalid global zone"),
- ((SFPreset *) (p->data))->name);
- sfont_zone_delete (sf, hz, (SFZone *) (p2->data));
- }
- }
-
- while (p3)
- { /* Kill any zones following an instrument */
- discarded = TRUE;
- if ((size -= SFGENSIZE) < 0)
- return (gerr (ErrCorr,
- _("Preset generator chunk size mismatch")));
- FSKIP (SFGENSIZE, fd);
- SLADVREM (z->gen, p3);
- }
-
- p2 = fluid_list_next (p2); /* next zone */
- }
- if (discarded)
- FLUID_LOG(FLUID_WARN,
- _("Preset \"%s\": Some invalid generators were discarded"),
- ((SFPreset *) (p->data))->name);
- p = fluid_list_next (p);
- }
-
- /* in case there isn't a terminal record */
- if (size == 0)
- return (OK);
-
- size -= SFGENSIZE;
- if (size != 0)
- return (gerr (ErrCorr, _("Preset generator chunk size mismatch")));
- FSKIP (SFGENSIZE, fd); /* terminal gen */
-
- return (OK);
-}
-
-/* instrument header loader */
-static int
-load_ihdr (int size, SFData * sf, FILE * fd)
-{
- int i, i2;
- SFInst *p, *pr = NULL; /* ptr to current & previous instrument */
- unsigned short zndx, pzndx = 0;
-
- if (size % SFIHDRSIZE || size == 0) /* chunk size is valid? */
- return (gerr (ErrCorr, _("Instrument header has invalid size")));
-
- size = size / SFIHDRSIZE - 1;
- if (size == 0)
- { /* at least one preset + term record */
- FLUID_LOG (FLUID_WARN, _("File contains no instruments"));
- FSKIP (SFIHDRSIZE, fd);
- return (OK);
- }
-
- for (i = 0; i < size; i++)
- { /* load all instrument headers */
- p = FLUID_NEW (SFInst);
- sf->inst = fluid_list_append (sf->inst, p);
- p->zone = NULL; /* For proper cleanup if fail (sfont_close) */
- READSTR (&p->name, fd); /* Possible read failure ^ */
- READW (zndx, fd);
-
- if (pr)
- { /* not first instrument? */
- if (zndx < pzndx)
- return (gerr (ErrCorr,
- _("Instrument header indices not monotonic")));
- i2 = zndx - pzndx;
- while (i2--)
- pr->zone = fluid_list_prepend (pr->zone, NULL);
- }
- else if (zndx > 0) /* 1st inst, warn if ofs >0 */
- FLUID_LOG (FLUID_WARN, _("%d instrument zones not referenced, discarding"),
- zndx);
- pzndx = zndx;
- pr = p; /* update instrument ptr */
- }
-
- FSKIP (20, fd);
- READW (zndx, fd);
-
- if (zndx < pzndx)
- return (gerr (ErrCorr, _("Instrument header indices not monotonic")));
- i2 = zndx - pzndx;
- while (i2--)
- pr->zone = fluid_list_prepend (pr->zone, NULL);
-
- return (OK);
-}
+ * SAMPLE
+ */
-/* instrument bag loader */
-static int
-load_ibag (int size, SFData * sf, FILE * fd)
+/*
+ * fluid_sample_in_rom
+ */
+int
+fluid_sample_in_rom(fluid_sample_t *sample)
{
- fluid_list_t *p, *p2;
- SFZone *z, *pz = NULL;
- unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0;
- int i;
-
- if (size % SFBAGSIZE || size == 0) /* size is multiple of SFBAGSIZE? */
- return (gerr (ErrCorr, _("Instrument bag chunk size is invalid")));
-
- p = sf->inst;
- while (p)
- { /* traverse through inst */
- p2 = ((SFInst *) (p->data))->zone;
- while (p2)
- { /* load this inst's zones */
- if ((size -= SFBAGSIZE) < 0)
- return (gerr (ErrCorr, _("Instrument bag chunk size mismatch")));
- z = FLUID_NEW (SFZone);
- p2->data = z;
- z->gen = NULL; /* In case of failure, */
- z->mod = NULL; /* sfont_close can clean up */
- READW (genndx, fd); /* READW = possible read failure */
- READW (modndx, fd);
- z->instsamp = NULL;
-
- if (pz)
- { /* if not first zone */
- if (genndx < pgenndx)
- return (gerr (ErrCorr,
- _("Instrument generator indices not monotonic")));
- if (modndx < pmodndx)
- return (gerr (ErrCorr,
- _("Instrument modulator indices not monotonic")));
- i = genndx - pgenndx;
- while (i--)
- pz->gen = fluid_list_prepend (pz->gen, NULL);
- i = modndx - pmodndx;
- while (i--)
- pz->mod = fluid_list_prepend (pz->mod, NULL);
- }
- pz = z; /* update previous zone ptr */
- pgenndx = genndx;
- pmodndx = modndx;
- p2 = fluid_list_next (p2);
- }
- p = fluid_list_next (p);
- }
-
- size -= SFBAGSIZE;
- if (size != 0)
- return (gerr (ErrCorr, _("Instrument chunk size mismatch")));
-
- READW (genndx, fd);
- READW (modndx, fd);
-
- if (!pz)
- { /* in case that all are no zoners */
- if (genndx > 0)
- FLUID_LOG (FLUID_WARN,
- _("No instrument generators and terminal index not 0"));
- if (modndx > 0)
- FLUID_LOG (FLUID_WARN,
- _("No instrument modulators and terminal index not 0"));
- return (OK);
- }
-
- if (genndx < pgenndx)
- return (gerr (ErrCorr, _("Instrument generator indices not monotonic")));
- if (modndx < pmodndx)
- return (gerr (ErrCorr, _("Instrument modulator indices not monotonic")));
- i = genndx - pgenndx;
- while (i--)
- pz->gen = fluid_list_prepend (pz->gen, NULL);
- i = modndx - pmodndx;
- while (i--)
- pz->mod = fluid_list_prepend (pz->mod, NULL);
-
- return (OK);
+ return (sample->sampletype & FLUID_SAMPLETYPE_ROM);
}
-/* instrument modulator loader */
-static int
-load_imod (int size, SFData * sf, FILE * fd)
-{
- fluid_list_t *p, *p2, *p3;
- SFMod *m;
-
- p = sf->inst;
- while (p)
- { /* traverse through all inst */
- p2 = ((SFInst *) (p->data))->zone;
- while (p2)
- { /* traverse this inst's zones */
- p3 = ((SFZone *) (p2->data))->mod;
- while (p3)
- { /* load zone's modulators */
- if ((size -= SFMODSIZE) < 0)
- return (gerr (ErrCorr,
- _("Instrument modulator chunk size mismatch")));
- m = FLUID_NEW (SFMod);
- p3->data = m;
- READW (m->src, fd);
- READW (m->dest, fd);
- READW (m->amount, fd);
- READW (m->amtsrc, fd);
- READW (m->trans, fd);
- p3 = fluid_list_next (p3);
- }
- p2 = fluid_list_next (p2);
- }
- p = fluid_list_next (p);
- }
-
- /*
- If there isn't even a terminal record
- Hmmm, the specs say there should be one, but..
- */
- if (size == 0)
- return (OK);
-
- size -= SFMODSIZE;
- if (size != 0)
- return (gerr (ErrCorr, _("Instrument modulator chunk size mismatch")));
- FSKIP (SFMODSIZE, fd); /* terminal mod */
-
- return (OK);
-}
-/* load instrument generators (see load_pgen for loading rules) */
-static int
-load_igen (int size, SFData * sf, FILE * fd)
+/*
+ * fluid_sample_import_sfont
+ */
+int
+fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont)
{
- fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
- SFZone *z;
- SFGen *g;
- SFGenAmount genval;
- unsigned short genid;
- int level, skip, drop, gzone, discarded;
-
- p = sf->inst;
- while (p)
- { /* traverse through all instruments */
- gzone = FALSE;
- discarded = FALSE;
- p2 = ((SFInst *) (p->data))->zone;
- if (p2)
- hz = &p2;
- while (p2)
- { /* traverse this instrument's zones */
- level = 0;
- z = (SFZone *) (p2->data);
- p3 = z->gen;
- while (p3)
- { /* load zone's generators */
- dup = NULL;
- skip = FALSE;
- drop = FALSE;
- if ((size -= SFGENSIZE) < 0)
- return (gerr (ErrCorr, _("IGEN chunk size mismatch")));
-
- READW (genid, fd);
-
- if (genid == Gen_KeyRange)
- { /* nothing precedes */
- if (level == 0)
- {
- level = 1;
- READB (genval.range.lo, fd);
- READB (genval.range.hi, fd);
- }
- else
- skip = TRUE;
- }
- else if (genid == Gen_VelRange)
- { /* only KeyRange precedes */
- if (level <= 1)
- {
- level = 2;
- READB (genval.range.lo, fd);
- READB (genval.range.hi, fd);
- }
- else
- skip = TRUE;
- }
- else if (genid == Gen_SampleId)
- { /* sample is last gen */
- level = 3;
- READW (genval.uword, fd);
- ((SFZone *) (p2->data))->instsamp = GINT_TO_POINTER (genval.uword + 1);
- break; /* break out of generator loop */
- }
- else
- {
- level = 2;
- if (gen_valid (genid))
- { /* gen valid? */
- READW (genval.sword, fd);
- dup = gen_inlist (genid, z->gen);
- }
- else
- skip = TRUE;
- }
-
- if (!skip)
- {
- if (!dup)
- { /* if gen ! dup alloc new */
- g = FLUID_NEW (SFGen);
- p3->data = g;
- g->id = genid;
- }
- else
- {
- g = (SFGen *) (dup->data);
- drop = TRUE;
- }
- g->amount = genval;
- }
- else
- { /* skip this generator */
- discarded = TRUE;
- drop = TRUE;
- FSKIPW (fd);
- }
-
- if (!drop)
- p3 = fluid_list_next (p3); /* next gen */
- else
- SLADVREM (z->gen, p3);
-
- } /* generator loop */
-
- if (level == 3)
- SLADVREM (z->gen, p3); /* zone has sample? */
- else
- { /* its a global zone */
- if (!gzone)
- {
- gzone = TRUE;
-
- /* if global zone is not 1st zone, relocate */
- if (*hz != p2)
- {
- void* save = p2->data;
- FLUID_LOG (FLUID_WARN,
- _("Instrument \"%s\": Global zone is not first zone"),
- ((SFPreset *) (p->data))->name);
- SLADVREM (*hz, p2);
- *hz = fluid_list_prepend (*hz, save);
- continue;
- }
- }
- else
- { /* previous global zone exists, discard */
- FLUID_LOG (FLUID_WARN,
- _("Instrument \"%s\": Discarding invalid global zone"),
- ((SFInst *) (p->data))->name);
- sfont_zone_delete (sf, hz, (SFZone *) (p2->data));
- }
- }
-
- while (p3)
- { /* Kill any zones following a sample */
- discarded = TRUE;
- if ((size -= SFGENSIZE) < 0)
- return (gerr (ErrCorr,
- _("Instrument generator chunk size mismatch")));
- FSKIP (SFGENSIZE, fd);
- SLADVREM (z->gen, p3);
- }
-
- p2 = fluid_list_next (p2); /* next zone */
- }
- if (discarded)
- FLUID_LOG(FLUID_WARN,
- _("Instrument \"%s\": Some invalid generators were discarded"),
- ((SFInst *) (p->data))->name);
- p = fluid_list_next (p);
- }
-
- /* for those non-terminal record cases, grr! */
- if (size == 0)
- return (OK);
-
- size -= SFGENSIZE;
- if (size != 0)
- return (gerr (ErrCorr, _("IGEN chunk size mismatch")));
- FSKIP (SFGENSIZE, fd); /* terminal gen */
-
- return (OK);
-}
+ FLUID_STRCPY(sample->name, sfsample->name);
-/* sample header loader */
-static int
-load_shdr (unsigned int size, SFData * sf, FILE * fd)
-{
- unsigned int i;
- SFSample *p;
+ sample->source_start = sfsample->start;
+ sample->source_end = (sfsample->end > 0) ? sfsample->end - 1 : 0; /* marks last sample, contrary to SF spec. */
+ sample->source_loopstart = sfsample->loopstart;
+ sample->source_loopend = sfsample->loopend;
- if (size % SFSHDRSIZE || size == 0) /* size is multiple of SHDR size? */
- return (gerr (ErrCorr, _("Sample header has invalid size")));
+ sample->start = sample->source_start;
+ sample->end = sample->source_end;
+ sample->loopstart = sample->source_loopstart;
+ sample->loopend = sample->source_loopend;
+ sample->samplerate = sfsample->samplerate;
+ sample->origpitch = sfsample->origpitch;
+ sample->pitchadj = sfsample->pitchadj;
+ sample->sampletype = sfsample->sampletype;
- size = size / SFSHDRSIZE - 1;
- if (size == 0)
- { /* at least one sample + term record? */
- FLUID_LOG (FLUID_WARN, _("File contains no samples"));
- FSKIP (SFSHDRSIZE, fd);
- return (OK);
+ if(defsfont->dynamic_samples)
+ {
+ sample->notify = dynamic_samples_sample_notify;
}
- /* load all sample headers */
- for (i = 0; i < size; i++)
+ if(fluid_sample_validate(sample, defsfont->samplesize) == FLUID_FAILED)
{
- p = FLUID_NEW (SFSample);
- sf->sample = fluid_list_append (sf->sample, p);
- READSTR (&p->name, fd);
- READD (p->start, fd);
- READD (p->end, fd); /* - end, loopstart and loopend */
- READD (p->loopstart, fd); /* - will be checked and turned into */
- READD (p->loopend, fd); /* - offsets in fixup_sample() */
- READD (p->samplerate, fd);
- READB (p->origpitch, fd);
- READB (p->pitchadj, fd);
- FSKIPW (fd); /* skip sample link */
- READW (p->sampletype, fd);
- p->samfile = 0;
+ return FLUID_FAILED;
}
- FSKIP (SFSHDRSIZE, fd); /* skip terminal shdr */
-
- return (OK);
+ return FLUID_OK;
}
-/* "fixup" (inst # -> inst ptr) instrument references in preset list */
-static int
-fixup_pgen (SFData * sf)
+/* Called if a sample is no longer used by a voice. Used by dynamic sample loading
+ * to unload a sample that is not used by any loaded presets anymore but couldn't
+ * be unloaded straight away because it was still in use by a voice. */
+static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason)
{
- fluid_list_t *p, *p2, *p3;
- SFZone *z;
- int i;
-
- p = sf->preset;
- while (p)
- {
- p2 = ((SFPreset *) (p->data))->zone;
- while (p2)
- { /* traverse this preset's zones */
- z = (SFZone *) (p2->data);
- if ((i = GPOINTER_TO_INT (z->instsamp)))
- { /* load instrument # */
- p3 = fluid_list_nth (sf->inst, i - 1);
- if (!p3)
- return (gerr (ErrCorr,
- _("Preset %03d %03d: Invalid instrument reference"),
- ((SFPreset *) (p->data))->bank,
- ((SFPreset *) (p->data))->prenum));
- z->instsamp = p3;
- }
- else
- z->instsamp = NULL;
- p2 = fluid_list_next (p2);
- }
- p = fluid_list_next (p);
- }
-
- return (OK);
-}
+ if(reason == FLUID_SAMPLE_DONE && sample->preset_count == 0)
+ {
+ unload_sample(sample);
+ }
-/* "fixup" (sample # -> sample ptr) sample references in instrument list */
-static int
-fixup_igen (SFData * sf)
-{
- fluid_list_t *p, *p2, *p3;
- SFZone *z;
- int i;
-
- p = sf->inst;
- while (p)
- {
- p2 = ((SFInst *) (p->data))->zone;
- while (p2)
- { /* traverse instrument's zones */
- z = (SFZone *) (p2->data);
- if ((i = GPOINTER_TO_INT (z->instsamp)))
- { /* load sample # */
- p3 = fluid_list_nth (sf->sample, i - 1);
- if (!p3)
- return (gerr (ErrCorr,
- _("Instrument \"%s\": Invalid sample reference"),
- ((SFInst *) (p->data))->name));
- z->instsamp = p3;
- }
- p2 = fluid_list_next (p2);
- }
- p = fluid_list_next (p);
- }
-
- return (OK);
+ return FLUID_OK;
}
-/* convert sample end, loopstart and loopend to offsets and check if valid */
-static int
-fixup_sample (SFData * sf)
+/* Called if a preset has been selected for or unselected from a channel. Used by
+ * dynamic sample loading to load and unload samples on demand. */
+static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan)
{
- fluid_list_t *p;
- SFSample *sam;
-
- p = sf->sample;
- while (p)
- {
- sam = (SFSample *) (p->data);
-
- /* if sample is not a ROM sample and end is over the sample data chunk
- or sam start is greater than 4 less than the end (at least 4 samples) */
- if ((!(sam->sampletype & FLUID_SAMPLETYPE_ROM)
- && sam->end > sdtachunk_size) || sam->start > (sam->end - 4))
- {
- FLUID_LOG (FLUID_WARN, _("Sample '%s' start/end file positions are invalid,"
- " disabling and will not be saved"), sam->name);
-
- /* disable sample by setting all sample markers to 0 */
- sam->start = sam->end = sam->loopstart = sam->loopend = 0;
-
- return (OK);
- }
- else if (sam->loopend > sam->end || sam->loopstart >= sam->loopend
- || sam->loopstart <= sam->start)
- { /* loop is fowled?? (cluck cluck :) */
- /* can pad loop by 8 samples and ensure at least 4 for loop (2*8+4) */
- if ((sam->end - sam->start) >= 20)
- {
- sam->loopstart = sam->start + 8;
- sam->loopend = sam->end - 8;
- }
- else
- { /* loop is fowled, sample is tiny (can't pad 8 samples) */
- sam->loopstart = sam->start + 1;
- sam->loopend = sam->end - 1;
- }
- }
-
- /* convert sample end, loopstart, loopend to offsets from sam->start */
- sam->end -= sam->start + 1; /* marks last sample, contrary to SF spec. */
- sam->loopstart -= sam->start;
- sam->loopend -= sam->start;
-
- p = fluid_list_next (p);
- }
-
- return (OK);
-}
+ fluid_defsfont_t *defsfont;
-/*=================================sfont.c========================
- Smurf SoundFont Editor
- ================================================================*/
-
-
-/* optimum chunk area sizes (could be more optimum) */
-#define PRESET_CHUNK_OPTIMUM_AREA 256
-#define INST_CHUNK_OPTIMUM_AREA 256
-#define SAMPLE_CHUNK_OPTIMUM_AREA 256
-#define ZONE_CHUNK_OPTIMUM_AREA 256
-#define MOD_CHUNK_OPTIMUM_AREA 256
-#define GEN_CHUNK_OPTIMUM_AREA 256
+ if(reason == FLUID_PRESET_SELECTED)
+ {
+ FLUID_LOG(FLUID_DBG, "Selected preset '%s' on channel %d", fluid_preset_get_name(preset), chan);
+ defsfont = fluid_sfont_get_data(preset->sfont);
+ load_preset_samples(defsfont, preset);
+ }
+ else if(reason == FLUID_PRESET_UNSELECTED)
+ {
+ FLUID_LOG(FLUID_DBG, "Deselected preset '%s' from channel %d", fluid_preset_get_name(preset), chan);
+ defsfont = fluid_sfont_get_data(preset->sfont);
+ unload_preset_samples(defsfont, preset);
+ }
-unsigned short badgen[] = { Gen_Unused1, Gen_Unused2, Gen_Unused3, Gen_Unused4,
- Gen_Reserved1, Gen_Reserved2, Gen_Reserved3, 0
-};
+ return FLUID_OK;
+}
-unsigned short badpgen[] = { Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
- Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_EndAddrCoarseOfs,
- Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity,
- Gen_EndLoopAddrCoarseOfs, Gen_SampleModes, Gen_ExclusiveClass,
- Gen_OverrideRootKey, 0
-};
-/* close SoundFont file and delete a SoundFont structure */
-void
-sfont_close (SFData * sf)
+/* Walk through all samples used by the passed in preset and make sure that the
+ * sample data is loaded for each sample. Used by dynamic sample loading. */
+static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)
{
- fluid_list_t *p, *p2;
-
- if (sf->sffd)
- fclose (sf->sffd);
-
- if (sf->fname)
- free (sf->fname);
-
- p = sf->info;
- while (p)
- {
- free (p->data);
- p = fluid_list_next (p);
- }
- delete_fluid_list(sf->info);
- sf->info = NULL;
-
- p = sf->preset;
- while (p)
- { /* loop over presets */
- p2 = ((SFPreset *) (p->data))->zone;
- while (p2)
- { /* loop over preset's zones */
- sfont_free_zone (p2->data);
- p2 = fluid_list_next (p2);
- } /* free preset's zone list */
- delete_fluid_list (((SFPreset *) (p->data))->zone);
- FLUID_FREE (p->data); /* free preset chunk */
- p = fluid_list_next (p);
- }
- delete_fluid_list (sf->preset);
- sf->preset = NULL;
-
- p = sf->inst;
- while (p)
- { /* loop over instruments */
- p2 = ((SFInst *) (p->data))->zone;
- while (p2)
- { /* loop over inst's zones */
- sfont_free_zone (p2->data);
- p2 = fluid_list_next (p2);
- } /* free inst's zone list */
- delete_fluid_list (((SFInst *) (p->data))->zone);
- FLUID_FREE (p->data);
- p = fluid_list_next (p);
- }
- delete_fluid_list (sf->inst);
- sf->inst = NULL;
-
- p = sf->sample;
- while (p)
- {
- FLUID_FREE (p->data);
- p = fluid_list_next (p);
- }
- delete_fluid_list (sf->sample);
- sf->sample = NULL;
-
- FLUID_FREE (sf);
-}
+ fluid_defpreset_t *defpreset;
+ fluid_preset_zone_t *preset_zone;
+ fluid_inst_t *inst;
+ fluid_inst_zone_t *inst_zone;
+ fluid_sample_t *sample;
+ SFData *sffile = NULL;
-/* free all elements of a zone (Preset or Instrument) */
-void
-sfont_free_zone (SFZone * zone)
-{
- fluid_list_t *p;
+ defpreset = fluid_preset_get_data(preset);
+ preset_zone = fluid_defpreset_get_zone(defpreset);
- if (!zone)
- return;
+ while(preset_zone != NULL)
+ {
+ inst = fluid_preset_zone_get_inst(preset_zone);
+ inst_zone = fluid_inst_get_zone(inst);
+
+ while(inst_zone != NULL)
+ {
+ sample = fluid_inst_zone_get_sample(inst_zone);
+
+ if((sample != NULL) && (sample->start != sample->end))
+ {
+ sample->preset_count++;
+
+ /* If this is the first time this sample has been selected,
+ * load the sampledata */
+ if(sample->preset_count == 1)
+ {
+ /* Make sure we have an open Soundfont file. Do this here
+ * to avoid having to open the file if no loading is necessary
+ * for a preset */
+ if(sffile == NULL)
+ {
+ sffile = fluid_sffile_open(defsfont->filename, defsfont->fcbs);
+
+ if(sffile == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Unable to open Soundfont file");
+ return FLUID_FAILED;
+ }
+ }
+
+ if(fluid_defsfont_load_sampledata(defsfont, sffile, sample) == FLUID_OK)
+ {
+ fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));
+ fluid_voice_optimize_sample(sample);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_ERR, "Unable to load sample '%s', disabling", sample->name);
+ sample->start = sample->end = 0;
+ }
+ }
+ }
+
+ inst_zone = fluid_inst_zone_next(inst_zone);
+ }
- p = zone->gen;
- while (p)
- { /* Free gen chunks for this zone */
- if (p->data)
- FLUID_FREE (p->data);
- p = fluid_list_next (p);
+ preset_zone = fluid_preset_zone_next(preset_zone);
}
- delete_fluid_list (zone->gen); /* free genlist */
- p = zone->mod;
- while (p)
- { /* Free mod chunks for this zone */
- if (p->data)
- FLUID_FREE (p->data);
- p = fluid_list_next (p);
+ if(sffile != NULL)
+ {
+ fluid_sffile_close(sffile);
}
- delete_fluid_list (zone->mod); /* free modlist */
- FLUID_FREE (zone); /* free zone chunk */
+ return FLUID_OK;
}
-/* preset sort function, first by bank, then by preset # */
-int
-sfont_preset_compare_func (void* a, void* b)
+/* Walk through all samples used by the passed in preset and unload the sample data
+ * of each sample that is not used by any selected preset anymore. Used by dynamic
+ * sample loading. */
+static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)
{
- int aval, bval;
+ fluid_defpreset_t *defpreset;
+ fluid_preset_zone_t *preset_zone;
+ fluid_inst_t *inst;
+ fluid_inst_zone_t *inst_zone;
+ fluid_sample_t *sample;
+
+ defpreset = fluid_preset_get_data(preset);
+ preset_zone = fluid_defpreset_get_zone(defpreset);
+
+ while(preset_zone != NULL)
+ {
+ inst = fluid_preset_zone_get_inst(preset_zone);
+ inst_zone = fluid_inst_get_zone(inst);
+
+ while(inst_zone != NULL)
+ {
+ sample = fluid_inst_zone_get_sample(inst_zone);
+
+ if((sample != NULL) && (sample->preset_count > 0))
+ {
+ sample->preset_count--;
+
+ /* If the sample is not used by any preset or used by a
+ * sounding voice, unload it from the sample cache. If it's
+ * still in use by a voice, dynamic_samples_sample_notify will
+ * take care of unloading the sample as soon as the voice is
+ * finished with it (but only on the next API call). */
+ if(sample->preset_count == 0 && sample->refcount == 0)
+ {
+ unload_sample(sample);
+ }
+ }
+
+ inst_zone = fluid_inst_zone_next(inst_zone);
+ }
- aval = (int) (((SFPreset *) a)->bank) << 16 | ((SFPreset *) a)->prenum;
- bval = (int) (((SFPreset *) b)->bank) << 16 | ((SFPreset *) b)->prenum;
+ preset_zone = fluid_preset_zone_next(preset_zone);
+ }
- return (aval - bval);
+ return FLUID_OK;
}
-/* delete zone from zone list */
-void
-sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone)
+/* Unload an unused sample from the samplecache */
+static void unload_sample(fluid_sample_t *sample)
{
- *zlist = fluid_list_remove (*zlist, (void*) zone);
- sfont_free_zone (zone);
-}
+ fluid_return_if_fail(sample != NULL);
+ fluid_return_if_fail(sample->data != NULL);
+ fluid_return_if_fail(sample->preset_count == 0);
+ fluid_return_if_fail(sample->refcount == 0);
-/* Find generator in gen list */
-fluid_list_t *
-gen_inlist (int gen, fluid_list_t * genlist)
-{ /* is generator in gen list? */
- fluid_list_t *p;
+ FLUID_LOG(FLUID_DBG, "Unloading sample '%s'", sample->name);
- p = genlist;
- while (p)
+ if(fluid_samplecache_unload(sample->data) == FLUID_FAILED)
{
- if (p->data == NULL)
- return (NULL);
- if (gen == ((SFGen *) p->data)->id)
- break;
- p = fluid_list_next (p);
+ FLUID_LOG(FLUID_ERR, "Unable to unload sample '%s'", sample->name);
+ }
+ else
+ {
+ sample->data = NULL;
+ sample->data24 = NULL;
}
- return (p);
-}
-
-/* check validity of instrument generator */
-int
-gen_valid (int gen)
-{ /* is generator id valid? */
- int i = 0;
-
- if (gen > Gen_MaxValid)
- return (FALSE);
- while (badgen[i] && badgen[i] != gen)
- i++;
- return (badgen[i] == 0);
-}
-
-/* check validity of preset generator */
-int
-gen_validp (int gen)
-{ /* is preset generator valid? */
- int i = 0;
-
- if (!gen_valid (gen))
- return (FALSE);
- while (badpgen[i] && badpgen[i] != (unsigned short) gen)
- i++;
- return (badpgen[i] == 0);
}
-/*================================util.c===========================*/
-
-/* Logging function, returns FAIL to use as a return value in calling funcs */
-int
-gerr (int ev, char * fmt, ...)
+static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx)
{
- va_list args;
-
- va_start (args, fmt);
- vprintf(fmt, args);
- va_end (args);
+ fluid_list_t *list;
+ fluid_inst_t *inst;
- printf("\n");
-
- return (FAIL);
-}
+ for(list = defsfont->inst; list != NULL; list = fluid_list_next(list))
+ {
+ inst = fluid_list_get(list);
-int
-safe_fread (void *buf, int count, FILE * fd)
-{
- if (fread (buf, count, 1, fd) != 1)
- { /* size_t = count, nmemb = 1 */
- if (feof (fd))
- gerr (ErrEof, _("EOF while attemping to read %d bytes"), count);
- else
- FLUID_LOG (FLUID_ERR, _("File read failed"));
- return (FAIL);
- }
- return (OK);
-}
+ if(inst->source_idx == idx)
+ {
+ return inst;
+ }
+ }
-int
-safe_fseek (FILE * fd, long ofs, int whence)
-{
- if (fseek (fd, ofs, whence) == -1) {
- FLUID_LOG (FLUID_ERR, _("File seek failed with offset = %ld and whence = %d"), ofs, whence);
- return (FAIL);
- }
- return (OK);
+ return NULL;
}
diff --git a/libs/fluidsynth/src/fluid_defsfont.h b/libs/fluidsynth/src/fluid_defsfont.h
index 29f3fd9e86..8b24934d81 100644
--- a/libs/fluidsynth/src/fluid_defsfont.h
+++ b/libs/fluidsynth/src/fluid_defsfont.h
@@ -5,16 +5,16 @@
* SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -27,16 +27,13 @@
#include "fluidsynth.h"
#include "fluidsynth_priv.h"
+#include "fluid_sffile.h"
#include "fluid_list.h"
+#include "fluid_mod.h"
+#include "fluid_gen.h"
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-
/*-----------------------------------sfont.h----------------------------*/
#define SF_SAMPMODES_LOOP 1
@@ -47,318 +44,6 @@
#define SF_MIN_SAMPLE_LENGTH 32
-/* Sound Font structure defines */
-
-typedef struct _SFVersion
-{ /* version structure */
- unsigned short major;
- unsigned short minor;
-}
-SFVersion;
-
-typedef struct _SFMod
-{ /* Modulator structure */
- unsigned short src; /* source modulator */
- unsigned short dest; /* destination generator */
- signed short amount; /* signed, degree of modulation */
- unsigned short amtsrc; /* second source controls amnt of first */
- unsigned short trans; /* transform applied to source */
-}
-SFMod;
-
-typedef union _SFGenAmount
-{ /* Generator amount structure */
- signed short sword; /* signed 16 bit value */
- unsigned short uword; /* unsigned 16 bit value */
- struct
- {
- unsigned char lo; /* low value for ranges */
- unsigned char hi; /* high value for ranges */
- }
- range;
-}
-SFGenAmount;
-
-typedef struct _SFGen
-{ /* Generator structure */
- unsigned short id; /* generator ID */
- SFGenAmount amount; /* generator value */
-}
-SFGen;
-
-typedef struct _SFZone
-{ /* Sample/instrument zone structure */
- fluid_list_t *instsamp; /* instrument/sample pointer for zone */
- fluid_list_t *gen; /* list of generators */
- fluid_list_t *mod; /* list of modulators */
-}
-SFZone;
-
-typedef struct _SFSample
-{ /* Sample structure */
- char name[21]; /* Name of sample */
- unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
- unsigned int start; /* Offset in sample area to start of sample */
- unsigned int end; /* Offset from start to end of sample,
- this is the last point of the
- sample, the SF spec has this as the
- 1st point after, corrected on
- load/save */
- unsigned int loopstart; /* Offset from start to start of loop */
- unsigned int loopend; /* Offset from start to end of loop,
- marks the first point after loop,
- whose sample value is ideally
- equivalent to loopstart */
- unsigned int samplerate; /* Sample rate recorded at */
- unsigned char origpitch; /* root midi key number */
- signed char pitchadj; /* pitch correction in cents */
- unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
- fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */
-}
-SFSample;
-
-typedef struct _SFInst
-{ /* Instrument structure */
- char name[21]; /* Name of instrument */
- fluid_list_t *zone; /* list of instrument zones */
-}
-SFInst;
-
-typedef struct _SFPreset
-{ /* Preset structure */
- char name[21]; /* preset name */
- unsigned short prenum; /* preset number */
- unsigned short bank; /* bank number */
- unsigned int libr; /* Not used (preserved) */
- unsigned int genre; /* Not used (preserved) */
- unsigned int morph; /* Not used (preserved) */
- fluid_list_t *zone; /* list of preset zones */
-}
-SFPreset;
-
-/* NOTE: sffd is also used to determine if sound font is new (NULL) */
-typedef struct _SFData
-{ /* Sound font data structure */
- SFVersion version; /* sound font version */
- SFVersion romver; /* ROM version */
- unsigned int samplepos; /* position within sffd of the sample chunk */
- unsigned int samplesize; /* length within sffd of the sample chunk */
- char *fname; /* file name */
- FILE *sffd; /* loaded sfont file descriptor */
- fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
- fluid_list_t *preset; /* linked list of preset info */
- fluid_list_t *inst; /* linked list of instrument info */
- fluid_list_t *sample; /* linked list of sample info */
-}
-SFData;
-
-/* sf file chunk IDs */
-enum
-{ UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID,
- INFO_ID, SDTA_ID, PDTA_ID, /* info/sample/preset */
-
- IFIL_ID, ISNG_ID, INAM_ID, IROM_ID, /* info ids (1st byte of info strings) */
- IVER_ID, ICRD_ID, IENG_ID, IPRD_ID, /* more info ids */
- ICOP_ID, ICMT_ID, ISFT_ID, /* and yet more info ids */
-
- SNAM_ID, SMPL_ID, /* sample ids */
- PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID, /* preset ids */
- IHDR_ID, IBAG_ID, IMOD_ID, IGEN_ID, /* instrument ids */
- SHDR_ID /* sample info */
-};
-
-/* generator types */
-typedef enum
-{ Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
- Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_ModLFO2Pitch,
- Gen_VibLFO2Pitch, Gen_ModEnv2Pitch, Gen_FilterFc, Gen_FilterQ,
- Gen_ModLFO2FilterFc, Gen_ModEnv2FilterFc, Gen_EndAddrCoarseOfs,
- Gen_ModLFO2Vol, Gen_Unused1, Gen_ChorusSend, Gen_ReverbSend, Gen_Pan,
- Gen_Unused2, Gen_Unused3, Gen_Unused4,
- Gen_ModLFODelay, Gen_ModLFOFreq, Gen_VibLFODelay, Gen_VibLFOFreq,
- Gen_ModEnvDelay, Gen_ModEnvAttack, Gen_ModEnvHold, Gen_ModEnvDecay,
- Gen_ModEnvSustain, Gen_ModEnvRelease, Gen_Key2ModEnvHold,
- Gen_Key2ModEnvDecay, Gen_VolEnvDelay, Gen_VolEnvAttack,
- Gen_VolEnvHold, Gen_VolEnvDecay, Gen_VolEnvSustain, Gen_VolEnvRelease,
- Gen_Key2VolEnvHold, Gen_Key2VolEnvDecay, Gen_Instrument,
- Gen_Reserved1, Gen_KeyRange, Gen_VelRange,
- Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity,
- Gen_Attenuation, Gen_Reserved2, Gen_EndLoopAddrCoarseOfs,
- Gen_CoarseTune, Gen_FineTune, Gen_SampleId, Gen_SampleModes,
- Gen_Reserved3, Gen_ScaleTune, Gen_ExclusiveClass, Gen_OverrideRootKey,
- Gen_Dummy
-}
-Gen_Type;
-
-#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
-#define Gen_Count Gen_Dummy /* count of generators */
-#define GenArrSize sizeof(SFGenAmount)*Gen_Count /* gen array size */
-
-/* generator unit type */
-typedef enum
-{
- None, /* No unit type */
- Unit_Smpls, /* in samples */
- Unit_32kSmpls, /* in 32k samples */
- Unit_Cent, /* in cents (1/100th of a semitone) */
- Unit_HzCent, /* in Hz Cents */
- Unit_TCent, /* in Time Cents */
- Unit_cB, /* in centibels (1/100th of a decibel) */
- Unit_Percent, /* in percentage */
- Unit_Semitone, /* in semitones */
- Unit_Range /* a range of values */
-}
-Gen_Unit;
-
-/* global data */
-
-extern unsigned short badgen[]; /* list of bad generators */
-extern unsigned short badpgen[]; /* list of bad preset generators */
-
-/* functions */
-void sfont_init_chunks (void);
-
-void sfont_close (SFData * sf);
-void sfont_free_zone (SFZone * zone);
-int sfont_preset_compare_func (void* a, void* b);
-
-void sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone);
-
-fluid_list_t *gen_inlist (int gen, fluid_list_t * genlist);
-int gen_valid (int gen);
-int gen_validp (int gen);
-
-
-/*-----------------------------------sffile.h----------------------------*/
-/*
- File structures and routines (used to be in sffile.h)
-*/
-
-#define CHNKIDSTR(id) &idlist[(id - 1) * 4]
-
-/* sfont file chunk sizes */
-#define SFPHDRSIZE 38
-#define SFBAGSIZE 4
-#define SFMODSIZE 10
-#define SFGENSIZE 4
-#define SFIHDRSIZE 22
-#define SFSHDRSIZE 46
-
-/* sfont file data structures */
-typedef struct _SFChunk
-{ /* RIFF file chunk structure */
- unsigned int id; /* chunk id */
- unsigned int size; /* size of the following chunk */
-}
-SFChunk;
-
-typedef struct _SFPhdr
-{
- unsigned char name[20]; /* preset name */
- unsigned short preset; /* preset number */
- unsigned short bank; /* bank number */
- unsigned short pbagndx; /* index into preset bag */
- unsigned int library; /* just for preserving them */
- unsigned int genre; /* Not used */
- unsigned int morphology; /* Not used */
-}
-SFPhdr;
-
-typedef struct _SFBag
-{
- unsigned short genndx; /* index into generator list */
- unsigned short modndx; /* index into modulator list */
-}
-SFBag;
-
-typedef struct _SFIhdr
-{
- char name[20]; /* Name of instrument */
- unsigned short ibagndx; /* Instrument bag index */
-}
-SFIhdr;
-
-typedef struct _SFShdr
-{ /* Sample header loading struct */
- char name[20]; /* Sample name */
- unsigned int start; /* Offset to start of sample */
- unsigned int end; /* Offset to end of sample */
- unsigned int loopstart; /* Offset to start of loop */
- unsigned int loopend; /* Offset to end of loop */
- unsigned int samplerate; /* Sample rate recorded at */
- unsigned char origpitch; /* root midi key number */
- signed char pitchadj; /* pitch correction in cents */
- unsigned short samplelink; /* Not used */
- unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
-}
-SFShdr;
-
-/* data */
-extern char idlist[];
-
-/* functions */
-SFData *sfload_file (const char * fname);
-
-
-
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-
-/* GLIB - Library of useful routines for C programming
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <glib.h>
-
-
-/*-----------------------------------util.h----------------------------*/
-/*
- Utility functions (formerly in util.h)
- */
-#define FAIL 0
-#define OK 1
-
-enum
-{ ErrWarn, ErrFatal, ErrStatus, ErrCorr, ErrEof, ErrMem, Errno,
- ErrRead, ErrWrite
-};
-
-#define ErrMax ErrWrite
-#define ErrnoStart Errno
-#define ErrnoEnd ErrWrite
-
-int gerr (int ev, char * fmt, ...);
-int safe_fread (void *buf, int count, FILE * fd);
-int safe_fwrite (void *buf, int count, FILE * fd);
-int safe_fseek (FILE * fd, long ofs, int whence);
-
-
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-
-
-
/***************************************************************
*
* FORWARD DECLARATIONS
@@ -367,7 +52,26 @@ typedef struct _fluid_defsfont_t fluid_defsfont_t;
typedef struct _fluid_defpreset_t fluid_defpreset_t;
typedef struct _fluid_preset_zone_t fluid_preset_zone_t;
typedef struct _fluid_inst_t fluid_inst_t;
-typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
+typedef struct _fluid_inst_zone_t fluid_inst_zone_t; /**< Soundfont Instrument Zone */
+typedef struct _fluid_voice_zone_t fluid_voice_zone_t;
+
+/* defines the velocity and key range for a zone */
+struct _fluid_zone_range_t
+{
+ int keylo;
+ int keyhi;
+ int vello;
+ int velhi;
+ unsigned char ignore; /* set to TRUE for legato playing to ignore this range zone */
+};
+
+/* Stored on a preset zone to keep track of the inst zones that could start a voice
+ * and their combined preset zone/instument zone ranges */
+struct _fluid_voice_zone_t
+{
+ fluid_inst_zone_t *inst_zone;
+ fluid_zone_range_t range;
+};
/*
@@ -375,57 +79,62 @@ typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
*/
-fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings);
-int delete_fluid_defsfloader(fluid_sfloader_t* loader);
-fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename);
+fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *filename);
-int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont);
-char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont);
-fluid_preset_t* fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
-void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont);
-int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset);
+int fluid_defsfont_sfont_delete(fluid_sfont_t *sfont);
+const char *fluid_defsfont_sfont_get_name(fluid_sfont_t *sfont);
+fluid_preset_t *fluid_defsfont_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum);
+void fluid_defsfont_sfont_iteration_start(fluid_sfont_t *sfont);
+fluid_preset_t *fluid_defsfont_sfont_iteration_next(fluid_sfont_t *sfont);
-int fluid_defpreset_preset_delete(fluid_preset_t* preset);
-char* fluid_defpreset_preset_get_name(fluid_preset_t* preset);
-int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset);
-int fluid_defpreset_preset_get_num(fluid_preset_t* preset);
-int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
+void fluid_defpreset_preset_delete(fluid_preset_t *preset);
+const char *fluid_defpreset_preset_get_name(fluid_preset_t *preset);
+int fluid_defpreset_preset_get_banknum(fluid_preset_t *preset);
+int fluid_defpreset_preset_get_num(fluid_preset_t *preset);
+int fluid_defpreset_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel);
+int fluid_zone_inside_range(fluid_zone_range_t *zone_range, int key, int vel);
/*
* fluid_defsfont_t
*/
struct _fluid_defsfont_t
{
- char* filename; /* the filename of this soundfont */
- unsigned int samplepos; /* the position in the file at which the sample data starts */
- unsigned int samplesize; /* the size of the sample data */
- short* sampledata; /* the sample data, loaded in ram */
- fluid_list_t* sample; /* the samples in this soundfont */
- fluid_defpreset_t* preset; /* the presets of this soundfont */
- int mlock; /* Should we try memlock (avoid swapping)? */
-
- fluid_preset_t iter_preset; /* preset interface used in the iteration */
- fluid_defpreset_t* iter_cur; /* the current preset in the iteration */
-
- fluid_preset_t** preset_stack; /* List of presets that are available to use */
- int preset_stack_capacity; /* Length of preset_stack array */
- int preset_stack_size; /* Current number of items in the stack */
+ const fluid_file_callbacks_t *fcbs; /* the file callbacks used to load this Soundfont */
+ char *filename; /* the filename of this soundfont */
+ unsigned int samplepos; /* the position in the file at which the sample data starts */
+ unsigned int samplesize; /* the size of the sample data in bytes */
+ short *sampledata; /* the sample data, loaded in ram */
+
+ unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit sample support */
+ unsigned int sample24size; /* length within sffd of the sm24 chunk */
+ char *sample24data; /* if not NULL, the least significant byte of the 24bit sample data, loaded in ram */
+
+ fluid_sfont_t *sfont; /* pointer to parent sfont */
+ fluid_list_t *sample; /* the samples in this soundfont */
+ fluid_list_t *preset; /* the presets of this soundfont */
+ fluid_list_t *inst; /* the instruments of this soundfont */
+ int mlock; /* Should we try memlock (avoid swapping)? */
+ int dynamic_samples; /* Enables dynamic sample loading if set */
+
+ fluid_list_t *preset_iter_cur; /* the current preset in the iteration */
};
-fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings);
-int delete_fluid_defsfont(fluid_defsfont_t* sfont);
-int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file);
-char* fluid_defsfont_get_name(fluid_defsfont_t* sfont);
-fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int prenum);
-void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont);
-int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset);
-int fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont);
-int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample);
-int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset);
+fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings);
+int delete_fluid_defsfont(fluid_defsfont_t *defsfont);
+int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *file_callbacks, const char *file);
+const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont);
+fluid_preset_t *fluid_defsfont_get_preset(fluid_defsfont_t *defsfont, int bank, int prenum);
+void fluid_defsfont_iteration_start(fluid_defsfont_t *defsfont);
+fluid_preset_t *fluid_defsfont_iteration_next(fluid_defsfont_t *defsfont);
+int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample);
+int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata);
+
+int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample);
+int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset);
/*
@@ -433,98 +142,90 @@ int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset
*/
struct _fluid_defpreset_t
{
- fluid_defpreset_t* next;
- fluid_defsfont_t* sfont; /* the soundfont this preset belongs to */
- char name[21]; /* the name of the preset */
- unsigned int bank; /* the bank number */
- unsigned int num; /* the preset number */
- fluid_preset_zone_t* global_zone; /* the global zone of the preset */
- fluid_preset_zone_t* zone; /* the chained list of preset zones */
+ fluid_defpreset_t *next;
+ fluid_defsfont_t *defsfont; /* the soundfont this preset belongs to */
+ char name[21]; /* the name of the preset */
+ unsigned int bank; /* the bank number */
+ unsigned int num; /* the preset number */
+ fluid_preset_zone_t *global_zone; /* the global zone of the preset */
+ fluid_preset_zone_t *zone; /* the chained list of preset zones */
};
-fluid_defpreset_t* new_fluid_defpreset(fluid_defsfont_t* sfont);
-int delete_fluid_defpreset(fluid_defpreset_t* preset);
-fluid_defpreset_t* fluid_defpreset_next(fluid_defpreset_t* preset);
-int fluid_defpreset_import_sfont(fluid_defpreset_t* preset, SFPreset* sfpreset, fluid_defsfont_t* sfont);
-int fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
-int fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
-fluid_preset_zone_t* fluid_defpreset_get_zone(fluid_defpreset_t* preset);
-fluid_preset_zone_t* fluid_defpreset_get_global_zone(fluid_defpreset_t* preset);
-int fluid_defpreset_get_banknum(fluid_defpreset_t* preset);
-int fluid_defpreset_get_num(fluid_defpreset_t* preset);
-char* fluid_defpreset_get_name(fluid_defpreset_t* preset);
-int fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
+fluid_defpreset_t *new_fluid_defpreset(fluid_defsfont_t *defsfont);
+void delete_fluid_defpreset(fluid_defpreset_t *defpreset);
+fluid_defpreset_t *fluid_defpreset_next(fluid_defpreset_t *defpreset);
+int fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset, SFPreset *sfpreset, fluid_defsfont_t *defsfont);
+int fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone);
+int fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone);
+fluid_preset_zone_t *fluid_defpreset_get_zone(fluid_defpreset_t *defpreset);
+fluid_preset_zone_t *fluid_defpreset_get_global_zone(fluid_defpreset_t *defpreset);
+int fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset);
+int fluid_defpreset_get_num(fluid_defpreset_t *defpreset);
+const char *fluid_defpreset_get_name(fluid_defpreset_t *defpreset);
+int fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int chan, int key, int vel);
/*
* fluid_preset_zone
*/
struct _fluid_preset_zone_t
{
- fluid_preset_zone_t* next;
- char* name;
- fluid_inst_t* inst;
- int keylo;
- int keyhi;
- int vello;
- int velhi;
- fluid_gen_t gen[GEN_LAST];
- fluid_mod_t * mod; /* List of modulators */
+ fluid_preset_zone_t *next;
+ char *name;
+ fluid_inst_t *inst;
+ fluid_list_t *voice_zone;
+ fluid_zone_range_t range;
+ fluid_gen_t gen[GEN_LAST];
+ fluid_mod_t *mod; /* List of modulators */
};
-fluid_preset_zone_t* new_fluid_preset_zone(char* name);
-int delete_fluid_preset_zone(fluid_preset_zone_t* zone);
-fluid_preset_zone_t* fluid_preset_zone_next(fluid_preset_zone_t* preset);
-int fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone* sfzone, fluid_defsfont_t* sfont);
-int fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel);
-fluid_inst_t* fluid_preset_zone_get_inst(fluid_preset_zone_t* zone);
+fluid_preset_zone_t *new_fluid_preset_zone(char *name);
+void delete_fluid_preset_zone(fluid_preset_zone_t *zone);
+fluid_preset_zone_t *fluid_preset_zone_next(fluid_preset_zone_t *zone);
+int fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defssfont);
+fluid_inst_t *fluid_preset_zone_get_inst(fluid_preset_zone_t *zone);
/*
* fluid_inst_t
*/
struct _fluid_inst_t
{
- char name[21];
- fluid_inst_zone_t* global_zone;
- fluid_inst_zone_t* zone;
+ char name[21];
+ int source_idx; /* Index of instrument in source Soundfont */
+ fluid_inst_zone_t *global_zone;
+ fluid_inst_zone_t *zone;
};
-fluid_inst_t* new_fluid_inst(void);
-int delete_fluid_inst(fluid_inst_t* inst);
-int fluid_inst_import_sfont(fluid_inst_t* inst, SFInst *sfinst, fluid_defsfont_t* sfont);
-int fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
-int fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
-fluid_inst_zone_t* fluid_inst_get_zone(fluid_inst_t* inst);
-fluid_inst_zone_t* fluid_inst_get_global_zone(fluid_inst_t* inst);
+fluid_inst_t *new_fluid_inst(void);
+fluid_inst_t *fluid_inst_import_sfont(fluid_preset_zone_t *preset_zone, SFInst *sfinst, fluid_defsfont_t *defsfont);
+void delete_fluid_inst(fluid_inst_t *inst);
+int fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone);
+int fluid_inst_add_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone);
+fluid_inst_zone_t *fluid_inst_get_zone(fluid_inst_t *inst);
+fluid_inst_zone_t *fluid_inst_get_global_zone(fluid_inst_t *inst);
/*
* fluid_inst_zone_t
*/
struct _fluid_inst_zone_t
{
- fluid_inst_zone_t* next;
- char* name;
- fluid_sample_t* sample;
- int keylo;
- int keyhi;
- int vello;
- int velhi;
- fluid_gen_t gen[GEN_LAST];
- fluid_mod_t * mod; /* List of modulators */
+ fluid_inst_zone_t *next;
+ char *name;
+ fluid_sample_t *sample;
+ fluid_zone_range_t range;
+ fluid_gen_t gen[GEN_LAST];
+ fluid_mod_t *mod; /* List of modulators */
};
-fluid_inst_zone_t* new_fluid_inst_zone(char* name);
-int delete_fluid_inst_zone(fluid_inst_zone_t* zone);
-fluid_inst_zone_t* fluid_inst_zone_next(fluid_inst_zone_t* zone);
-int fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont);
-int fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel);
-fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone);
+fluid_inst_zone_t *new_fluid_inst_zone(char *name);
+void delete_fluid_inst_zone(fluid_inst_zone_t *zone);
+fluid_inst_zone_t *fluid_inst_zone_next(fluid_inst_zone_t *zone);
+int fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont);
+fluid_sample_t *fluid_inst_zone_get_sample(fluid_inst_zone_t *zone);
-fluid_sample_t* new_fluid_sample(void);
-int delete_fluid_sample(fluid_sample_t* sample);
-int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont);
-int fluid_sample_in_rom(fluid_sample_t* sample);
+int fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont);
+int fluid_sample_in_rom(fluid_sample_t *sample);
#endif /* _FLUID_SFONT_H */
diff --git a/libs/fluidsynth/src/fluid_event.c b/libs/fluidsynth/src/fluid_event.c
index b3b0608345..d7962eac98 100644
--- a/libs/fluidsynth/src/fluid_event.c
+++ b/libs/fluidsynth/src/fluid_event.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -28,7 +28,7 @@
*/
-#include "fluid_event_priv.h"
+#include "fluid_event.h"
#include "fluidsynth_priv.h"
/***************************************************************
@@ -39,33 +39,36 @@
/* Event alloc/free */
void
-fluid_event_clear(fluid_event_t* evt)
+fluid_event_clear(fluid_event_t *evt)
{
- FLUID_MEMSET(evt, 0, sizeof(fluid_event_t));
+ FLUID_MEMSET(evt, 0, sizeof(fluid_event_t));
- // by default, no type
- evt->dest = -1;
- evt->src = -1;
- evt->type = -1;
+ // by default, no type
+ evt->dest = -1;
+ evt->src = -1;
+ evt->type = -1;
}
/**
* Create a new sequencer event structure.
* @return New sequencer event structure or NULL if out of memory
*/
-fluid_event_t*
+fluid_event_t *
new_fluid_event()
{
- fluid_event_t* evt;
+ fluid_event_t *evt;
- evt = FLUID_NEW(fluid_event_t);
- if (evt == NULL) {
- fluid_log(FLUID_PANIC, "event: Out of memory\n");
- return NULL;
- }
- fluid_event_clear(evt);
+ evt = FLUID_NEW(fluid_event_t);
- return(evt);
+ if(evt == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "event: Out of memory\n");
+ return NULL;
+ }
+
+ fluid_event_clear(evt);
+
+ return(evt);
}
/**
@@ -73,14 +76,11 @@ new_fluid_event()
* @param evt Sequencer event structure created by new_fluid_event().
*/
void
-delete_fluid_event(fluid_event_t* evt)
+delete_fluid_event(fluid_event_t *evt)
{
+ fluid_return_if_fail(evt != NULL);
- if (evt == NULL) {
- return;
- }
-
- FLUID_FREE(evt);
+ FLUID_FREE(evt);
}
/**
@@ -90,43 +90,43 @@ delete_fluid_event(fluid_event_t* evt)
* @param time Time value to assign
*/
void
-fluid_event_set_time(fluid_event_t* evt, unsigned int time)
+fluid_event_set_time(fluid_event_t *evt, unsigned int time)
{
- evt->time = time;
+ evt->time = time;
}
/**
- * Set source of a sequencer event (DOCME).
+ * Set source of a sequencer event. \c src must be a unique sequencer ID or -1 if not set.
* @param evt Sequencer event structure
- * @param src DOCME
+ * @param src Unique sequencer ID
*/
void
-fluid_event_set_source(fluid_event_t* evt, short src)
+fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src)
{
- evt->src = src;
+ evt->src = src;
}
/**
- * Set destination of a sequencer event (DOCME).
+ * Set destination of this sequencer event, i.e. the sequencer client this event will be sent to. \c dest must be a unique sequencer ID.
* @param evt Sequencer event structure
- * @param dest DOCME
+ * @param dest The destination unique sequencer ID
*/
void
-fluid_event_set_dest(fluid_event_t* evt, short dest)
+fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest)
{
- evt->dest = dest;
+ evt->dest = dest;
}
/**
* Set a sequencer event to be a timer event.
* @param evt Sequencer event structure
- * @param data DOCME
+ * @param data User supplied data pointer
*/
void
-fluid_event_timer(fluid_event_t* evt, void* data)
+fluid_event_timer(fluid_event_t *evt, void *data)
{
- evt->type = FLUID_SEQ_TIMER;
- evt->data = data;
+ evt->type = FLUID_SEQ_TIMER;
+ evt->data = data;
}
/**
@@ -137,12 +137,12 @@ fluid_event_timer(fluid_event_t* evt, void* data)
* @param vel MIDI velocity value (0-127)
*/
void
-fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
+fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel)
{
- evt->type = FLUID_SEQ_NOTEON;
- evt->channel = channel;
- evt->key = key;
- evt->vel = vel;
+ evt->type = FLUID_SEQ_NOTEON;
+ evt->channel = channel;
+ evt->key = key;
+ evt->vel = vel;
}
/**
@@ -152,11 +152,11 @@ fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
* @param key MIDI note number (0-127)
*/
void
-fluid_event_noteoff(fluid_event_t* evt, int channel, short key)
+fluid_event_noteoff(fluid_event_t *evt, int channel, short key)
{
- evt->type = FLUID_SEQ_NOTEOFF;
- evt->channel = channel;
- evt->key = key;
+ evt->type = FLUID_SEQ_NOTEOFF;
+ evt->channel = channel;
+ evt->key = key;
}
/**
@@ -165,16 +165,16 @@ fluid_event_noteoff(fluid_event_t* evt, int channel, short key)
* @param channel MIDI channel number
* @param key MIDI note number (0-127)
* @param vel MIDI velocity value (0-127)
- * @param duration Duration of note (DOCME units?)
+ * @param duration Duration of note in the time scale used by the sequencer (by default milliseconds)
*/
void
-fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration)
+fluid_event_note(fluid_event_t *evt, int channel, short key, short vel, unsigned int duration)
{
- evt->type = FLUID_SEQ_NOTE;
- evt->channel = channel;
- evt->key = key;
- evt->vel = vel;
- evt->duration = duration;
+ evt->type = FLUID_SEQ_NOTE;
+ evt->channel = channel;
+ evt->key = key;
+ evt->vel = vel;
+ evt->duration = duration;
}
/**
@@ -183,10 +183,10 @@ fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned
* @param channel MIDI channel number
*/
void
-fluid_event_all_sounds_off(fluid_event_t* evt, int channel)
+fluid_event_all_sounds_off(fluid_event_t *evt, int channel)
{
- evt->type = FLUID_SEQ_ALLSOUNDSOFF;
- evt->channel = channel;
+ evt->type = FLUID_SEQ_ALLSOUNDSOFF;
+ evt->channel = channel;
}
/**
@@ -195,10 +195,10 @@ fluid_event_all_sounds_off(fluid_event_t* evt, int channel)
* @param channel MIDI channel number
*/
void
-fluid_event_all_notes_off(fluid_event_t* evt, int channel)
+fluid_event_all_notes_off(fluid_event_t *evt, int channel)
{
- evt->type = FLUID_SEQ_ALLNOTESOFF;
- evt->channel = channel;
+ evt->type = FLUID_SEQ_ALLNOTESOFF;
+ evt->channel = channel;
}
/**
@@ -208,11 +208,11 @@ fluid_event_all_notes_off(fluid_event_t* evt, int channel)
* @param bank_num MIDI bank number (0-16383)
*/
void
-fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
+fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num)
{
- evt->type = FLUID_SEQ_BANKSELECT;
- evt->channel = channel;
- evt->control = bank_num;
+ evt->type = FLUID_SEQ_BANKSELECT;
+ evt->channel = channel;
+ evt->control = bank_num;
}
/**
@@ -222,11 +222,11 @@ fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
* @param val MIDI program number (0-127)
*/
void
-fluid_event_program_change(fluid_event_t* evt, int channel, short val)
+fluid_event_program_change(fluid_event_t *evt, int channel, short val)
{
- evt->type = FLUID_SEQ_PROGRAMCHANGE;
- evt->channel = channel;
- evt->value = val;
+ evt->type = FLUID_SEQ_PROGRAMCHANGE;
+ evt->channel = channel;
+ evt->value = val;
}
/**
@@ -238,27 +238,26 @@ fluid_event_program_change(fluid_event_t* evt, int channel, short val)
* @param preset_num MIDI preset number (0-127)
*/
void
-fluid_event_program_select(fluid_event_t* evt, int channel,
- unsigned int sfont_id, short bank_num, short preset_num)
+fluid_event_program_select(fluid_event_t *evt, int channel,
+ unsigned int sfont_id, short bank_num, short preset_num)
{
- evt->type = FLUID_SEQ_PROGRAMSELECT;
- evt->channel = channel;
- evt->duration = sfont_id;
- evt->value = preset_num;
- evt->control = bank_num;
+ evt->type = FLUID_SEQ_PROGRAMSELECT;
+ evt->channel = channel;
+ evt->duration = sfont_id;
+ evt->value = preset_num;
+ evt->control = bank_num;
}
/**
- * Set a sequencer event to be an any control change event.
+ * Set a sequencer event to be an any control change event (for internal use).
* @param evt Sequencer event structure
* @param channel MIDI channel number
- * DOCME
*/
void
-fluid_event_any_control_change(fluid_event_t* evt, int channel)
+fluid_event_any_control_change(fluid_event_t *evt, int channel)
{
- evt->type = FLUID_SEQ_ANYCONTROLCHANGE;
- evt->channel = channel;
+ evt->type = FLUID_SEQ_ANYCONTROLCHANGE;
+ evt->channel = channel;
}
/**
@@ -268,27 +267,36 @@ fluid_event_any_control_change(fluid_event_t* evt, int channel)
* @param pitch MIDI pitch bend value (0-16383, 8192 = no bend)
*/
void
-fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch)
+fluid_event_pitch_bend(fluid_event_t *evt, int channel, int pitch)
{
- evt->type = FLUID_SEQ_PITCHBEND;
- evt->channel = channel;
- if (pitch < 0) pitch = 0;
- if (pitch > 16383) pitch = 16383;
- evt->pitch = pitch;
+ evt->type = FLUID_SEQ_PITCHBEND;
+ evt->channel = channel;
+
+ if(pitch < 0)
+ {
+ pitch = 0;
+ }
+
+ if(pitch > 16383)
+ {
+ pitch = 16383;
+ }
+
+ evt->pitch = pitch;
}
/**
* Set a sequencer event to be a pitch wheel sensitivity event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
- * @param value MIDI pitch wheel sensitivity value (DOCME units?)
+ * @param value MIDI pitch wheel sensitivity value in semitones
*/
void
-fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
+fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, short value)
{
- evt->type = FLUID_SEQ_PITCHWHHELSENS;
- evt->channel = channel;
- evt->value = value;
+ evt->type = FLUID_SEQ_PITCHWHEELSENS;
+ evt->channel = channel;
+ evt->value = value;
}
/**
@@ -298,13 +306,22 @@ fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
* @param val MIDI modulation value (0-127)
*/
void
-fluid_event_modulation(fluid_event_t* evt, int channel, short val)
+fluid_event_modulation(fluid_event_t *evt, int channel, short val)
{
- evt->type = FLUID_SEQ_MODULATION;
- evt->channel = channel;
- if (val < 0) val = 0;
- if (val > 127) val = 127;
- evt->value = val;
+ evt->type = FLUID_SEQ_MODULATION;
+ evt->channel = channel;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->value = val;
}
/**
@@ -314,13 +331,22 @@ fluid_event_modulation(fluid_event_t* evt, int channel, short val)
* @param val MIDI sustain value (0-127)
*/
void
-fluid_event_sustain(fluid_event_t* evt, int channel, short val)
+fluid_event_sustain(fluid_event_t *evt, int channel, short val)
{
- evt->type = FLUID_SEQ_SUSTAIN;
- evt->channel = channel;
- if (val < 0) val = 0;
- if (val > 127) val = 127;
- evt->value = val;
+ evt->type = FLUID_SEQ_SUSTAIN;
+ evt->channel = channel;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->value = val;
}
/**
@@ -328,15 +354,15 @@ fluid_event_sustain(fluid_event_t* evt, int channel, short val)
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param control MIDI control number (0-127)
- * @param val MIDI control value (0-16383 DOCME is that true?)
+ * @param val MIDI control value (0-127)
*/
void
-fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val)
+fluid_event_control_change(fluid_event_t *evt, int channel, short control, short val)
{
- evt->type = FLUID_SEQ_CONTROLCHANGE;
- evt->channel = channel;
- evt->control = control;
- evt->value = val;
+ evt->type = FLUID_SEQ_CONTROLCHANGE;
+ evt->channel = channel;
+ evt->control = control;
+ evt->value = val;
}
/**
@@ -346,13 +372,22 @@ fluid_event_control_change(fluid_event_t* evt, int channel, short control, short
* @param val MIDI panning value (0-127, 0=left, 64 = middle, 127 = right)
*/
void
-fluid_event_pan(fluid_event_t* evt, int channel, short val)
+fluid_event_pan(fluid_event_t *evt, int channel, short val)
{
- evt->type = FLUID_SEQ_PAN;
- evt->channel = channel;
- if (val < 0) val = 0;
- if (val > 127) val = 127;
- evt->value = val;
+ evt->type = FLUID_SEQ_PAN;
+ evt->channel = channel;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->value = val;
}
/**
@@ -362,13 +397,22 @@ fluid_event_pan(fluid_event_t* evt, int channel, short val)
* @param val Volume value (0-127)
*/
void
-fluid_event_volume(fluid_event_t* evt, int channel, short val)
+fluid_event_volume(fluid_event_t *evt, int channel, short val)
{
- evt->type = FLUID_SEQ_VOLUME;
- evt->channel = channel;
- if (val < 0) val = 0;
- if (val > 127) val = 127;
- evt->value = val;
+ evt->type = FLUID_SEQ_VOLUME;
+ evt->channel = channel;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->value = val;
}
/**
@@ -378,13 +422,22 @@ fluid_event_volume(fluid_event_t* evt, int channel, short val)
* @param val Reverb amount (0-127)
*/
void
-fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
+fluid_event_reverb_send(fluid_event_t *evt, int channel, short val)
{
- evt->type = FLUID_SEQ_REVERBSEND;
- evt->channel = channel;
- if (val < 0) val = 0;
- if (val > 127) val = 127;
- evt->value = val;
+ evt->type = FLUID_SEQ_REVERBSEND;
+ evt->channel = channel;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->value = val;
}
/**
@@ -394,13 +447,22 @@ fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
* @param val Chorus amount (0-127)
*/
void
-fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
+fluid_event_chorus_send(fluid_event_t *evt, int channel, short val)
{
- evt->type = FLUID_SEQ_CHORUSSEND;
- evt->channel = channel;
- if (val < 0) val = 0;
- if (val > 127) val = 127;
- evt->value = val;
+ evt->type = FLUID_SEQ_CHORUSSEND;
+ evt->channel = channel;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->value = val;
}
@@ -410,9 +472,9 @@ fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
* @since 1.1.0
*/
void
-fluid_event_unregistering(fluid_event_t* evt)
+fluid_event_unregistering(fluid_event_t *evt)
{
- evt->type = FLUID_SEQ_UNREGISTERING;
+ evt->type = FLUID_SEQ_UNREGISTERING;
}
/**
@@ -422,14 +484,61 @@ fluid_event_unregistering(fluid_event_t* evt)
* @param val Aftertouch amount (0-127)
* @since 1.1.0
*/
-void
-fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val)
+void
+fluid_event_channel_pressure(fluid_event_t *evt, int channel, short val)
+{
+ evt->type = FLUID_SEQ_CHANNELPRESSURE;
+ evt->channel = channel;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->value = val;
+}
+
+/**
+ * Set a sequencer event to be a polyphonic aftertouch event.
+ * @param evt Sequencer event structure
+ * @param channel MIDI channel number
+ * @param key MIDI note number (0-127)
+ * @param val Aftertouch amount (0-127)
+ * @since 2.0.0
+ */
+void
+fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, short val)
{
- evt->type = FLUID_SEQ_CHANNELPRESSURE;
- evt->channel = channel;
- if (val < 0) val = 0;
- if (val > 127) val = 127;
- evt->value = val;
+ evt->type = FLUID_SEQ_KEYPRESSURE;
+ evt->channel = channel;
+
+ if(key < 0)
+ {
+ key = 0;
+ }
+
+ if(key > 127)
+ {
+ key = 127;
+ }
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+
+ if(val > 127)
+ {
+ val = 127;
+ }
+
+ evt->key = key;
+ evt->value = val;
}
/**
@@ -437,10 +546,10 @@ fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val)
* @param evt Sequencer event structure
* @since 1.1.0
*/
-void
-fluid_event_system_reset(fluid_event_t* evt)
+void
+fluid_event_system_reset(fluid_event_t *evt)
{
- evt->type = FLUID_SEQ_SYSTEMRESET;
+ evt->type = FLUID_SEQ_SYSTEMRESET;
}
@@ -454,49 +563,50 @@ fluid_event_system_reset(fluid_event_t* evt)
* @param evt Sequencer event structure
* @return Event type (#fluid_seq_event_type).
*/
-int fluid_event_get_type(fluid_event_t* evt)
+int fluid_event_get_type(fluid_event_t *evt)
{
- return evt->type;
+ return evt->type;
}
/**
+ * @internal
* Get the time field from a sequencer event structure.
* @param evt Sequencer event structure
- * @return Time value (DOCME units?)
+ * @return Time value
*/
-unsigned int fluid_event_get_time(fluid_event_t* evt)
+unsigned int fluid_event_get_time(fluid_event_t *evt)
{
- return evt->time;
+ return evt->time;
}
/**
- * Get the source field from a sequencer event structure.
+ * Get the source sequencer client from a sequencer event structure.
* @param evt Sequencer event structure
- * @return DOCME
+ * @return source field of the sequencer event
*/
-short fluid_event_get_source(fluid_event_t* evt)
+fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt)
{
- return evt->src;
+ return evt->src;
}
/**
- * Get the dest field from a sequencer event structure.
+ * Get the dest sequencer client from a sequencer event structure.
* @param evt Sequencer event structure
- * @return DOCME
+ * @return dest field of the sequencer event
*/
-short fluid_event_get_dest(fluid_event_t* evt)
+fluid_seq_id_t fluid_event_get_dest(fluid_event_t *evt)
{
- return evt->dest;
+ return evt->dest;
}
/**
* Get the MIDI channel field from a sequencer event structure.
* @param evt Sequencer event structure
- * @return MIDI channel number (DOCME 0-15 or more?)
+ * @return MIDI zero-based channel number
*/
-int fluid_event_get_channel(fluid_event_t* evt)
+int fluid_event_get_channel(fluid_event_t *evt)
{
- return evt->channel;
+ return evt->channel;
}
/**
@@ -504,9 +614,9 @@ int fluid_event_get_channel(fluid_event_t* evt)
* @param evt Sequencer event structure
* @return MIDI note number (0-127)
*/
-short fluid_event_get_key(fluid_event_t* evt)
+short fluid_event_get_key(fluid_event_t *evt)
{
- return evt->key;
+ return evt->key;
}
/**
@@ -514,10 +624,10 @@ short fluid_event_get_key(fluid_event_t* evt)
* @param evt Sequencer event structure
* @return MIDI velocity value (0-127)
*/
-short fluid_event_get_velocity(fluid_event_t* evt)
+short fluid_event_get_velocity(fluid_event_t *evt)
{
- return evt->vel;
+ return evt->vel;
}
/**
@@ -525,9 +635,9 @@ short fluid_event_get_velocity(fluid_event_t* evt)
* @param evt Sequencer event structure
* @return MIDI control number (0-127)
*/
-short fluid_event_get_control(fluid_event_t* evt)
+short fluid_event_get_control(fluid_event_t *evt)
{
- return evt->control;
+ return evt->control;
}
/**
@@ -537,13 +647,13 @@ short fluid_event_get_control(fluid_event_t* evt)
*
* The Value field is used by the following event types:
* #FLUID_SEQ_PROGRAMCHANGE, #FLUID_SEQ_PROGRAMSELECT (preset_num),
- * #FLUID_SEQ_PITCHWHHELSENS, #FLUID_SEQ_MODULATION, #FLUID_SEQ_SUSTAIN,
+ * #FLUID_SEQ_PITCHWHEELSENS, #FLUID_SEQ_MODULATION, #FLUID_SEQ_SUSTAIN,
* #FLUID_SEQ_CONTROLCHANGE, #FLUID_SEQ_PAN, #FLUID_SEQ_VOLUME,
* #FLUID_SEQ_REVERBSEND, #FLUID_SEQ_CHORUSSEND.
*/
-short fluid_event_get_value(fluid_event_t* evt)
+short fluid_event_get_value(fluid_event_t *evt)
{
- return evt->value;
+ return evt->value;
}
/**
@@ -553,21 +663,21 @@ short fluid_event_get_value(fluid_event_t* evt)
*
* Used by the #FLUID_SEQ_TIMER event type.
*/
-void* fluid_event_get_data(fluid_event_t* evt)
+void *fluid_event_get_data(fluid_event_t *evt)
{
- return evt->data;
+ return evt->data;
}
/**
* Get the duration field from a sequencer event structure.
* @param evt Sequencer event structure
- * @return Note duration value (DOCME units?)
+ * @return Note duration value in the time scale used by the sequencer (by default milliseconds)
*
* Used by the #FLUID_SEQ_NOTE event type.
*/
-unsigned int fluid_event_get_duration(fluid_event_t* evt)
+unsigned int fluid_event_get_duration(fluid_event_t *evt)
{
- return evt->duration;
+ return evt->duration;
}
/**
@@ -578,9 +688,9 @@ unsigned int fluid_event_get_duration(fluid_event_t* evt)
* Used by the #FLUID_SEQ_BANKSELECT and #FLUID_SEQ_PROGRAMSELECT
* event types.
*/
-short fluid_event_get_bank(fluid_event_t* evt)
+short fluid_event_get_bank(fluid_event_t *evt)
{
- return evt->control;
+ return evt->control;
}
/**
@@ -590,9 +700,9 @@ short fluid_event_get_bank(fluid_event_t* evt)
*
* Used by the #FLUID_SEQ_PITCHBEND event type.
*/
-int fluid_event_get_pitch(fluid_event_t* evt)
+int fluid_event_get_pitch(fluid_event_t *evt)
{
- return evt->pitch;
+ return evt->pitch;
}
/**
@@ -604,9 +714,9 @@ int fluid_event_get_pitch(fluid_event_t* evt)
* event types.
*/
short
-fluid_event_get_program(fluid_event_t* evt)
+fluid_event_get_program(fluid_event_t *evt)
{
- return evt->value;
+ return evt->value;
}
/**
@@ -617,9 +727,9 @@ fluid_event_get_program(fluid_event_t* evt)
* Used by the #FLUID_SEQ_PROGRAMSELECT event type.
*/
unsigned int
-fluid_event_get_sfont_id(fluid_event_t* evt)
+fluid_event_get_sfont_id(fluid_event_t *evt)
{
- return evt->duration;
+ return evt->duration;
}
@@ -628,154 +738,176 @@ fluid_event_get_sfont_id(fluid_event_t* evt)
/* heap management */
/********************/
-fluid_evt_heap_t*
+fluid_evt_heap_t *
_fluid_evt_heap_init(int nbEvents)
{
#ifdef HEAP_WITH_DYNALLOC
- int i;
- fluid_evt_heap_t* heap;
- fluid_evt_entry *tmp;
+ int i;
+ fluid_evt_heap_t *heap;
+ fluid_evt_entry *tmp;
- heap = FLUID_NEW(fluid_evt_heap_t);
- if (heap == NULL) {
- fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
- return NULL;
- }
+ heap = FLUID_NEW(fluid_evt_heap_t);
- heap->freelist = NULL;
- fluid_mutex_init(heap->mutex);
+ if(heap == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "sequencer: Out of memory\n");
+ return NULL;
+ }
+
+ heap->freelist = NULL;
+ fluid_mutex_init(heap->mutex);
- /* LOCK */
- fluid_mutex_lock(heap->mutex);
+ /* LOCK */
+ fluid_mutex_lock(heap->mutex);
- /* Allocate the event entries */
- for (i = 0; i < nbEvents; i++) {
- tmp = FLUID_NEW(fluid_evt_entry);
- tmp->next = heap->freelist;
- heap->freelist = tmp;
- }
+ /* Allocate the event entries */
+ for(i = 0; i < nbEvents; i++)
+ {
+ tmp = FLUID_NEW(fluid_evt_entry);
+ tmp->next = heap->freelist;
+ heap->freelist = tmp;
+ }
- /* UNLOCK */
- fluid_mutex_unlock(heap->mutex);
+ /* UNLOCK */
+ fluid_mutex_unlock(heap->mutex);
#else
- int i;
- fluid_evt_heap_t* heap;
- int siz = 2*sizeof(fluid_evt_entry *) + sizeof(fluid_evt_entry)*nbEvents;
-
- heap = (fluid_evt_heap_t *)FLUID_MALLOC(siz);
- if (heap == NULL) {
- fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
- return NULL;
- }
- FLUID_MEMSET(heap, 0, siz);
-
- /* link all heap events */
- {
- fluid_evt_entry *tmp = &(heap->pool);
- for (i = 0 ; i < nbEvents - 1 ; i++)
- tmp[i].next = &(tmp[i+1]);
- tmp[nbEvents-1].next = NULL;
-
- /* set head & tail */
- heap->tail = &(tmp[nbEvents-1]);
- heap->head = &(heap->pool);
- }
+ int i;
+ fluid_evt_heap_t *heap;
+ int siz = 2 * sizeof(fluid_evt_entry *) + sizeof(fluid_evt_entry) * nbEvents;
+
+ heap = (fluid_evt_heap_t *)FLUID_MALLOC(siz);
+
+ if(heap == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "sequencer: Out of memory\n");
+ return NULL;
+ }
+
+ FLUID_MEMSET(heap, 0, siz);
+
+ /* link all heap events */
+ {
+ fluid_evt_entry *tmp = &(heap->pool);
+
+ for(i = 0 ; i < nbEvents - 1 ; i++)
+ {
+ tmp[i].next = &(tmp[i + 1]);
+ }
+
+ tmp[nbEvents - 1].next = NULL;
+
+ /* set head & tail */
+ heap->tail = &(tmp[nbEvents - 1]);
+ heap->head = &(heap->pool);
+ }
#endif
- return (heap);
+ return (heap);
}
void
-_fluid_evt_heap_free(fluid_evt_heap_t* heap)
+_fluid_evt_heap_free(fluid_evt_heap_t *heap)
{
#ifdef HEAP_WITH_DYNALLOC
- fluid_evt_entry *tmp, *next;
+ fluid_evt_entry *tmp, *next;
+
+ /* LOCK */
+ fluid_mutex_lock(heap->mutex);
- /* LOCK */
- fluid_mutex_lock(heap->mutex);
+ tmp = heap->freelist;
- tmp = heap->freelist;
- while (tmp) {
- next = tmp->next;
- FLUID_FREE(tmp);
- tmp = next;
- }
+ while(tmp)
+ {
+ next = tmp->next;
+ FLUID_FREE(tmp);
+ tmp = next;
+ }
- /* UNLOCK */
- fluid_mutex_unlock(heap->mutex);
- fluid_mutex_destroy(heap->mutex);
+ /* UNLOCK */
+ fluid_mutex_unlock(heap->mutex);
+ fluid_mutex_destroy(heap->mutex);
- FLUID_FREE(heap);
+ FLUID_FREE(heap);
#else
- FLUID_FREE(heap);
+ FLUID_FREE(heap);
#endif
}
-fluid_evt_entry*
-_fluid_seq_heap_get_free(fluid_evt_heap_t* heap)
+fluid_evt_entry *
+_fluid_seq_heap_get_free(fluid_evt_heap_t *heap)
{
#ifdef HEAP_WITH_DYNALLOC
- fluid_evt_entry* evt = NULL;
+ fluid_evt_entry *evt = NULL;
- /* LOCK */
- fluid_mutex_lock(heap->mutex);
+ /* LOCK */
+ fluid_mutex_lock(heap->mutex);
#if !defined(MACOS9)
- if (heap->freelist == NULL) {
- heap->freelist = FLUID_NEW(fluid_evt_entry);
- if (heap->freelist != NULL) {
- heap->freelist->next = NULL;
+
+ if(heap->freelist == NULL)
+ {
+ heap->freelist = FLUID_NEW(fluid_evt_entry);
+
+ if(heap->freelist != NULL)
+ {
+ heap->freelist->next = NULL;
+ }
}
- }
+
#endif
- evt = heap->freelist;
+ evt = heap->freelist;
- if (evt != NULL) {
- heap->freelist = heap->freelist->next;
- evt->next = NULL;
- }
+ if(evt != NULL)
+ {
+ heap->freelist = heap->freelist->next;
+ evt->next = NULL;
+ }
- /* UNLOCK */
- fluid_mutex_unlock(heap->mutex);
+ /* UNLOCK */
+ fluid_mutex_unlock(heap->mutex);
- return evt;
+ return evt;
#else
- fluid_evt_entry* evt;
- if (heap->head == NULL) return NULL;
+ fluid_evt_entry *evt;
- /* take from head of the heap */
- /* critical - should threadlock ? */
- evt = heap->head;
- heap->head = heap->head->next;
+ if(heap->head == NULL)
+ {
+ return NULL;
+ }
- return evt;
+ /* take from head of the heap */
+ /* critical - should threadlock ? */
+ evt = heap->head;
+ heap->head = heap->head->next;
+
+ return evt;
#endif
}
void
-_fluid_seq_heap_set_free(fluid_evt_heap_t* heap, fluid_evt_entry* evt)
+_fluid_seq_heap_set_free(fluid_evt_heap_t *heap, fluid_evt_entry *evt)
{
#ifdef HEAP_WITH_DYNALLOC
- /* LOCK */
- fluid_mutex_lock(heap->mutex);
+ /* LOCK */
+ fluid_mutex_lock(heap->mutex);
- evt->next = heap->freelist;
- heap->freelist = evt;
+ evt->next = heap->freelist;
+ heap->freelist = evt;
- /* UNLOCK */
- fluid_mutex_unlock(heap->mutex);
+ /* UNLOCK */
+ fluid_mutex_unlock(heap->mutex);
#else
- /* append to the end of the heap */
- /* critical - should threadlock ? */
- heap->tail->next = evt;
- heap->tail = evt;
- evt->next = NULL;
+ /* append to the end of the heap */
+ /* critical - should threadlock ? */
+ heap->tail->next = evt;
+ heap->tail = evt;
+ evt->next = NULL;
#endif
}
diff --git a/libs/fluidsynth/src/fluid_event.h b/libs/fluidsynth/src/fluid_event.h
new file mode 100644
index 0000000000..4beb0147e5
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_event.h
@@ -0,0 +1,87 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+#ifndef _FLUID_EVENT_PRIV_H
+#define _FLUID_EVENT_PRIV_H
+
+#include "fluidsynth.h"
+#include "fluid_sys.h"
+
+/* Private data for event */
+/* ?? should be optimized in size, using unions */
+struct _fluid_event_t
+{
+ unsigned int time;
+ int type;
+ fluid_seq_id_t src;
+ fluid_seq_id_t dest;
+ int channel;
+ short key;
+ short vel;
+ short control;
+ short value;
+ short id; //?? unused ?
+ int pitch;
+ unsigned int duration;
+ void *data;
+};
+
+unsigned int fluid_event_get_time(fluid_event_t *evt);
+void fluid_event_set_time(fluid_event_t *evt, unsigned int time);
+
+void fluid_event_clear(fluid_event_t *evt);
+
+/* private data for sorter + heap */
+enum fluid_evt_entry_type
+{
+ FLUID_EVT_ENTRY_INSERT = 0,
+ FLUID_EVT_ENTRY_REMOVE
+};
+
+typedef struct _fluid_evt_entry fluid_evt_entry;
+struct _fluid_evt_entry
+{
+ fluid_evt_entry *next;
+ short entryType;
+ fluid_event_t evt;
+};
+
+#define HEAP_WITH_DYNALLOC 1
+/* #undef HEAP_WITH_DYNALLOC */
+
+typedef struct _fluid_evt_heap_t
+{
+#ifdef HEAP_WITH_DYNALLOC
+ fluid_evt_entry *freelist;
+ fluid_mutex_t mutex;
+#else
+ fluid_evt_entry *head;
+ fluid_evt_entry *tail;
+ fluid_evt_entry pool;
+#endif
+} fluid_evt_heap_t;
+
+fluid_evt_heap_t *_fluid_evt_heap_init(int nbEvents);
+void _fluid_evt_heap_free(fluid_evt_heap_t *heap);
+fluid_evt_entry *_fluid_seq_heap_get_free(fluid_evt_heap_t *heap);
+void _fluid_seq_heap_set_free(fluid_evt_heap_t *heap, fluid_evt_entry *evt);
+
+#endif /* _FLUID_EVENT_PRIV_H */
diff --git a/libs/fluidsynth/src/fluid_gen.c b/libs/fluidsynth/src/fluid_gen.c
index 0f1413eab2..f01f941942 100644
--- a/libs/fluidsynth/src/fluid_gen.c
+++ b/libs/fluidsynth/src/fluid_gen.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -24,89 +24,94 @@
/* See SFSpec21 $8.1.3 */
-fluid_gen_info_t fluid_gen_info[] = {
- /* number/name init scale min max def */
- { GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
- { GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
- { GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
- { GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
- { GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
- { GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
- { GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
- { GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
- { GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
- { GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
- { GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
- { GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
- { GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
- { GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
- { GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
- { GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
- { GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
- { GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
- { GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
- { GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
- { GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
- { GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
- { GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
- { GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
- { GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
- { GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
- { GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
- { GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
- { GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
- { GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
- { GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
- { GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
- { GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
- { GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
- { GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
- { GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
- { GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
- { GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
- { GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
- { GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
- { GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
- { GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
- { GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
- { GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
- { GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
- { GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
- { GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
- { GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
- { GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
- { GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f }
+static const fluid_gen_info_t fluid_gen_info[] =
+{
+ /* number/name init scale min max def */
+ { GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
+ { GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
+ { GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
+ { GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
+ { GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
+ { GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
+ { GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
+ { GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
+ { GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
+ { GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
+ { GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
+ { GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
+ { GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
+ { GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
+ { GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
+ { GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
+ { GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
+ { GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
+ { GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
+ { GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
+ { GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
+ { GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
+ { GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
+ { GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
+ { GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
+ { GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
+ { GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
+ { GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
+ { GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
+ { GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
+ { GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
+ { GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
+ { GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
+ { GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
+ { GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
+ { GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
+ { GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
+ { GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
+ { GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
+ { GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
+ { GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
+ { GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
+ { GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
+ { GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
+ { GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
+ { GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
+ { GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
+ { GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
+ { GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
+ { GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f },
+ { GEN_CUSTOM_BALANCE, 1, 0, -960.0f, 960.0f, 0.0f },
+ { GEN_CUSTOM_FILTERFC, 1, 2, 0.0f, 22050.0f, 0.0f },
+ { GEN_CUSTOM_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f }
};
/**
* Set an array of generators to their default values.
* @param gen Array of generators (should be #GEN_LAST in size).
- * @return Always returns 0
+ * @return Always returns #FLUID_OK
*/
int
-fluid_gen_set_default_values(fluid_gen_t* gen)
+fluid_gen_set_default_values(fluid_gen_t *gen)
{
- int i;
+ int i;
- for (i = 0; i < GEN_LAST; i++) {
- gen[i].flags = GEN_UNUSED;
- gen[i].mod = 0.0;
- gen[i].nrpn = 0.0;
- gen[i].val = fluid_gen_info[i].def;
- }
+ for(i = 0; i < GEN_LAST; i++)
+ {
+ gen[i].flags = GEN_UNUSED;
+ gen[i].mod = 0.0;
+ gen[i].nrpn = 0.0;
+ gen[i].val = fluid_gen_info[i].def;
+ }
- return FLUID_OK;
+ return FLUID_OK;
}
@@ -115,35 +120,37 @@ fluid_gen_set_default_values(fluid_gen_t* gen)
* Set an array of generators to their initial value
*/
int
-fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel)
+fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel)
{
- int i;
+ int i;
- fluid_gen_set_default_values(gen);
+ fluid_gen_set_default_values(gen);
- for (i = 0; i < GEN_LAST; i++) {
- gen[i].nrpn = fluid_channel_get_gen(channel, i);
+ for(i = 0; i < GEN_LAST; i++)
+ {
+ gen[i].nrpn = fluid_channel_get_gen(channel, i);
- /* This is an extension to the SoundFont standard. More
- * documentation is available at the fluid_synth_set_gen2()
- * function. */
- if (fluid_channel_get_gen_abs(channel, i)) {
- gen[i].flags = GEN_ABS_NRPN;
- }
- }
+ /* This is an extension to the SoundFont standard. More
+ * documentation is available at the fluid_synth_set_gen2()
+ * function. */
+ if(fluid_channel_get_gen_abs(channel, i))
+ {
+ gen[i].flags = GEN_ABS_NRPN;
+ }
+ }
- return FLUID_OK;
+ return FLUID_OK;
}
fluid_real_t fluid_gen_scale(int gen, float value)
{
- return (fluid_gen_info[gen].min
- + value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min));
+ return (fluid_gen_info[gen].min
+ + value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min));
}
fluid_real_t fluid_gen_scale_nrpn(int gen, int data)
{
- fluid_real_t value = (float) data - 8192.0f;
- fluid_clip(value, -8192, 8192);
- return value * (float) fluid_gen_info[gen].nrpn_scale;
+ fluid_real_t value = (float) data - 8192.0f;
+ fluid_clip(value, -8192, 8192);
+ return value * (float) fluid_gen_info[gen].nrpn_scale;
}
diff --git a/libs/fluidsynth/src/fluid_gen.h b/libs/fluidsynth/src/fluid_gen.h
index f54d0490fc..d156b807b9 100644
--- a/libs/fluidsynth/src/fluid_gen.h
+++ b/libs/fluidsynth/src/fluid_gen.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -24,21 +24,44 @@
#include "fluidsynth_priv.h"
-typedef struct _fluid_gen_info_t {
- char num; /* Generator number */
- char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
- char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
- float min; /* The minimum value */
- float max; /* The maximum value */
- float def; /* The default value (cfr. fluid_gen_set_default_values()) */
+typedef struct _fluid_gen_info_t
+{
+ char num; /* Generator number */
+ char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
+ char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
+ float min; /* The minimum value */
+ float max; /* The maximum value */
+ float def; /* The default value (cfr. fluid_gen_set_default_values()) */
} fluid_gen_info_t;
+/*
+ * SoundFont generator structure.
+ */
+typedef struct _fluid_gen_t
+{
+ unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
+ double val; /**< The nominal value */
+ double mod; /**< Change by modulators */
+ double nrpn; /**< Change by NRPN messages */
+} fluid_gen_t;
+
+/*
+ * Enum value for 'flags' field of #fluid_gen_t (not really flags).
+ */
+enum fluid_gen_flags
+{
+ GEN_UNUSED, /**< Generator value is not set */
+ GEN_SET, /**< Generator value is set */
+ GEN_ABS_NRPN /**< Generator is an absolute value */
+};
+
#define fluid_gen_set_mod(_gen, _val) { (_gen)->mod = (double) (_val); }
#define fluid_gen_set_nrpn(_gen, _val) { (_gen)->nrpn = (double) (_val); }
fluid_real_t fluid_gen_scale(int gen, float value);
fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn);
-int fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel);
+int fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel);
+int fluid_gen_set_default_values(fluid_gen_t *gen);
#endif /* _FLUID_GEN_H */
diff --git a/libs/fluidsynth/src/fluid_hash.c b/libs/fluidsynth/src/fluid_hash.c
index 9d5a92009e..b6586895b5 100644
--- a/libs/fluidsynth/src/fluid_hash.c
+++ b/libs/fluidsynth/src/fluid_hash.c
@@ -42,67 +42,71 @@
typedef struct
{
- fluid_hashtable_t *hashtable;
- fluid_hashnode_t *prev_node;
- fluid_hashnode_t *node;
- int position;
- int pre_advanced; // Boolean
- int version;
+ fluid_hashtable_t *hashtable;
+ fluid_hashnode_t *prev_node;
+ fluid_hashnode_t *node;
+ int position;
+ int pre_advanced; // Boolean
+ int version;
} RealIter;
/* Excerpt from glib gprimes.c */
-static const guint primes[] =
+static const unsigned int primes[] =
{
- 11,
- 19,
- 37,
- 73,
- 109,
- 163,
- 251,
- 367,
- 557,
- 823,
- 1237,
- 1861,
- 2777,
- 4177,
- 6247,
- 9371,
- 14057,
- 21089,
- 31627,
- 47431,
- 71143,
- 106721,
- 160073,
- 240101,
- 360163,
- 540217,
- 810343,
- 1215497,
- 1823231,
- 2734867,
- 4102283,
- 6153409,
- 9230113,
- 13845163,
+ 11,
+ 19,
+ 37,
+ 73,
+ 109,
+ 163,
+ 251,
+ 367,
+ 557,
+ 823,
+ 1237,
+ 1861,
+ 2777,
+ 4177,
+ 6247,
+ 9371,
+ 14057,
+ 21089,
+ 31627,
+ 47431,
+ 71143,
+ 106721,
+ 160073,
+ 240101,
+ 360163,
+ 540217,
+ 810343,
+ 1215497,
+ 1823231,
+ 2734867,
+ 4102283,
+ 6153409,
+ 9230113,
+ 13845163,
};
-static const unsigned int nprimes = sizeof (primes) / sizeof (primes[0]);
+static const unsigned int nprimes = FLUID_N_ELEMENTS(primes);
static unsigned int
-spaced_primes_closest (unsigned int num)
+spaced_primes_closest(unsigned int num)
{
- unsigned int i;
+ unsigned int i;
- for (i = 0; i < nprimes; i++)
- if (primes[i] > num)
- return primes[i];
+ for(i = 0; i < nprimes; i++)
+ {
+ if(primes[i] > num)
+ {
+ return primes[i];
+ }
+ }
- return primes[nprimes - 1];
+ return primes[nprimes - 1];
}
/* End excerpt from glib gprimes.c */
@@ -136,51 +140,57 @@ spaced_primes_closest (unsigned int num)
* save insertions from having to compute the hash record again for
* the new record.
*/
-static inline fluid_hashnode_t **
-fluid_hashtable_lookup_node (fluid_hashtable_t *hashtable, const void *key,
- unsigned int *hash_return)
+static FLUID_INLINE fluid_hashnode_t **
+fluid_hashtable_lookup_node(fluid_hashtable_t *hashtable, const void *key,
+ unsigned int *hash_return)
{
- fluid_hashnode_t **node_ptr, *node;
- unsigned int hash_value;
-
- hash_value = (* hashtable->hash_func)(key);
- node_ptr = &hashtable->nodes[hash_value % hashtable->size];
-
- if (hash_return)
- *hash_return = hash_value;
-
- /* Hash table lookup needs to be fast.
- * We therefore remove the extra conditional of testing
- * whether to call the key_equal_func or not from
- * the inner loop.
- *
- * Additional optimisation: first check if our full hash
- * values are equal so we can avoid calling the full-blown
- * key equality function in most cases.
- */
- if (hashtable->key_equal_func)
+ fluid_hashnode_t **node_ptr, *node;
+ unsigned int hash_value;
+
+ hash_value = (* hashtable->hash_func)(key);
+ node_ptr = &hashtable->nodes[hash_value % hashtable->size];
+
+ if(hash_return)
{
- while ((node = *node_ptr))
+ *hash_return = hash_value;
+ }
+
+ /* Hash table lookup needs to be fast.
+ * We therefore remove the extra conditional of testing
+ * whether to call the key_equal_func or not from
+ * the inner loop.
+ *
+ * Additional optimisation: first check if our full hash
+ * values are equal so we can avoid calling the full-blown
+ * key equality function in most cases.
+ */
+ if(hashtable->key_equal_func)
+ {
+ while((node = *node_ptr))
{
- if (node->key_hash == hash_value &&
- hashtable->key_equal_func (node->key, key))
- break;
+ if(node->key_hash == hash_value &&
+ hashtable->key_equal_func(node->key, key))
+ {
+ break;
+ }
- node_ptr = &(*node_ptr)->next;
+ node_ptr = &(*node_ptr)->next;
}
}
- else
+ else
{
- while ((node = *node_ptr))
+ while((node = *node_ptr))
{
- if (node->key == key)
- break;
+ if(node->key == key)
+ {
+ break;
+ }
- node_ptr = &(*node_ptr)->next;
+ node_ptr = &(*node_ptr)->next;
}
}
- return node_ptr;
+ return node_ptr;
}
/*
@@ -213,25 +223,29 @@ fluid_hashtable_lookup_node (fluid_hashtable_t *hashtable, const void *key,
* modified at all. Stay tuned. :)
*/
static void
-fluid_hashtable_remove_node (fluid_hashtable_t *hashtable,
- fluid_hashnode_t ***node_ptr_ptr, int notify)
+fluid_hashtable_remove_node(fluid_hashtable_t *hashtable,
+ fluid_hashnode_t ***node_ptr_ptr, int notify)
{
- fluid_hashnode_t **node_ptr, *node;
+ fluid_hashnode_t **node_ptr, *node;
- node_ptr = *node_ptr_ptr;
- node = *node_ptr;
+ node_ptr = *node_ptr_ptr;
+ node = *node_ptr;
- *node_ptr = node->next;
+ *node_ptr = node->next;
- if (notify && hashtable->key_destroy_func)
- hashtable->key_destroy_func (node->key);
+ if(notify && hashtable->key_destroy_func)
+ {
+ hashtable->key_destroy_func(node->key);
+ }
- if (notify && hashtable->value_destroy_func)
- hashtable->value_destroy_func (node->value);
+ if(notify && hashtable->value_destroy_func)
+ {
+ hashtable->value_destroy_func(node->value);
+ }
- FLUID_FREE (node);
+ FLUID_FREE(node);
- hashtable->nnodes--;
+ hashtable->nnodes--;
}
/*
@@ -246,16 +260,20 @@ fluid_hashtable_remove_node (fluid_hashtable_t *hashtable,
* for the key and value of the hash node.
*/
static void
-fluid_hashtable_remove_all_nodes (fluid_hashtable_t *hashtable, int notify)
+fluid_hashtable_remove_all_nodes(fluid_hashtable_t *hashtable, int notify)
{
- fluid_hashnode_t **node_ptr;
- int i;
+ fluid_hashnode_t **node_ptr;
+ int i;
- for (i = 0; i < hashtable->size; i++)
- for (node_ptr = &hashtable->nodes[i]; *node_ptr != NULL;)
- fluid_hashtable_remove_node (hashtable, &node_ptr, notify);
+ for(i = 0; i < hashtable->size; i++)
+ {
+ for(node_ptr = &hashtable->nodes[i]; *node_ptr != NULL;)
+ {
+ fluid_hashtable_remove_node(hashtable, &node_ptr, notify);
+ }
+ }
- hashtable->nnodes = 0;
+ hashtable->nnodes = 0;
}
/*
@@ -268,43 +286,45 @@ fluid_hashtable_remove_all_nodes (fluid_hashtable_t *hashtable, int notify)
* fluid_hashtable_maybe_resize() instead.
*/
static void
-fluid_hashtable_resize (fluid_hashtable_t *hashtable)
+fluid_hashtable_resize(fluid_hashtable_t *hashtable)
{
- fluid_hashnode_t **new_nodes;
- fluid_hashnode_t *node;
- fluid_hashnode_t *next;
- unsigned int hash_val;
- int new_size;
- int i;
+ fluid_hashnode_t **new_nodes;
+ fluid_hashnode_t *node;
+ fluid_hashnode_t *next;
+ unsigned int hash_val;
+ int new_size;
+ int i;
- new_size = spaced_primes_closest (hashtable->nnodes);
- new_size = (new_size < HASH_TABLE_MIN_SIZE) ? HASH_TABLE_MIN_SIZE :
- ((new_size > HASH_TABLE_MAX_SIZE) ? HASH_TABLE_MAX_SIZE : new_size);
+ new_size = spaced_primes_closest(hashtable->nnodes);
+ new_size = (new_size < HASH_TABLE_MIN_SIZE) ? HASH_TABLE_MIN_SIZE :
+ ((new_size > HASH_TABLE_MAX_SIZE) ? HASH_TABLE_MAX_SIZE : new_size);
- new_nodes = FLUID_ARRAY (fluid_hashnode_t *, new_size);
+ new_nodes = FLUID_ARRAY(fluid_hashnode_t *, new_size);
- if (!new_nodes)
- {
- FLUID_LOG (FLUID_ERR, "Out of memory");
- return;
- }
+ if(!new_nodes)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return;
+ }
- FLUID_MEMSET (new_nodes, 0, new_size * sizeof (fluid_hashnode_t *));
+ FLUID_MEMSET(new_nodes, 0, new_size * sizeof(fluid_hashnode_t *));
- for (i = 0; i < hashtable->size; i++)
- for (node = hashtable->nodes[i]; node; node = next)
- {
- next = node->next;
+ for(i = 0; i < hashtable->size; i++)
+ {
+ for(node = hashtable->nodes[i]; node; node = next)
+ {
+ next = node->next;
- hash_val = node->key_hash % new_size;
+ hash_val = node->key_hash % new_size;
- node->next = new_nodes[hash_val];
- new_nodes[hash_val] = node;
- }
+ node->next = new_nodes[hash_val];
+ new_nodes[hash_val] = node;
+ }
+ }
- FLUID_FREE (hashtable->nodes);
- hashtable->nodes = new_nodes;
- hashtable->size = new_size;
+ FLUID_FREE(hashtable->nodes);
+ hashtable->nodes = new_nodes;
+ hashtable->size = new_size;
}
/*
@@ -316,15 +336,17 @@ fluid_hashtable_resize (fluid_hashtable_t *hashtable)
* Essentially, calls fluid_hashtable_resize() if the table has strayed
* too far from its ideal size for its number of nodes.
*/
-static inline void
-fluid_hashtable_maybe_resize (fluid_hashtable_t *hashtable)
+static FLUID_INLINE void
+fluid_hashtable_maybe_resize(fluid_hashtable_t *hashtable)
{
- int nnodes = hashtable->nnodes;
- int size = hashtable->size;
+ int nnodes = hashtable->nnodes;
+ int size = hashtable->size;
- if ((size >= 3 * nnodes && size > HASH_TABLE_MIN_SIZE) ||
- (3 * size <= nnodes && size < HASH_TABLE_MAX_SIZE))
- fluid_hashtable_resize (hashtable);
+ if((size >= 3 * nnodes && size > HASH_TABLE_MIN_SIZE) ||
+ (3 * size <= nnodes && size < HASH_TABLE_MAX_SIZE))
+ {
+ fluid_hashtable_resize(hashtable);
+ }
}
/**
@@ -345,10 +367,10 @@ fluid_hashtable_maybe_resize (fluid_hashtable_t *hashtable)
*
* Return value: a new #fluid_hashtable_t.
**/
-fluid_hashtable_t*
-new_fluid_hashtable (fluid_hash_func_t hash_func, fluid_equal_func_t key_equal_func)
+fluid_hashtable_t *
+new_fluid_hashtable(fluid_hash_func_t hash_func, fluid_equal_func_t key_equal_func)
{
- return new_fluid_hashtable_full (hash_func, key_equal_func, NULL, NULL);
+ return new_fluid_hashtable_full(hash_func, key_equal_func, NULL, NULL);
}
@@ -369,33 +391,39 @@ new_fluid_hashtable (fluid_hash_func_t hash_func, fluid_equal_func_t key_equal_f
*
* Return value: a new #fluid_hashtable_t.
**/
-fluid_hashtable_t*
-new_fluid_hashtable_full (fluid_hash_func_t hash_func,
- fluid_equal_func_t key_equal_func,
- fluid_destroy_notify_t key_destroy_func,
- fluid_destroy_notify_t value_destroy_func)
+fluid_hashtable_t *
+new_fluid_hashtable_full(fluid_hash_func_t hash_func,
+ fluid_equal_func_t key_equal_func,
+ fluid_destroy_notify_t key_destroy_func,
+ fluid_destroy_notify_t value_destroy_func)
{
- fluid_hashtable_t *hashtable;
+ fluid_hashtable_t *hashtable;
- hashtable = FLUID_NEW (fluid_hashtable_t);
+ hashtable = FLUID_NEW(fluid_hashtable_t);
- if (!hashtable)
- {
- FLUID_LOG (FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- hashtable->size = HASH_TABLE_MIN_SIZE;
- hashtable->nnodes = 0;
- hashtable->hash_func = hash_func ? hash_func : fluid_direct_hash;
- hashtable->key_equal_func = key_equal_func;
- hashtable->ref_count = 1;
- hashtable->key_destroy_func = key_destroy_func;
- hashtable->value_destroy_func = value_destroy_func;
- hashtable->nodes = FLUID_ARRAY (fluid_hashnode_t*, hashtable->size);
- FLUID_MEMSET (hashtable->nodes, 0, hashtable->size * sizeof (fluid_hashnode_t *));
-
- return hashtable;
+ if(!hashtable)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ hashtable->size = HASH_TABLE_MIN_SIZE;
+ hashtable->nnodes = 0;
+ hashtable->hash_func = hash_func ? hash_func : fluid_direct_hash;
+ hashtable->key_equal_func = key_equal_func;
+ fluid_atomic_int_set(&hashtable->ref_count, 1);
+ hashtable->key_destroy_func = key_destroy_func;
+ hashtable->value_destroy_func = value_destroy_func;
+ hashtable->nodes = FLUID_ARRAY(fluid_hashnode_t *, hashtable->size);
+ if(hashtable->nodes == NULL)
+ {
+ delete_fluid_hashtable(hashtable);
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+ FLUID_MEMSET(hashtable->nodes, 0, hashtable->size * sizeof(*hashtable->nodes));
+
+ return hashtable;
}
/**
@@ -411,7 +439,7 @@ new_fluid_hashtable_full (fluid_hash_func_t hash_func,
* gpointer key, value;
*
* fluid_hashtable_iter_init (&iter, hashtable);
- * while (fluid_hashtable_iter_next (&iter, &key, &value))
+ * while (fluid_hashtable_iter_next (&iter, &key, &value))
* {
* /&ast; do something with key and value &ast;/
* }
@@ -420,19 +448,19 @@ new_fluid_hashtable_full (fluid_hash_func_t hash_func,
* Since: 2.16
**/
void
-fluid_hashtable_iter_init (fluid_hashtable_iter_t *iter,
- fluid_hashtable_t *hashtable)
+fluid_hashtable_iter_init(fluid_hashtable_iter_t *iter,
+ fluid_hashtable_t *hashtable)
{
- RealIter *ri = (RealIter *) iter;
+ RealIter *ri = (RealIter *) iter;
- fluid_return_if_fail (iter != NULL);
- fluid_return_if_fail (hashtable != NULL);
+ fluid_return_if_fail(iter != NULL);
+ fluid_return_if_fail(hashtable != NULL);
- ri->hashtable = hashtable;
- ri->prev_node = NULL;
- ri->node = NULL;
- ri->position = -1;
- ri->pre_advanced = FALSE;
+ ri->hashtable = hashtable;
+ ri->prev_node = NULL;
+ ri->node = NULL;
+ ri->position = -1;
+ ri->pre_advanced = FALSE;
}
/**
@@ -450,45 +478,55 @@ fluid_hashtable_iter_init (fluid_hashtable_iter_t *iter,
* Since: 2.16
**/
int
-fluid_hashtable_iter_next (fluid_hashtable_iter_t *iter, void **key,
- void **value)
+fluid_hashtable_iter_next(fluid_hashtable_iter_t *iter, void **key,
+ void **value)
{
- RealIter *ri = (RealIter *) iter;
+ RealIter *ri = (RealIter *) iter;
- fluid_return_val_if_fail (iter != NULL, FALSE);
+ fluid_return_val_if_fail(iter != NULL, FALSE);
- if (ri->pre_advanced)
+ if(ri->pre_advanced)
{
- ri->pre_advanced = FALSE;
+ ri->pre_advanced = FALSE;
- if (ri->node == NULL)
- return FALSE;
+ if(ri->node == NULL)
+ {
+ return FALSE;
+ }
}
- else
+ else
{
- if (ri->node != NULL)
- {
- ri->prev_node = ri->node;
- ri->node = ri->node->next;
- }
-
- while (ri->node == NULL)
- {
- ri->position++;
- if (ri->position >= ri->hashtable->size)
- return FALSE;
-
- ri->prev_node = NULL;
- ri->node = ri->hashtable->nodes[ri->position];
- }
+ if(ri->node != NULL)
+ {
+ ri->prev_node = ri->node;
+ ri->node = ri->node->next;
+ }
+
+ while(ri->node == NULL)
+ {
+ ri->position++;
+
+ if(ri->position >= ri->hashtable->size)
+ {
+ return FALSE;
+ }
+
+ ri->prev_node = NULL;
+ ri->node = ri->hashtable->nodes[ri->position];
+ }
}
- if (key != NULL)
- *key = ri->node->key;
- if (value != NULL)
- *value = ri->node->value;
+ if(key != NULL)
+ {
+ *key = ri->node->key;
+ }
+
+ if(value != NULL)
+ {
+ *value = ri->node->value;
+ }
- return TRUE;
+ return TRUE;
}
/**
@@ -502,62 +540,74 @@ fluid_hashtable_iter_next (fluid_hashtable_iter_t *iter, void **key,
* Since: 2.16
**/
fluid_hashtable_t *
-fluid_hashtable_iter_get_hash_table (fluid_hashtable_iter_t *iter)
+fluid_hashtable_iter_get_hash_table(fluid_hashtable_iter_t *iter)
{
- fluid_return_val_if_fail (iter != NULL, NULL);
+ fluid_return_val_if_fail(iter != NULL, NULL);
- return ((RealIter *) iter)->hashtable;
+ return ((RealIter *) iter)->hashtable;
}
static void
-iter_remove_or_steal (RealIter *ri, int notify)
+iter_remove_or_steal(RealIter *ri, int notify)
{
- fluid_hashnode_t *prev;
- fluid_hashnode_t *node;
- int position;
+ fluid_hashnode_t *prev;
+ fluid_hashnode_t *node;
+ int position;
- fluid_return_if_fail (ri != NULL);
- fluid_return_if_fail (ri->node != NULL);
+ fluid_return_if_fail(ri != NULL);
+ fluid_return_if_fail(ri->node != NULL);
- prev = ri->prev_node;
- node = ri->node;
- position = ri->position;
+ prev = ri->prev_node;
+ node = ri->node;
+ position = ri->position;
- /* pre-advance the iterator since we will remove the node */
+ /* pre-advance the iterator since we will remove the node */
- ri->node = ri->node->next;
- /* ri->prev_node is still the correct previous node */
+ ri->node = ri->node->next;
+ /* ri->prev_node is still the correct previous node */
- while (ri->node == NULL)
+ while(ri->node == NULL)
{
- ri->position++;
- if (ri->position >= ri->hashtable->size)
- break;
+ ri->position++;
- ri->prev_node = NULL;
- ri->node = ri->hashtable->nodes[ri->position];
+ if(ri->position >= ri->hashtable->size)
+ {
+ break;
+ }
+
+ ri->prev_node = NULL;
+ ri->node = ri->hashtable->nodes[ri->position];
}
- ri->pre_advanced = TRUE;
+ ri->pre_advanced = TRUE;
- /* remove the node */
+ /* remove the node */
- if (prev != NULL)
- prev->next = node->next;
- else
- ri->hashtable->nodes[position] = node->next;
+ if(prev != NULL)
+ {
+ prev->next = node->next;
+ }
+ else
+ {
+ ri->hashtable->nodes[position] = node->next;
+ }
- if (notify)
+ if(notify)
{
- if (ri->hashtable->key_destroy_func)
- ri->hashtable->key_destroy_func(node->key);
- if (ri->hashtable->value_destroy_func)
- ri->hashtable->value_destroy_func(node->value);
+ if(ri->hashtable->key_destroy_func)
+ {
+ ri->hashtable->key_destroy_func(node->key);
+ }
+
+ if(ri->hashtable->value_destroy_func)
+ {
+ ri->hashtable->value_destroy_func(node->value);
+ }
}
- FLUID_FREE (node);
+ FLUID_FREE(node);
- ri->hashtable->nnodes--;
+ ri->hashtable->nnodes--;
}
/**
@@ -571,15 +621,15 @@ iter_remove_or_steal (RealIter *ri, int notify)
*
* If the #fluid_hashtable_t was created using fluid_hashtable_new_full(), the
* key and value are freed using the supplied destroy functions, otherwise
- * you have to make sure that any dynamically allocated values are freed
+ * you have to make sure that any dynamically allocated values are freed
* yourself.
*
* Since: 2.16
**/
void
-fluid_hashtable_iter_remove (fluid_hashtable_iter_t *iter)
+fluid_hashtable_iter_remove(fluid_hashtable_iter_t *iter)
{
- iter_remove_or_steal ((RealIter *) iter, TRUE);
+ iter_remove_or_steal((RealIter *) iter, TRUE);
}
/**
@@ -595,9 +645,9 @@ fluid_hashtable_iter_remove (fluid_hashtable_iter_t *iter)
* Since: 2.16
**/
void
-fluid_hashtable_iter_steal (fluid_hashtable_iter_t *iter)
+fluid_hashtable_iter_steal(fluid_hashtable_iter_t *iter)
{
- iter_remove_or_steal ((RealIter *) iter, FALSE);
+ iter_remove_or_steal((RealIter *) iter, FALSE);
}
@@ -612,14 +662,14 @@ fluid_hashtable_iter_steal (fluid_hashtable_iter_t *iter)
*
* Since: 2.10
**/
-fluid_hashtable_t*
-fluid_hashtable_ref (fluid_hashtable_t *hashtable)
+fluid_hashtable_t *
+fluid_hashtable_ref(fluid_hashtable_t *hashtable)
{
- fluid_return_val_if_fail (hashtable != NULL, NULL);
- fluid_return_val_if_fail (hashtable->ref_count > 0, hashtable);
+ fluid_return_val_if_fail(hashtable != NULL, NULL);
+ fluid_return_val_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0, hashtable);
- fluid_atomic_int_add (&hashtable->ref_count, 1);
- return hashtable;
+ fluid_atomic_int_add(&hashtable->ref_count, 1);
+ return hashtable;
}
/**
@@ -634,16 +684,16 @@ fluid_hashtable_ref (fluid_hashtable_t *hashtable)
* Since: 2.10
**/
void
-fluid_hashtable_unref (fluid_hashtable_t *hashtable)
+fluid_hashtable_unref(fluid_hashtable_t *hashtable)
{
- fluid_return_if_fail (hashtable != NULL);
- fluid_return_if_fail (hashtable->ref_count > 0);
+ fluid_return_if_fail(hashtable != NULL);
+ fluid_return_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0);
- if (fluid_atomic_int_exchange_and_add (&hashtable->ref_count, -1) - 1 == 0)
+ if(fluid_atomic_int_exchange_and_add(&hashtable->ref_count, -1) - 1 == 0)
{
- fluid_hashtable_remove_all_nodes (hashtable, TRUE);
- FLUID_FREE (hashtable->nodes);
- FLUID_FREE (hashtable);
+ fluid_hashtable_remove_all_nodes(hashtable, TRUE);
+ FLUID_FREE(hashtable->nodes);
+ FLUID_FREE(hashtable);
}
}
@@ -659,13 +709,13 @@ fluid_hashtable_unref (fluid_hashtable_t *hashtable)
* destruction phase.
**/
void
-delete_fluid_hashtable (fluid_hashtable_t *hashtable)
+delete_fluid_hashtable(fluid_hashtable_t *hashtable)
{
- fluid_return_if_fail (hashtable != NULL);
- fluid_return_if_fail (hashtable->ref_count > 0);
+ fluid_return_if_fail(hashtable != NULL);
+ fluid_return_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0);
- fluid_hashtable_remove_all (hashtable);
- fluid_hashtable_unref (hashtable);
+ fluid_hashtable_remove_all(hashtable);
+ fluid_hashtable_unref(hashtable);
}
/**
@@ -681,15 +731,15 @@ delete_fluid_hashtable (fluid_hashtable_t *hashtable)
* Return value: the associated value, or %NULL if the key is not found.
**/
void *
-fluid_hashtable_lookup (fluid_hashtable_t *hashtable, const void *key)
+fluid_hashtable_lookup(fluid_hashtable_t *hashtable, const void *key)
{
- fluid_hashnode_t *node;
+ fluid_hashnode_t *node;
- fluid_return_val_if_fail (hashtable != NULL, NULL);
+ fluid_return_val_if_fail(hashtable != NULL, NULL);
- node = *fluid_hashtable_lookup_node (hashtable, key, NULL);
+ node = *fluid_hashtable_lookup_node(hashtable, key, NULL);
- return node ? node->value : NULL;
+ return node ? node->value : NULL;
}
/**
@@ -707,26 +757,32 @@ fluid_hashtable_lookup (fluid_hashtable_t *hashtable, const void *key)
* Return value: %TRUE if the key was found in the #fluid_hashtable_t.
**/
int
-fluid_hashtable_lookup_extended (fluid_hashtable_t *hashtable,
- const void *lookup_key,
- void **orig_key, void **value)
+fluid_hashtable_lookup_extended(fluid_hashtable_t *hashtable,
+ const void *lookup_key,
+ void **orig_key, void **value)
{
- fluid_hashnode_t *node;
+ fluid_hashnode_t *node;
- fluid_return_val_if_fail (hashtable != NULL, FALSE);
+ fluid_return_val_if_fail(hashtable != NULL, FALSE);
- node = *fluid_hashtable_lookup_node (hashtable, lookup_key, NULL);
+ node = *fluid_hashtable_lookup_node(hashtable, lookup_key, NULL);
- if (node == NULL)
- return FALSE;
+ if(node == NULL)
+ {
+ return FALSE;
+ }
- if (orig_key)
- *orig_key = node->key;
+ if(orig_key)
+ {
+ *orig_key = node->key;
+ }
- if (value)
- *value = node->value;
+ if(value)
+ {
+ *value = node->value;
+ }
- return TRUE;
+ return TRUE;
}
/*
@@ -746,54 +802,61 @@ fluid_hashtable_lookup_extended (fluid_hashtable_t *hashtable,
* new node.
*/
static void
-fluid_hashtable_insert_internal (fluid_hashtable_t *hashtable, void *key,
- void *value, int keep_new_key)
+fluid_hashtable_insert_internal(fluid_hashtable_t *hashtable, void *key,
+ void *value, int keep_new_key)
{
- fluid_hashnode_t **node_ptr, *node;
- unsigned int key_hash;
+ fluid_hashnode_t **node_ptr, *node;
+ unsigned int key_hash;
- fluid_return_if_fail (hashtable != NULL);
- fluid_return_if_fail (hashtable->ref_count > 0);
+ fluid_return_if_fail(hashtable != NULL);
+ fluid_return_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0);
- node_ptr = fluid_hashtable_lookup_node (hashtable, key, &key_hash);
+ node_ptr = fluid_hashtable_lookup_node(hashtable, key, &key_hash);
- if ((node = *node_ptr))
+ if((node = *node_ptr))
{
- if (keep_new_key)
+ if(keep_new_key)
{
- if (hashtable->key_destroy_func)
- hashtable->key_destroy_func (node->key);
- node->key = key;
+ if(hashtable->key_destroy_func)
+ {
+ hashtable->key_destroy_func(node->key);
+ }
+
+ node->key = key;
}
- else
+ else
{
- if (hashtable->key_destroy_func)
- hashtable->key_destroy_func (key);
+ if(hashtable->key_destroy_func)
+ {
+ hashtable->key_destroy_func(key);
+ }
}
- if (hashtable->value_destroy_func)
- hashtable->value_destroy_func (node->value);
+ if(hashtable->value_destroy_func)
+ {
+ hashtable->value_destroy_func(node->value);
+ }
- node->value = value;
+ node->value = value;
}
- else
+ else
{
- node = FLUID_NEW (fluid_hashnode_t);
+ node = FLUID_NEW(fluid_hashnode_t);
- if (!node)
- {
- FLUID_LOG (FLUID_ERR, "Out of memory");
- return;
- }
+ if(!node)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return;
+ }
- node->key = key;
- node->value = value;
- node->key_hash = key_hash;
- node->next = NULL;
+ node->key = key;
+ node->value = value;
+ node->key_hash = key_hash;
+ node->next = NULL;
- *node_ptr = node;
- hashtable->nnodes++;
- fluid_hashtable_maybe_resize (hashtable);
+ *node_ptr = node;
+ hashtable->nnodes++;
+ fluid_hashtable_maybe_resize(hashtable);
}
}
@@ -812,9 +875,9 @@ fluid_hashtable_insert_internal (fluid_hashtable_t *hashtable, void *key,
* using that function.
**/
void
-fluid_hashtable_insert (fluid_hashtable_t *hashtable, void *key, void *value)
+fluid_hashtable_insert(fluid_hashtable_t *hashtable, void *key, void *value)
{
- fluid_hashtable_insert_internal (hashtable, key, value, FALSE);
+ fluid_hashtable_insert_internal(hashtable, key, value, FALSE);
}
/**
@@ -831,9 +894,9 @@ fluid_hashtable_insert (fluid_hashtable_t *hashtable, void *key, void *value)
* #fluid_hashtable_t, the old key is freed using that function.
**/
void
-fluid_hashtable_replace (fluid_hashtable_t *hashtable, void *key, void *value)
+fluid_hashtable_replace(fluid_hashtable_t *hashtable, void *key, void *value)
{
- fluid_hashtable_insert_internal (hashtable, key, value, TRUE);
+ fluid_hashtable_insert_internal(hashtable, key, value, TRUE);
}
/*
@@ -850,21 +913,24 @@ fluid_hashtable_replace (fluid_hashtable_t *hashtable, void *key, void *value)
* destroy notify handlers only if @notify is %TRUE.
*/
static int
-fluid_hashtable_remove_internal (fluid_hashtable_t *hashtable, const void *key,
- int notify)
+fluid_hashtable_remove_internal(fluid_hashtable_t *hashtable, const void *key,
+ int notify)
{
- fluid_hashnode_t **node_ptr;
+ fluid_hashnode_t **node_ptr;
+
+ fluid_return_val_if_fail(hashtable != NULL, FALSE);
- fluid_return_val_if_fail (hashtable != NULL, FALSE);
+ node_ptr = fluid_hashtable_lookup_node(hashtable, key, NULL);
- node_ptr = fluid_hashtable_lookup_node (hashtable, key, NULL);
- if (*node_ptr == NULL)
- return FALSE;
+ if(*node_ptr == NULL)
+ {
+ return FALSE;
+ }
- fluid_hashtable_remove_node (hashtable, &node_ptr, notify);
- fluid_hashtable_maybe_resize (hashtable);
+ fluid_hashtable_remove_node(hashtable, &node_ptr, notify);
+ fluid_hashtable_maybe_resize(hashtable);
- return TRUE;
+ return TRUE;
}
/**
@@ -882,9 +948,9 @@ fluid_hashtable_remove_internal (fluid_hashtable_t *hashtable, const void *key,
* Return value: %TRUE if the key was found and removed from the #fluid_hashtable_t.
**/
int
-fluid_hashtable_remove (fluid_hashtable_t *hashtable, const void *key)
+fluid_hashtable_remove(fluid_hashtable_t *hashtable, const void *key)
{
- return fluid_hashtable_remove_internal (hashtable, key, TRUE);
+ return fluid_hashtable_remove_internal(hashtable, key, TRUE);
}
/**
@@ -898,9 +964,9 @@ fluid_hashtable_remove (fluid_hashtable_t *hashtable, const void *key)
* Return value: %TRUE if the key was found and removed from the #fluid_hashtable_t.
**/
int
-fluid_hashtable_steal (fluid_hashtable_t *hashtable, const void *key)
+fluid_hashtable_steal(fluid_hashtable_t *hashtable, const void *key)
{
- return fluid_hashtable_remove_internal (hashtable, key, FALSE);
+ return fluid_hashtable_remove_internal(hashtable, key, FALSE);
}
/**
@@ -917,14 +983,15 @@ fluid_hashtable_steal (fluid_hashtable_t *hashtable, const void *key)
* Since: 2.12
**/
void
-fluid_hashtable_remove_all (fluid_hashtable_t *hashtable)
+fluid_hashtable_remove_all(fluid_hashtable_t *hashtable)
{
- fluid_return_if_fail (hashtable != NULL);
+ fluid_return_if_fail(hashtable != NULL);
- fluid_hashtable_remove_all_nodes (hashtable, TRUE);
- fluid_hashtable_maybe_resize (hashtable);
+ fluid_hashtable_remove_all_nodes(hashtable, TRUE);
+ fluid_hashtable_maybe_resize(hashtable);
}
+#if 0
/**
* fluid_hashtable_steal_all:
* @hashtable: a #fluid_hashtable_t.
@@ -935,13 +1002,14 @@ fluid_hashtable_remove_all (fluid_hashtable_t *hashtable)
* Since: 2.12
**/
void
-fluid_hashtable_steal_all (fluid_hashtable_t *hashtable)
+fluid_hashtable_steal_all(fluid_hashtable_t *hashtable)
{
- fluid_return_if_fail (hashtable != NULL);
+ fluid_return_if_fail(hashtable != NULL);
- fluid_hashtable_remove_all_nodes (hashtable, FALSE);
- fluid_hashtable_maybe_resize (hashtable);
+ fluid_hashtable_remove_all_nodes(hashtable, FALSE);
+ fluid_hashtable_maybe_resize(hashtable);
}
+#endif
/*
* fluid_hashtable_foreach_remove_or_steal:
@@ -961,27 +1029,33 @@ fluid_hashtable_steal_all (fluid_hashtable_t *hashtable)
* for each removed node.
*/
static unsigned int
-fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
- fluid_hr_func_t func, void *user_data,
- int notify)
+fluid_hashtable_foreach_remove_or_steal(fluid_hashtable_t *hashtable,
+ fluid_hr_func_t func, void *user_data,
+ int notify)
{
- fluid_hashnode_t *node, **node_ptr;
- unsigned int deleted = 0;
- int i;
+ fluid_hashnode_t *node, **node_ptr;
+ unsigned int deleted = 0;
+ int i;
- for (i = 0; i < hashtable->size; i++)
- for (node_ptr = &hashtable->nodes[i]; (node = *node_ptr) != NULL;)
- if ((* func) (node->key, node->value, user_data))
+ for(i = 0; i < hashtable->size; i++)
+ {
+ for(node_ptr = &hashtable->nodes[i]; (node = *node_ptr) != NULL;)
{
- fluid_hashtable_remove_node (hashtable, &node_ptr, notify);
- deleted++;
+ if((* func)(node->key, node->value, user_data))
+ {
+ fluid_hashtable_remove_node(hashtable, &node_ptr, notify);
+ deleted++;
+ }
+ else
+ {
+ node_ptr = &node->next;
+ }
}
- else
- node_ptr = &node->next;
+ }
- fluid_hashtable_maybe_resize (hashtable);
+ fluid_hashtable_maybe_resize(hashtable);
- return deleted;
+ return deleted;
}
#if 0
@@ -997,19 +1071,19 @@ fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
* the #fluid_hashtable_t, they are used to free the memory allocated for the removed
* keys and values.
*
- * See #fluid_hashtable_iter_t for an alternative way to loop over the
+ * See #fluid_hashtable_iter_t for an alternative way to loop over the
* key/value pairs in the hash table.
*
* Return value: the number of key/value pairs removed.
**/
static unsigned int
-fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
- fluid_hr_func_t func, void *user_data)
+fluid_hashtable_foreach_remove(fluid_hashtable_t *hashtable,
+ fluid_hr_func_t func, void *user_data)
{
- fluid_return_val_if_fail (hashtable != NULL, 0);
- fluid_return_val_if_fail (func != NULL, 0);
+ fluid_return_val_if_fail(hashtable != NULL, 0);
+ fluid_return_val_if_fail(func != NULL, 0);
- return fluid_hashtable_foreach_remove_or_steal (hashtable, func, user_data, TRUE);
+ return fluid_hashtable_foreach_remove_or_steal(hashtable, func, user_data, TRUE);
}
#endif
@@ -1023,19 +1097,19 @@ fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
* If the function returns %TRUE, then the key/value pair is removed from the
* #fluid_hashtable_t, but no key or value destroy functions are called.
*
- * See #fluid_hashtable_iter_t for an alternative way to loop over the
+ * See #fluid_hashtable_iter_t for an alternative way to loop over the
* key/value pairs in the hash table.
*
* Return value: the number of key/value pairs removed.
**/
unsigned int
-fluid_hashtable_foreach_steal (fluid_hashtable_t *hashtable,
- fluid_hr_func_t func, void *user_data)
+fluid_hashtable_foreach_steal(fluid_hashtable_t *hashtable,
+ fluid_hr_func_t func, void *user_data)
{
- fluid_return_val_if_fail (hashtable != NULL, 0);
- fluid_return_val_if_fail (func != NULL, 0);
+ fluid_return_val_if_fail(hashtable != NULL, 0);
+ fluid_return_val_if_fail(func != NULL, 0);
- return fluid_hashtable_foreach_remove_or_steal (hashtable, func, user_data, FALSE);
+ return fluid_hashtable_foreach_remove_or_steal(hashtable, func, user_data, FALSE);
}
/**
@@ -1055,18 +1129,22 @@ fluid_hashtable_foreach_steal (fluid_hashtable_t *hashtable,
* order searches in contrast to fluid_hashtable_lookup().
**/
void
-fluid_hashtable_foreach (fluid_hashtable_t *hashtable, fluid_hr_func_t func,
- void *user_data)
+fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hr_func_t func,
+ void *user_data)
{
- fluid_hashnode_t *node;
- int i;
+ fluid_hashnode_t *node;
+ int i;
- fluid_return_if_fail (hashtable != NULL);
- fluid_return_if_fail (func != NULL);
+ fluid_return_if_fail(hashtable != NULL);
+ fluid_return_if_fail(func != NULL);
- for (i = 0; i < hashtable->size; i++)
- for (node = hashtable->nodes[i]; node; node = node->next)
- (* func) (node->key, node->value, user_data);
+ for(i = 0; i < hashtable->size; i++)
+ {
+ for(node = hashtable->nodes[i]; node; node = node->next)
+ {
+ (* func)(node->key, node->value, user_data);
+ }
+ }
}
/**
@@ -1096,20 +1174,27 @@ fluid_hashtable_foreach (fluid_hashtable_t *hashtable, fluid_hr_func_t func,
* Since: 2.4
**/
void *
-fluid_hashtable_find (fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
- void *user_data)
+fluid_hashtable_find(fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
+ void *user_data)
{
- fluid_hashnode_t *node;
- int i;
+ fluid_hashnode_t *node;
+ int i;
- fluid_return_val_if_fail (hashtable != NULL, NULL);
- fluid_return_val_if_fail (predicate != NULL, NULL);
+ fluid_return_val_if_fail(hashtable != NULL, NULL);
+ fluid_return_val_if_fail(predicate != NULL, NULL);
+
+ for(i = 0; i < hashtable->size; i++)
+ {
+ for(node = hashtable->nodes[i]; node; node = node->next)
+ {
+ if(predicate(node->key, node->value, user_data))
+ {
+ return node->value;
+ }
+ }
+ }
- for (i = 0; i < hashtable->size; i++)
- for (node = hashtable->nodes[i]; node; node = node->next)
- if (predicate (node->key, node->value, user_data))
- return node->value;
- return NULL;
+ return NULL;
}
/**
@@ -1121,11 +1206,11 @@ fluid_hashtable_find (fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
* Return value: the number of key/value pairs in the #fluid_hashtable_t.
**/
unsigned int
-fluid_hashtable_size (fluid_hashtable_t *hashtable)
+fluid_hashtable_size(fluid_hashtable_t *hashtable)
{
- fluid_return_val_if_fail (hashtable != NULL, 0);
+ fluid_return_val_if_fail(hashtable != NULL, 0);
- return hashtable->nnodes;
+ return hashtable->nnodes;
}
/**
@@ -1143,20 +1228,25 @@ fluid_hashtable_size (fluid_hashtable_t *hashtable)
* Since: 2.14
*/
fluid_list_t *
-fluid_hashtable_get_keys (fluid_hashtable_t *hashtable)
+fluid_hashtable_get_keys(fluid_hashtable_t *hashtable)
{
- fluid_hashnode_t *node;
- int i;
- fluid_list_t *retval;
+ fluid_hashnode_t *node;
+ int i;
+ fluid_list_t *retval;
+
+ fluid_return_val_if_fail(hashtable != NULL, NULL);
- fluid_return_val_if_fail (hashtable != NULL, NULL);
+ retval = NULL;
- retval = NULL;
- for (i = 0; i < hashtable->size; i++)
- for (node = hashtable->nodes[i]; node; node = node->next)
- retval = fluid_list_prepend (retval, node->key);
+ for(i = 0; i < hashtable->size; i++)
+ {
+ for(node = hashtable->nodes[i]; node; node = node->next)
+ {
+ retval = fluid_list_prepend(retval, node->key);
+ }
+ }
- return retval;
+ return retval;
}
/**
@@ -1174,20 +1264,25 @@ fluid_hashtable_get_keys (fluid_hashtable_t *hashtable)
* Since: 2.14
*/
fluid_list_t *
-fluid_hashtable_get_values (fluid_hashtable_t *hashtable)
+fluid_hashtable_get_values(fluid_hashtable_t *hashtable)
{
- fluid_hashnode_t *node;
- int i;
- fluid_list_t *retval;
+ fluid_hashnode_t *node;
+ int i;
+ fluid_list_t *retval;
- fluid_return_val_if_fail (hashtable != NULL, NULL);
+ fluid_return_val_if_fail(hashtable != NULL, NULL);
- retval = NULL;
- for (i = 0; i < hashtable->size; i++)
- for (node = hashtable->nodes[i]; node; node = node->next)
- retval = fluid_list_prepend (retval, node->value);
+ retval = NULL;
- return retval;
+ for(i = 0; i < hashtable->size; i++)
+ {
+ for(node = hashtable->nodes[i]; node; node = node->next)
+ {
+ retval = fluid_list_prepend(retval, node->value);
+ }
+ }
+
+ return retval;
}
@@ -1198,20 +1293,20 @@ fluid_hashtable_get_values (fluid_hashtable_t *hashtable)
* fluid_str_equal:
* @v1: a key
* @v2: a key to compare with @v1
- *
- * Compares two strings for byte-by-byte equality and returns %TRUE
- * if they are equal. It can be passed to new_fluid_hashtable() as the
+ *
+ * Compares two strings for byte-by-byte equality and returns %TRUE
+ * if they are equal. It can be passed to new_fluid_hashtable() as the
* @key_equal_func parameter, when using strings as keys in a #Ghashtable.
*
* Returns: %TRUE if the two keys match
*/
int
-fluid_str_equal (const void *v1, const void *v2)
+fluid_str_equal(const void *v1, const void *v2)
{
- const char *string1 = v1;
- const char *string2 = v2;
-
- return strcmp (string1, string2) == 0;
+ const char *string1 = v1;
+ const char *string2 = v2;
+
+ return FLUID_STRCMP(string1, string2) == 0;
}
/**
@@ -1219,23 +1314,27 @@ fluid_str_equal (const void *v1, const void *v2)
* @v: a string key
*
* Converts a string to a hash value.
- * It can be passed to new_fluid_hashtable() as the @hash_func
+ * It can be passed to new_fluid_hashtable() as the @hash_func
* parameter, when using strings as keys in a #fluid_hashtable_t.
*
* Returns: a hash value corresponding to the key
*/
unsigned int
-fluid_str_hash (const void *v)
+fluid_str_hash(const void *v)
{
- /* 31 bit hash function */
- const signed char *p = v;
- uint32 h = *p;
+ /* 31 bit hash function */
+ const signed char *p = v;
+ uint32_t h = *p;
- if (h)
- for (p += 1; *p != '\0'; p++)
- h = (h << 5) - h + *p;
+ if(h)
+ {
+ for(p += 1; *p != '\0'; p++)
+ {
+ h = (h << 5) - h + *p;
+ }
+ }
- return h;
+ return h;
}
@@ -1250,13 +1349,13 @@ fluid_str_hash (const void *v)
* Compares two #gpointer arguments and returns %TRUE if they are equal.
* It can be passed to new_fluid_hashtable() as the @key_equal_func
* parameter, when using pointers as keys in a #fluid_hashtable_t.
- *
+ *
* Returns: %TRUE if the two keys match.
*/
int
-fluid_direct_equal (const void *v1, const void *v2)
+fluid_direct_equal(const void *v1, const void *v2)
{
- return v1 == v2;
+ return v1 == v2;
}
/**
@@ -1264,15 +1363,15 @@ fluid_direct_equal (const void *v1, const void *v2)
* @v: a void * key
*
* Converts a gpointer to a hash value.
- * It can be passed to g_hashtable_new() as the @hash_func parameter,
+ * It can be passed to g_hashtable_new() as the @hash_func parameter,
* when using pointers as keys in a #fluid_hashtable_t.
*
* Returns: a hash value corresponding to the key.
*/
unsigned int
-fluid_direct_hash (const void *v)
+fluid_direct_hash(const void *v)
{
- return FLUID_POINTER_TO_UINT (v);
+ return FLUID_POINTER_TO_UINT(v);
}
/**
@@ -1280,17 +1379,17 @@ fluid_direct_hash (const void *v)
* @v1: a pointer to a int key.
* @v2: a pointer to a int key to compare with @v1.
*
- * Compares the two #gint values being pointed to and returns
+ * Compares the two #gint values being pointed to and returns
* %TRUE if they are equal.
* It can be passed to g_hashtable_new() as the @key_equal_func
* parameter, when using pointers to integers as keys in a #fluid_hashtable_t.
- *
+ *
* Returns: %TRUE if the two keys match.
*/
int
-fluid_int_equal (const void *v1, const void *v2)
+fluid_int_equal(const void *v1, const void *v2)
{
- return *((const int*) v1) == *((const int*) v2);
+ return *((const int *) v1) == *((const int *) v2);
}
/**
@@ -1298,13 +1397,13 @@ fluid_int_equal (const void *v1, const void *v2)
* @v: a pointer to a int key
*
* Converts a pointer to a #gint to a hash value.
- * It can be passed to g_hashtable_new() as the @hash_func parameter,
+ * It can be passed to g_hashtable_new() as the @hash_func parameter,
* when using pointers to integers values as keys in a #fluid_hashtable_t.
*
* Returns: a hash value corresponding to the key.
*/
unsigned int
-fluid_int_hash (const void *v)
+fluid_int_hash(const void *v)
{
- return *(const int*) v;
+ return *(const int *) v;
}
diff --git a/libs/fluidsynth/src/fluid_hash.h b/libs/fluidsynth/src/fluid_hash.h
index 3beff0607e..96b2471be5 100644
--- a/libs/fluidsynth/src/fluid_hash.h
+++ b/libs/fluidsynth/src/fluid_hash.h
@@ -27,7 +27,7 @@
/*
* Adapted for FluidSynth use by Josh Green <jgreen@users.sourceforge.net>
* September 8, 2009 from glib 2.18.4
- *
+ *
* - Self contained (no dependencies on glib)
* - changed names to fluid_hashtable_...
*/
@@ -52,80 +52,80 @@ typedef struct _fluid_hashnode_t fluid_hashnode_t;
struct _fluid_hashnode_t
{
- void *key;
- void *value;
- fluid_hashnode_t *next;
- unsigned int key_hash;
+ void *key;
+ void *value;
+ fluid_hashnode_t *next;
+ unsigned int key_hash;
};
struct _fluid_hashtable_t
{
- int size;
- int nnodes;
- fluid_hashnode_t **nodes;
- fluid_hash_func_t hash_func;
- fluid_equal_func_t key_equal_func;
- volatile int ref_count;
- fluid_destroy_notify_t key_destroy_func;
- fluid_destroy_notify_t value_destroy_func;
- fluid_rec_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
+ int size;
+ int nnodes;
+ fluid_hashnode_t **nodes;
+ fluid_hash_func_t hash_func;
+ fluid_equal_func_t key_equal_func;
+ fluid_atomic_int_t ref_count;
+ fluid_destroy_notify_t key_destroy_func;
+ fluid_destroy_notify_t value_destroy_func;
+ fluid_rec_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
};
struct _fluid_hashtable_iter_t
{
- /*< private >*/
- void * dummy1;
- void * dummy2;
- void * dummy3;
- int dummy4;
- int dummy5; // Bool
- void * dummy6;
+ /*< private >*/
+ void *dummy1;
+ void *dummy2;
+ void *dummy3;
+ int dummy4;
+ int dummy5; // Bool
+ void *dummy6;
};
-fluid_hashtable_t* new_fluid_hashtable (fluid_hash_func_t hash_func,
- fluid_equal_func_t key_equal_func);
-fluid_hashtable_t* new_fluid_hashtable_full (fluid_hash_func_t hash_func,
- fluid_equal_func_t key_equal_func,
- fluid_destroy_notify_t key_destroy_func,
- fluid_destroy_notify_t value_destroy_func);
+fluid_hashtable_t *new_fluid_hashtable(fluid_hash_func_t hash_func,
+ fluid_equal_func_t key_equal_func);
+fluid_hashtable_t *new_fluid_hashtable_full(fluid_hash_func_t hash_func,
+ fluid_equal_func_t key_equal_func,
+ fluid_destroy_notify_t key_destroy_func,
+ fluid_destroy_notify_t value_destroy_func);
void delete_fluid_hashtable(fluid_hashtable_t *hashtable);
-void fluid_hashtable_iter_init (fluid_hashtable_iter_t *iter, fluid_hashtable_t *hashtable);
-int fluid_hashtable_iter_next (fluid_hashtable_iter_t *iter, void **key, void **value);
-fluid_hashtable_t *fluid_hashtable_iter_get_hash_table (fluid_hashtable_iter_t *iter);
-void fluid_hashtable_iter_remove (fluid_hashtable_iter_t *iter);
-void fluid_hashtable_iter_steal (fluid_hashtable_iter_t *iter);
-
-fluid_hashtable_t* fluid_hashtable_ref (fluid_hashtable_t *hashtable);
-void fluid_hashtable_unref (fluid_hashtable_t *hashtable);
-
-void *fluid_hashtable_lookup (fluid_hashtable_t *hashtable, const void *key);
-int fluid_hashtable_lookup_extended (fluid_hashtable_t *hashtable, const void *lookup_key,
- void **orig_key, void **value);
-
-void fluid_hashtable_insert (fluid_hashtable_t *hashtable, void *key, void *value);
-void fluid_hashtable_replace (fluid_hashtable_t *hashtable, void *key, void *value);
-
-int fluid_hashtable_remove (fluid_hashtable_t *hashtable, const void *key);
-int fluid_hashtable_steal (fluid_hashtable_t *hashtable, const void *key);
-void fluid_hashtable_remove_all (fluid_hashtable_t *hashtable);
-void fluid_hashtable_steal_all (fluid_hashtable_t *hashtable);
-unsigned int fluid_hashtable_foreach_steal (fluid_hashtable_t *hashtable,
- fluid_hr_func_t func, void *user_data);
-void fluid_hashtable_foreach (fluid_hashtable_t *hashtable, fluid_hr_func_t func,
- void *user_data);
-void *fluid_hashtable_find (fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
+void fluid_hashtable_iter_init(fluid_hashtable_iter_t *iter, fluid_hashtable_t *hashtable);
+int fluid_hashtable_iter_next(fluid_hashtable_iter_t *iter, void **key, void **value);
+fluid_hashtable_t *fluid_hashtable_iter_get_hash_table(fluid_hashtable_iter_t *iter);
+void fluid_hashtable_iter_remove(fluid_hashtable_iter_t *iter);
+void fluid_hashtable_iter_steal(fluid_hashtable_iter_t *iter);
+
+fluid_hashtable_t *fluid_hashtable_ref(fluid_hashtable_t *hashtable);
+void fluid_hashtable_unref(fluid_hashtable_t *hashtable);
+
+void *fluid_hashtable_lookup(fluid_hashtable_t *hashtable, const void *key);
+int fluid_hashtable_lookup_extended(fluid_hashtable_t *hashtable, const void *lookup_key,
+ void **orig_key, void **value);
+
+void fluid_hashtable_insert(fluid_hashtable_t *hashtable, void *key, void *value);
+void fluid_hashtable_replace(fluid_hashtable_t *hashtable, void *key, void *value);
+
+int fluid_hashtable_remove(fluid_hashtable_t *hashtable, const void *key);
+int fluid_hashtable_steal(fluid_hashtable_t *hashtable, const void *key);
+void fluid_hashtable_remove_all(fluid_hashtable_t *hashtable);
+void fluid_hashtable_steal_all(fluid_hashtable_t *hashtable);
+unsigned int fluid_hashtable_foreach_steal(fluid_hashtable_t *hashtable,
+ fluid_hr_func_t func, void *user_data);
+void fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hr_func_t func,
void *user_data);
-unsigned int fluid_hashtable_size (fluid_hashtable_t *hashtable);
-fluid_list_t *fluid_hashtable_get_keys (fluid_hashtable_t *hashtable);
-fluid_list_t *fluid_hashtable_get_values (fluid_hashtable_t *hashtable);
-
-int fluid_str_equal (const void *v1, const void *v2);
-unsigned int fluid_str_hash (const void *v);
-int fluid_direct_equal (const void *v1, const void *v2);
-unsigned int fluid_direct_hash (const void *v);
-int fluid_int_equal (const void *v1, const void *v2);
-unsigned int fluid_int_hash (const void *v);
+void *fluid_hashtable_find(fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
+ void *user_data);
+unsigned int fluid_hashtable_size(fluid_hashtable_t *hashtable);
+fluid_list_t *fluid_hashtable_get_keys(fluid_hashtable_t *hashtable);
+fluid_list_t *fluid_hashtable_get_values(fluid_hashtable_t *hashtable);
+
+int fluid_str_equal(const void *v1, const void *v2);
+unsigned int fluid_str_hash(const void *v);
+int fluid_direct_equal(const void *v1, const void *v2);
+unsigned int fluid_direct_hash(const void *v);
+int fluid_int_equal(const void *v1, const void *v2);
+unsigned int fluid_int_hash(const void *v);
#endif /* _FLUID_HASH_H */
diff --git a/libs/fluidsynth/src/fluid_iir_filter.c b/libs/fluidsynth/src/fluid_iir_filter.c
index 5b474692ae..0770ef62b6 100644
--- a/libs/fluidsynth/src/fluid_iir_filter.c
+++ b/libs/fluidsynth/src/fluid_iir_filter.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -23,7 +23,12 @@
#include "fluid_conv.h"
/**
- * Applies a lowpass filter with variable cutoff frequency and quality factor.
+ * Applies a low- or high-pass filter with variable cutoff frequency and quality factor
+ * for a given biquad transfer function:
+ * b0 + b1*z^-1 + b2*z^-2
+ * H(z) = ------------------------
+ * a0 + a1*z^-1 + a2*z^-2
+ *
* Also modifies filter state accordingly.
* @param iir_filter Filter parameter
* @param dsp_buf Pointer to the synthesized audio data
@@ -31,271 +36,384 @@
*/
/*
* Variable description:
- * - dsp_a1, dsp_a2, dsp_b0, dsp_b1, dsp_b2: Filter coefficients
+ * - dsp_a1, dsp_a2: Filter coefficients for the the previously filtered output signal
+ * - dsp_b0, dsp_b1, dsp_b2: Filter coefficients for input signal
+ * - coefficients normalized to a0
*
* A couple of variables are used internally, their results are discarded:
* - dsp_i: Index through the output buffer
- * - dsp_phase_fractional: The fractional part of dsp_phase
- * - dsp_coeff: A table of four coefficients, depending on the fractional phase.
- * Used to interpolate between samples.
- * - dsp_process_buffer: Holds the processed signal between stages
* - dsp_centernode: delay line for the IIR filter
* - dsp_hist1: same
* - dsp_hist2: same
*/
-void
-fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
+void
+fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter,
fluid_real_t *dsp_buf, int count)
{
- /* IIR filter sample history */
- fluid_real_t dsp_hist1 = iir_filter->hist1;
- fluid_real_t dsp_hist2 = iir_filter->hist2;
-
- /* IIR filter coefficients */
- fluid_real_t dsp_a1 = iir_filter->a1;
- fluid_real_t dsp_a2 = iir_filter->a2;
- fluid_real_t dsp_b02 = iir_filter->b02;
- fluid_real_t dsp_b1 = iir_filter->b1;
- int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count;
+ if(iir_filter->type == FLUID_IIR_DISABLED || iir_filter->q_lin == 0)
+ {
+ return;
+ }
+ else
+ {
+ /* IIR filter sample history */
+ fluid_real_t dsp_hist1 = iir_filter->hist1;
+ fluid_real_t dsp_hist2 = iir_filter->hist2;
+
+ /* IIR filter coefficients */
+ fluid_real_t dsp_a1 = iir_filter->a1;
+ fluid_real_t dsp_a2 = iir_filter->a2;
+ fluid_real_t dsp_b02 = iir_filter->b02;
+ fluid_real_t dsp_b1 = iir_filter->b1;
+ int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count;
+
+ fluid_real_t dsp_centernode;
+ int dsp_i;
+
+ /* filter (implement the voice filter according to SoundFont standard) */
+
+ /* Check for denormal number (too close to zero). */
+ if(fabs(dsp_hist1) < 1e-20)
+ {
+ dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */
+ }
- fluid_real_t dsp_centernode;
- int dsp_i;
+ /* Two versions of the filter loop. One, while the filter is
+ * changing towards its new setting. The other, if the filter
+ * doesn't change.
+ */
+
+ if(dsp_filter_coeff_incr_count > 0)
+ {
+ fluid_real_t dsp_a1_incr = iir_filter->a1_incr;
+ fluid_real_t dsp_a2_incr = iir_filter->a2_incr;
+ fluid_real_t dsp_b02_incr = iir_filter->b02_incr;
+ fluid_real_t dsp_b1_incr = iir_filter->b1_incr;
+
+
+ /* Increment is added to each filter coefficient filter_coeff_incr_count times. */
+ for(dsp_i = 0; dsp_i < count; dsp_i++)
+ {
+ /* The filter is implemented in Direct-II form. */
+ dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
+ dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
+ dsp_hist2 = dsp_hist1;
+ dsp_hist1 = dsp_centernode;
+
+ if(dsp_filter_coeff_incr_count-- > 0)
+ {
+ fluid_real_t old_b02 = dsp_b02;
+ dsp_a1 += dsp_a1_incr;
+ dsp_a2 += dsp_a2_incr;
+ dsp_b02 += dsp_b02_incr;
+ dsp_b1 += dsp_b1_incr;
+
+ /* Compensate history to avoid the filter going havoc with large frequency changes */
+ if(iir_filter->compensate_incr && fabs(dsp_b02) > 0.001)
+ {
+ fluid_real_t compensate = old_b02 / dsp_b02;
+ dsp_hist1 *= compensate;
+ dsp_hist2 *= compensate;
+ }
+ }
+ } /* for dsp_i */
+ }
+ else /* The filter parameters are constant. This is duplicated to save time. */
+ {
+ for(dsp_i = 0; dsp_i < count; dsp_i++)
+ {
+ /* The filter is implemented in Direct-II form. */
+ dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
+ dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
+ dsp_hist2 = dsp_hist1;
+ dsp_hist1 = dsp_centernode;
+ }
+ }
- /* filter (implement the voice filter according to SoundFont standard) */
+ iir_filter->hist1 = dsp_hist1;
+ iir_filter->hist2 = dsp_hist2;
+ iir_filter->a1 = dsp_a1;
+ iir_filter->a2 = dsp_a2;
+ iir_filter->b02 = dsp_b02;
+ iir_filter->b1 = dsp_b1;
+ iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
- /* Check for denormal number (too close to zero). */
- if (fabs (dsp_hist1) < 1e-20) dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */
+ fluid_check_fpe("voice_filter");
+ }
+}
- /* Two versions of the filter loop. One, while the filter is
- * changing towards its new setting. The other, if the filter
- * doesn't change.
- */
- if (dsp_filter_coeff_incr_count > 0)
- {
- fluid_real_t dsp_a1_incr = iir_filter->a1_incr;
- fluid_real_t dsp_a2_incr = iir_filter->a2_incr;
- fluid_real_t dsp_b02_incr = iir_filter->b02_incr;
- fluid_real_t dsp_b1_incr = iir_filter->b1_incr;
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init)
+{
+ fluid_iir_filter_t *iir_filter = obj;
+ enum fluid_iir_filter_type type = param[0].i;
+ enum fluid_iir_filter_flags flags = param[1].i;
+ iir_filter->type = type;
+ iir_filter->flags = flags;
- /* Increment is added to each filter coefficient filter_coeff_incr_count times. */
- for (dsp_i = 0; dsp_i < count; dsp_i++)
+ if(type != FLUID_IIR_DISABLED)
{
- /* The filter is implemented in Direct-II form. */
- dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
- dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
- dsp_hist2 = dsp_hist1;
- dsp_hist1 = dsp_centernode;
-
- if (dsp_filter_coeff_incr_count-- > 0)
- {
- fluid_real_t old_b02 = dsp_b02;
- dsp_a1 += dsp_a1_incr;
- dsp_a2 += dsp_a2_incr;
- dsp_b02 += dsp_b02_incr;
- dsp_b1 += dsp_b1_incr;
-
- /* Compensate history to avoid the filter going havoc with large frequency changes */
- if (iir_filter->compensate_incr && fabs(dsp_b02) > 0.001) {
- fluid_real_t compensate = old_b02 / dsp_b02;
- dsp_centernode *= compensate;
- dsp_hist1 *= compensate;
- dsp_hist2 *= compensate;
- }
- }
- } /* for dsp_i */
- }
- else /* The filter parameters are constant. This is duplicated to save time. */
- {
- for (dsp_i = 0; dsp_i < count; dsp_i++)
- { /* The filter is implemented in Direct-II form. */
- dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
- dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
- dsp_hist2 = dsp_hist1;
- dsp_hist1 = dsp_centernode;
+ fluid_iir_filter_reset(iir_filter);
}
- }
-
- iir_filter->hist1 = dsp_hist1;
- iir_filter->hist2 = dsp_hist2;
- iir_filter->a1 = dsp_a1;
- iir_filter->a2 = dsp_a2;
- iir_filter->b02 = dsp_b02;
- iir_filter->b1 = dsp_b1;
- iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
-
- fluid_check_fpe ("voice_filter");
}
-
-void
-fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter)
+void
+fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter)
{
- iir_filter->hist1 = 0;
- iir_filter->hist2 = 0;
- iir_filter->last_fres = -1.;
- iir_filter->filter_startup = 1;
+ iir_filter->hist1 = 0;
+ iir_filter->hist2 = 0;
+ iir_filter->last_fres = -1.;
+ iir_filter->q_lin = 0;
+ iir_filter->filter_startup = 1;
}
-void
-fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
- fluid_real_t fres)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres)
{
- iir_filter->fres = fres;
- iir_filter->last_fres = -1.;
-}
+ fluid_iir_filter_t *iir_filter = obj;
+ fluid_real_t fres = param[0].real;
+ iir_filter->fres = fres;
+ iir_filter->last_fres = -1.;
+}
-void
-fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
- fluid_real_t q_dB)
+static fluid_real_t fluid_iir_filter_q_from_dB(fluid_real_t q_dB)
{
+ /* The generator contains 'centibels' (1/10 dB) => divide by 10 to
+ * obtain dB */
+ q_dB /= 10.0f;
+
+ /* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */
+ fluid_clip(q_dB, 0.0f, 96.0f);
+
+ /* Short version: Modify the Q definition in a way, that a Q of 0
+ * dB leads to no resonance hump in the freq. response.
+ *
+ * Long version: From SF2.01, page 39, item 9 (initialFilterQ):
+ * "The gain at the cutoff frequency may be less than zero when
+ * zero is specified". Assume q_dB=0 / q_lin=1: If we would leave
+ * q as it is, then this results in a 3 dB hump slightly below
+ * fc. At fc, the gain is exactly the DC gain (0 dB). What is
+ * (probably) meant here is that the filter does not show a
+ * resonance hump for q_dB=0. In this case, the corresponding
+ * q_lin is 1/sqrt(2)=0.707. The filter should have 3 dB of
+ * attenuation at fc now. In this case Q_dB is the height of the
+ * resonance peak not over the DC gain, but over the frequency
+ * response of a non-resonant filter. This idea is implemented as
+ * follows: */
+ q_dB -= 3.01f;
+
/* The 'sound font' Q is defined in dB. The filter needs a linear
q. Convert. */
- iir_filter->q_lin = (fluid_real_t) (pow(10.0f, q_dB / 20.0f));
+ return pow(10.0f, q_dB / 20.0f);
+}
- /* SF 2.01 page 59:
- *
- * The SoundFont specs ask for a gain reduction equal to half the
- * height of the resonance peak (Q). For example, for a 10 dB
- * resonance peak, the gain is reduced by 5 dB. This is done by
- * multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
- * by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
- * The gain is later factored into the 'b' coefficients
- * (numerator of the filter equation). This gain factor depends
- * only on Q, so this is the right place to calculate it.
- */
- iir_filter->filter_gain = (fluid_real_t) (1.0 / sqrt(iir_filter->q_lin));
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q)
+{
+ fluid_iir_filter_t *iir_filter = obj;
+ fluid_real_t q = param[0].real;
+ int flags = iir_filter->flags;
+
+ if(flags & FLUID_IIR_Q_ZERO_OFF && q <= 0.0)
+ {
+ q = 0;
+ }
+ else if(flags & FLUID_IIR_Q_LINEAR)
+ {
+ /* q is linear (only for user-defined filter)
+ * increase to avoid Q being somewhere between zero and one,
+ * which results in some strange amplified lowpass signal
+ */
+ q++;
+ }
+ else
+ {
+ q = fluid_iir_filter_q_from_dB(q);
+ }
+
+ iir_filter->q_lin = q;
+ iir_filter->filter_gain = 1.0;
+
+ if(!(flags & FLUID_IIR_NO_GAIN_AMP))
+ {
+ /* SF 2.01 page 59:
+ *
+ * The SoundFont specs ask for a gain reduction equal to half the
+ * height of the resonance peak (Q). For example, for a 10 dB
+ * resonance peak, the gain is reduced by 5 dB. This is done by
+ * multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
+ * by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
+ * The gain is later factored into the 'b' coefficients
+ * (numerator of the filter equation). This gain factor depends
+ * only on Q, so this is the right place to calculate it.
+ */
+ iir_filter->filter_gain /= sqrt(q);
+ }
/* The synthesis loop will have to recalculate the filter coefficients. */
iir_filter->last_fres = -1.;
-
}
-
-static inline void
-fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter,
- int transition_samples,
+static FLUID_INLINE void
+fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter,
+ int transition_samples,
fluid_real_t output_rate)
{
+ /* FLUID_IIR_Q_LINEAR may switch the filter off by setting Q==0 */
+ if(iir_filter->q_lin == 0)
+ {
+ return;
+ }
+ else
+ {
+ /*
+ * Those equations from Robert Bristow-Johnson's `Cookbook
+ * formulae for audio EQ biquad filter coefficients', obtained
+ * from Harmony-central.com / Computer / Programming. They are
+ * the result of the bilinear transform on an analogue filter
+ * prototype. To quote, `BLT frequency warping has been taken
+ * into account for both significant frequency relocation and for
+ * bandwidth readjustment'. */
+
+ fluid_real_t omega = (fluid_real_t)(2.0 * M_PI *
+ (iir_filter->last_fres / ((float) output_rate)));
+ fluid_real_t sin_coeff = (fluid_real_t) sin(omega);
+ fluid_real_t cos_coeff = (fluid_real_t) cos(omega);
+ fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->q_lin);
+ fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff);
+
+ /* Calculate the filter coefficients. All coefficients are
+ * normalized by a0. Think of `a1' as `a1/a0'.
+ *
+ * Here a couple of multiplications are saved by reusing common expressions.
+ * The original equations should be:
+ * iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain;
+ * iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
+ * iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */
+
+ /* "a" coeffs are same for all 3 available filter types */
+ fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
+ fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
+
+ fluid_real_t b02_temp, b1_temp;
+
+ switch(iir_filter->type)
+ {
+ case FLUID_IIR_HIGHPASS:
+ b1_temp = (1.0f + cos_coeff) * a0_inv * iir_filter->filter_gain;
+
+ /* both b0 -and- b2 */
+ b02_temp = b1_temp * 0.5f;
+
+ b1_temp *= -1.0f;
+ break;
+
+ case FLUID_IIR_LOWPASS:
+ b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain;
+
+ /* both b0 -and- b2 */
+ b02_temp = b1_temp * 0.5f;
+ break;
+
+ default:
+ /* filter disabled, should never get here */
+ return;
+ }
- /*
- * Those equations from Robert Bristow-Johnson's `Cookbook
- * formulae for audio EQ biquad filter coefficients', obtained
- * from Harmony-central.com / Computer / Programming. They are
- * the result of the bilinear transform on an analogue filter
- * prototype. To quote, `BLT frequency warping has been taken
- * into account for both significant frequency relocation and for
- * bandwidth readjustment'. */
-
- fluid_real_t omega = (fluid_real_t) (2.0 * M_PI *
- (iir_filter->last_fres / ((float) output_rate)));
- fluid_real_t sin_coeff = (fluid_real_t) sin(omega);
- fluid_real_t cos_coeff = (fluid_real_t) cos(omega);
- fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->q_lin);
- fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff);
-
- /* Calculate the filter coefficients. All coefficients are
- * normalized by a0. Think of `a1' as `a1/a0'.
- *
- * Here a couple of multiplications are saved by reusing common expressions.
- * The original equations should be:
- * iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain;
- * iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
- * iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */
-
- fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
- fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
- fluid_real_t b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain;
- /* both b0 -and- b2 */
- fluid_real_t b02_temp = b1_temp * 0.5f;
-
- iir_filter->compensate_incr = 0;
-
- if (iir_filter->filter_startup || (transition_samples == 0))
- {
- /* The filter is calculated, because the voice was started up.
- * In this case set the filter coefficients without delay.
- */
- iir_filter->a1 = a1_temp;
- iir_filter->a2 = a2_temp;
- iir_filter->b02 = b02_temp;
- iir_filter->b1 = b1_temp;
- iir_filter->filter_coeff_incr_count = 0;
- iir_filter->filter_startup = 0;
+ iir_filter->compensate_incr = 0;
+
+ if(iir_filter->filter_startup || (transition_samples == 0))
+ {
+ /* The filter is calculated, because the voice was started up.
+ * In this case set the filter coefficients without delay.
+ */
+ iir_filter->a1 = a1_temp;
+ iir_filter->a2 = a2_temp;
+ iir_filter->b02 = b02_temp;
+ iir_filter->b1 = b1_temp;
+ iir_filter->filter_coeff_incr_count = 0;
+ iir_filter->filter_startup = 0;
// printf("Setting initial filter coefficients.\n");
- }
- else
- {
-
- /* The filter frequency is changed. Calculate an increment
- * factor, so that the new setting is reached after one buffer
- * length. x_incr is added to the current value FLUID_BUFSIZE
- * times. The length is arbitrarily chosen. Longer than one
- * buffer will sacrifice some performance, though. Note: If
- * the filter is still too 'grainy', then increase this number
- * at will.
- */
-
- iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples;
- iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples;
- iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples;
- iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples;
- if (fabs(iir_filter->b02) > 0.0001) {
- fluid_real_t quota = b02_temp / iir_filter->b02;
- iir_filter->compensate_incr = quota < 0.5 || quota > 2;
+ }
+ else
+ {
+
+ /* The filter frequency is changed. Calculate an increment
+ * factor, so that the new setting is reached after one buffer
+ * length. x_incr is added to the current value FLUID_BUFSIZE
+ * times. The length is arbitrarily chosen. Longer than one
+ * buffer will sacrifice some performance, though. Note: If
+ * the filter is still too 'grainy', then increase this number
+ * at will.
+ */
+
+ iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples;
+ iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples;
+ iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples;
+ iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples;
+
+ if(fabs(iir_filter->b02) > 0.0001)
+ {
+ fluid_real_t quota = b02_temp / iir_filter->b02;
+ iir_filter->compensate_incr = quota < 0.5 || quota > 2;
+ }
+
+ /* Have to add the increments filter_coeff_incr_count times. */
+ iir_filter->filter_coeff_incr_count = transition_samples;
+ }
+
+ fluid_check_fpe("voice_write filter calculation");
}
- /* Have to add the increments filter_coeff_incr_count times. */
- iir_filter->filter_coeff_incr_count = transition_samples;
- }
- fluid_check_fpe ("voice_write filter calculation");
}
-void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
- fluid_real_t output_rate,
+void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter,
+ fluid_real_t output_rate,
fluid_real_t fres_mod)
{
- fluid_real_t fres;
-
- /* calculate the frequency of the resonant filter in Hz */
- fres = fluid_ct2hz(iir_filter->fres + fres_mod);
-
- /* FIXME - Still potential for a click during turn on, can we interpolate
- between 20khz cutoff and 0 Q? */
-
- /* I removed the optimization of turning the filter off when the
- * resonance frequence is above the maximum frequency. Instead, the
- * filter frequency is set to a maximum of 0.45 times the sampling
- * rate. For a 44100 kHz sampling rate, this amounts to 19845
- * Hz. The reason is that there were problems with anti-aliasing when the
- * synthesizer was run at lower sampling rates. Thanks to Stephan
- * Tassart for pointing me to this bug. By turning the filter on and
- * clipping the maximum filter frequency at 0.45*srate, the filter
- * is used as an anti-aliasing filter. */
-
- if (fres > 0.45f * output_rate)
- fres = 0.45f * output_rate;
- else if (fres < 5)
- fres = 5;
-
- /* if filter enabled and there is a significant frequency change.. */
- if ((abs (fres - iir_filter->last_fres) > 0.01))
- {
- /* The filter coefficients have to be recalculated (filter
- * parameters have changed). Recalculation for various reasons is
- * forced by setting last_fres to -1. The flag filter_startup
- * indicates, that the DSP loop runs for the first time, in this
- * case, the filter is set directly, instead of smoothly fading
- * between old and new settings. */
- iir_filter->last_fres = fres;
- fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE,
- output_rate);
- }
-
-
- fluid_check_fpe ("voice_write DSP coefficients");
+ fluid_real_t fres;
+
+ /* calculate the frequency of the resonant filter in Hz */
+ fres = fluid_ct2hz(iir_filter->fres + fres_mod);
+
+ /* FIXME - Still potential for a click during turn on, can we interpolate
+ between 20khz cutoff and 0 Q? */
+
+ /* I removed the optimization of turning the filter off when the
+ * resonance frequence is above the maximum frequency. Instead, the
+ * filter frequency is set to a maximum of 0.45 times the sampling
+ * rate. For a 44100 kHz sampling rate, this amounts to 19845
+ * Hz. The reason is that there were problems with anti-aliasing when the
+ * synthesizer was run at lower sampling rates. Thanks to Stephan
+ * Tassart for pointing me to this bug. By turning the filter on and
+ * clipping the maximum filter frequency at 0.45*srate, the filter
+ * is used as an anti-aliasing filter. */
+
+ if(fres > 0.45f * output_rate)
+ {
+ fres = 0.45f * output_rate;
+ }
+ else if(fres < 5)
+ {
+ fres = 5;
+ }
+
+ /* if filter enabled and there is a significant frequency change.. */
+ if(iir_filter->type != FLUID_IIR_DISABLED && fabs(fres - iir_filter->last_fres) > 0.01)
+ {
+ /* The filter coefficients have to be recalculated (filter
+ * parameters have changed). Recalculation for various reasons is
+ * forced by setting last_fres to -1. The flag filter_startup
+ * indicates, that the DSP loop runs for the first time, in this
+ * case, the filter is set directly, instead of smoothly fading
+ * between old and new settings. */
+ iir_filter->last_fres = fres;
+ fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE,
+ output_rate);
+ }
+
+
+ fluid_check_fpe("voice_write DSP coefficients");
}
diff --git a/libs/fluidsynth/src/fluid_iir_filter.h b/libs/fluidsynth/src/fluid_iir_filter.h
index 7dc5de14a5..355d197f1c 100644
--- a/libs/fluidsynth/src/fluid_iir_filter.h
+++ b/libs/fluidsynth/src/fluid_iir_filter.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -25,50 +25,50 @@
typedef struct _fluid_iir_filter_t fluid_iir_filter_t;
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q);
-void fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
- fluid_real_t *dsp_buf, int dsp_buf_count);
+void fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter,
+ fluid_real_t *dsp_buf, int dsp_buf_count);
-void fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter);
+void fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter);
-void fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
- fluid_real_t q_dB);
-
-void fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
- fluid_real_t fres);
-
-void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
- fluid_real_t output_rate,
- fluid_real_t fres_mod);
+void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter,
+ fluid_real_t output_rate,
+ fluid_real_t fres_mod);
/* We can't do information hiding here, as fluid_voice_t includes the struct
without a pointer. */
struct _fluid_iir_filter_t
{
- /* filter coefficients */
- /* The coefficients are normalized to a0. */
- /* b0 and b2 are identical => b02 */
- fluid_real_t b02; /* b0 / a0 */
- fluid_real_t b1; /* b1 / a0 */
- fluid_real_t a1; /* a0 / a0 */
- fluid_real_t a2; /* a1 / a0 */
+ enum fluid_iir_filter_type type; /* specifies the type of this filter */
+ enum fluid_iir_filter_flags flags; /* additional flags to customize this filter */
+
+ /* filter coefficients */
+ /* The coefficients are normalized to a0. */
+ /* b0 and b2 are identical => b02 */
+ fluid_real_t b02; /* b0 / a0 */
+ fluid_real_t b1; /* b1 / a0 */
+ fluid_real_t a1; /* a0 / a0 */
+ fluid_real_t a2; /* a1 / a0 */
- fluid_real_t b02_incr;
- fluid_real_t b1_incr;
- fluid_real_t a1_incr;
- fluid_real_t a2_incr;
- int filter_coeff_incr_count;
- int compensate_incr; /* Flag: If set, must compensate history */
- fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
- int filter_startup; /* Flag: If set, the filter will be set directly.
+ fluid_real_t b02_incr;
+ fluid_real_t b1_incr;
+ fluid_real_t a1_incr;
+ fluid_real_t a2_incr;
+ int filter_coeff_incr_count;
+ int compensate_incr; /* Flag: If set, must compensate history */
+ fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
+ int filter_startup; /* Flag: If set, the filter will be set directly.
Else it changes smoothly. */
- fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
- fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
- /* Serves as a flag: A deviation between fres and last_fres */
- /* indicates, that the filter has to be recalculated. */
- fluid_real_t q_lin; /* the q-factor on a linear scale */
- fluid_real_t filter_gain; /* Gain correction factor, depends on q */
+ fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
+ fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
+ /* Serves as a flag: A deviation between fres and last_fres */
+ /* indicates, that the filter has to be recalculated. */
+ fluid_real_t q_lin; /* the q-factor on a linear scale */
+ fluid_real_t filter_gain; /* Gain correction factor, depends on q */
};
#endif
diff --git a/libs/fluidsynth/src/fluid_lfo.c b/libs/fluidsynth/src/fluid_lfo.c
index ff178e0012..ae21cdd0f7 100644
--- a/libs/fluidsynth/src/fluid_lfo.c
+++ b/libs/fluidsynth/src/fluid_lfo.c
@@ -1,13 +1,17 @@
#include "fluid_lfo.h"
-void
-fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t increment)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_incr)
{
- lfo->increment = increment;
+ fluid_lfo_t *lfo = obj;
+ fluid_real_t increment = param[0].real;
+
+ lfo->increment = increment;
}
-void
-fluid_lfo_set_delay(fluid_lfo_t* lfo, unsigned int delay)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_delay)
{
- lfo->delay = delay;
+ fluid_lfo_t *lfo = obj;
+ unsigned int delay = param[0].i;
+
+ lfo->delay = delay;
}
diff --git a/libs/fluidsynth/src/fluid_lfo.h b/libs/fluidsynth/src/fluid_lfo.h
index e9440cf526..b9a9ca6eaa 100644
--- a/libs/fluidsynth/src/fluid_lfo.h
+++ b/libs/fluidsynth/src/fluid_lfo.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -21,50 +21,53 @@
#ifndef _FLUID_LFO_H
#define _FLUID_LFO_H
-#include "fluidsynth_priv.h"
+#include "fluid_sys.h"
typedef struct _fluid_lfo_t fluid_lfo_t;
-struct _fluid_lfo_t {
- fluid_real_t val; /* the current value of the LFO */
- unsigned int delay; /* the delay of the lfo in samples */
- fluid_real_t increment; /* the lfo frequency is converted to a per-buffer increment */
+struct _fluid_lfo_t
+{
+ fluid_real_t val; /* the current value of the LFO */
+ unsigned int delay; /* the delay of the lfo in samples */
+ fluid_real_t increment; /* the lfo frequency is converted to a per-buffer increment */
};
-static inline void
-fluid_lfo_reset(fluid_lfo_t* lfo)
+static FLUID_INLINE void
+fluid_lfo_reset(fluid_lfo_t *lfo)
{
- lfo->val = 0.0f;
+ lfo->val = 0.0f;
}
// These two cannot be inlined since they're used by event_dispatch
-void fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t increment);
-void fluid_lfo_set_delay(fluid_lfo_t* lfo, unsigned int delay);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_incr);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_delay);
-static inline fluid_real_t
-fluid_lfo_get_val(fluid_lfo_t* lfo)
+static FLUID_INLINE fluid_real_t
+fluid_lfo_get_val(fluid_lfo_t *lfo)
{
- return lfo->val;
+ return lfo->val;
}
-static inline void
-fluid_lfo_calc(fluid_lfo_t* lfo, unsigned int cur_delay)
+static FLUID_INLINE void
+fluid_lfo_calc(fluid_lfo_t *lfo, unsigned int cur_delay)
{
- if (cur_delay < lfo->delay)
- return;
-
- lfo->val += lfo->increment;
-
- if (lfo->val > (fluid_real_t) 1.0)
- {
- lfo->increment = -lfo->increment;
- lfo->val = (fluid_real_t) 2.0 - lfo->val;
- }
- else if (lfo->val < (fluid_real_t) -1.0)
- {
- lfo->increment = -lfo->increment;
- lfo->val = (fluid_real_t) -2.0 - lfo->val;
- }
+ if(cur_delay < lfo->delay)
+ {
+ return;
+ }
+
+ lfo->val += lfo->increment;
+
+ if(lfo->val > (fluid_real_t) 1.0)
+ {
+ lfo->increment = -lfo->increment;
+ lfo->val = (fluid_real_t) 2.0 - lfo->val;
+ }
+ else if(lfo->val < (fluid_real_t) -1.0)
+ {
+ lfo->increment = -lfo->increment;
+ lfo->val = (fluid_real_t) -2.0 - lfo->val;
+ }
}
diff --git a/libs/fluidsynth/src/fluid_list.c b/libs/fluidsynth/src/fluid_list.c
index dd47a39e0e..c92d731f89 100644
--- a/libs/fluidsynth/src/fluid_list.c
+++ b/libs/fluidsynth/src/fluid_list.c
@@ -2,16 +2,16 @@
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02110-1301, USA.
@@ -26,243 +26,296 @@
+#include "fluid_sys.h"
#include "fluid_list.h"
-fluid_list_t*
+fluid_list_t *
new_fluid_list(void)
{
- fluid_list_t* list;
- list = (fluid_list_t*) FLUID_MALLOC(sizeof(fluid_list_t));
- list->data = NULL;
- list->next = NULL;
- return list;
+ fluid_list_t *list;
+ list = (fluid_list_t *) FLUID_MALLOC(sizeof(fluid_list_t));
+ list->data = NULL;
+ list->next = NULL;
+ return list;
}
void
delete_fluid_list(fluid_list_t *list)
{
- fluid_list_t *next;
- while (list) {
- next = list->next;
- FLUID_FREE(list);
- list = next;
- }
+ fluid_list_t *next;
+ fluid_return_if_fail(list != NULL);
+
+ while(list)
+ {
+ next = list->next;
+ FLUID_FREE(list);
+ list = next;
+ }
}
void
delete1_fluid_list(fluid_list_t *list)
{
- if (list) {
FLUID_FREE(list);
- }
}
-fluid_list_t*
-fluid_list_append(fluid_list_t *list, void* data)
+fluid_list_t *
+fluid_list_append(fluid_list_t *list, void *data)
{
- fluid_list_t *new_list;
- fluid_list_t *last;
+ fluid_list_t *new_list;
+ fluid_list_t *last;
- new_list = new_fluid_list();
- new_list->data = data;
+ new_list = new_fluid_list();
+ new_list->data = data;
- if (list)
+ if(list)
{
- last = fluid_list_last(list);
- /* g_assert (last != NULL); */
- last->next = new_list;
+ last = fluid_list_last(list);
+ /* g_assert (last != NULL); */
+ last->next = new_list;
- return list;
+ return list;
+ }
+ else
+ {
+ return new_list;
}
- else
- return new_list;
}
-fluid_list_t*
-fluid_list_prepend(fluid_list_t *list, void* data)
+fluid_list_t *
+fluid_list_prepend(fluid_list_t *list, void *data)
{
- fluid_list_t *new_list;
+ fluid_list_t *new_list;
- new_list = new_fluid_list();
- new_list->data = data;
- new_list->next = list;
+ new_list = new_fluid_list();
+ new_list->data = data;
+ new_list->next = list;
- return new_list;
+ return new_list;
}
-fluid_list_t*
+fluid_list_t *
fluid_list_nth(fluid_list_t *list, int n)
{
- while ((n-- > 0) && list) {
- list = list->next;
- }
+ while((n-- > 0) && list)
+ {
+ list = list->next;
+ }
- return list;
+ return list;
}
-fluid_list_t*
-fluid_list_remove(fluid_list_t *list, void* data)
+fluid_list_t *
+fluid_list_remove(fluid_list_t *list, void *data)
{
- fluid_list_t *tmp;
- fluid_list_t *prev;
-
- prev = NULL;
- tmp = list;
-
- while (tmp) {
- if (tmp->data == data) {
- if (prev) {
- prev->next = tmp->next;
- }
- if (list == tmp) {
- list = list->next;
- }
- tmp->next = NULL;
- delete_fluid_list(tmp);
-
- break;
- }
+ fluid_list_t *tmp;
+ fluid_list_t *prev;
- prev = tmp;
- tmp = tmp->next;
- }
+ prev = NULL;
+ tmp = list;
- return list;
+ while(tmp)
+ {
+ if(tmp->data == data)
+ {
+ if(prev)
+ {
+ prev->next = tmp->next;
+ }
+
+ if(list == tmp)
+ {
+ list = list->next;
+ }
+
+ tmp->next = NULL;
+ delete_fluid_list(tmp);
+
+ break;
+ }
+
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ return list;
}
-fluid_list_t*
+fluid_list_t *
fluid_list_remove_link(fluid_list_t *list, fluid_list_t *link)
{
- fluid_list_t *tmp;
- fluid_list_t *prev;
-
- prev = NULL;
- tmp = list;
-
- while (tmp) {
- if (tmp == link) {
- if (prev) {
- prev->next = tmp->next;
- }
- if (list == tmp) {
- list = list->next;
- }
- tmp->next = NULL;
- break;
- }
+ fluid_list_t *tmp;
+ fluid_list_t *prev;
+
+ prev = NULL;
+ tmp = list;
- prev = tmp;
- tmp = tmp->next;
- }
+ while(tmp)
+ {
+ if(tmp == link)
+ {
+ if(prev)
+ {
+ prev->next = tmp->next;
+ }
+
+ if(list == tmp)
+ {
+ list = list->next;
+ }
+
+ tmp->next = NULL;
+ break;
+ }
+
+ prev = tmp;
+ tmp = tmp->next;
+ }
- return list;
+ return list;
}
-static fluid_list_t*
+static fluid_list_t *
fluid_list_sort_merge(fluid_list_t *l1, fluid_list_t *l2, fluid_compare_func_t compare_func)
{
- fluid_list_t list, *l;
+ fluid_list_t list, *l;
- l = &list;
+ l = &list;
- while (l1 && l2) {
- if (compare_func(l1->data,l2->data) < 0) {
- l = l->next = l1;
- l1 = l1->next;
- } else {
- l = l->next = l2;
- l2 = l2->next;
+ while(l1 && l2)
+ {
+ if(compare_func(l1->data, l2->data) < 0)
+ {
+ l = l->next = l1;
+ l1 = l1->next;
+ }
+ else
+ {
+ l = l->next = l2;
+ l2 = l2->next;
+ }
}
- }
- l->next= l1 ? l1 : l2;
- return list.next;
+ l->next = l1 ? l1 : l2;
+
+ return list.next;
}
-fluid_list_t*
+fluid_list_t *
fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func)
{
- fluid_list_t *l1, *l2;
+ fluid_list_t *l1, *l2;
- if (!list) {
- return NULL;
- }
- if (!list->next) {
- return list;
- }
-
- l1 = list;
- l2 = list->next;
-
- while ((l2 = l2->next) != NULL) {
- if ((l2 = l2->next) == NULL)
- break;
- l1=l1->next;
- }
- l2 = l1->next;
- l1->next = NULL;
-
- return fluid_list_sort_merge(fluid_list_sort(list, compare_func),
- fluid_list_sort(l2, compare_func),
- compare_func);
+ if(!list)
+ {
+ return NULL;
+ }
+
+ if(!list->next)
+ {
+ return list;
+ }
+
+ l1 = list;
+ l2 = list->next;
+
+ while((l2 = l2->next) != NULL)
+ {
+ if((l2 = l2->next) == NULL)
+ {
+ break;
+ }
+
+ l1 = l1->next;
+ }
+
+ l2 = l1->next;
+ l1->next = NULL;
+
+ return fluid_list_sort_merge(fluid_list_sort(list, compare_func),
+ fluid_list_sort(l2, compare_func),
+ compare_func);
}
-fluid_list_t*
+fluid_list_t *
fluid_list_last(fluid_list_t *list)
{
- if (list) {
- while (list->next)
- list = list->next;
- }
+ if(list)
+ {
+ while(list->next)
+ {
+ list = list->next;
+ }
+ }
- return list;
+ return list;
}
int
fluid_list_size(fluid_list_t *list)
{
- int n = 0;
- while (list) {
- n++;
- list = list->next;
- }
- return n;
+ int n = 0;
+
+ while(list)
+ {
+ n++;
+ list = list->next;
+ }
+
+ return n;
}
-fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data)
+fluid_list_t *fluid_list_insert_at(fluid_list_t *list, int n, void *data)
{
- fluid_list_t *new_list;
- fluid_list_t *cur;
- fluid_list_t *prev = NULL;
+ fluid_list_t *new_list;
+ fluid_list_t *cur;
+ fluid_list_t *prev = NULL;
- new_list = new_fluid_list();
- new_list->data = data;
+ new_list = new_fluid_list();
+ new_list->data = data;
- cur = list;
- while ((n-- > 0) && cur) {
- prev = cur;
- cur = cur->next;
- }
+ cur = list;
- new_list->next = cur;
+ while((n-- > 0) && cur)
+ {
+ prev = cur;
+ cur = cur->next;
+ }
- if (prev) {
- prev->next = new_list;
- return list;
- } else {
- return new_list;
- }
+ new_list->next = cur;
+
+ if(prev)
+ {
+ prev->next = new_list;
+ return list;
+ }
+ else
+ {
+ return new_list;
+ }
}
/* Compare function to sort strings alphabetically,
* for use with fluid_list_sort(). */
int
-fluid_list_str_compare_func (void *a, void *b)
+fluid_list_str_compare_func(void *a, void *b)
{
- if (a && b) return FLUID_STRCMP ((char *)a, (char *)b);
- if (!a && !b) return 0;
- if (a) return -1;
- return 1;
+ if(a && b)
+ {
+ return FLUID_STRCMP((char *)a, (char *)b);
+ }
+
+ if(!a && !b)
+ {
+ return 0;
+ }
+
+ if(a)
+ {
+ return -1;
+ }
+
+ return 1;
}
diff --git a/libs/fluidsynth/src/fluid_list.h b/libs/fluidsynth/src/fluid_list.h
index bdc32918b8..5be1cc3923 100644
--- a/libs/fluidsynth/src/fluid_list.h
+++ b/libs/fluidsynth/src/fluid_list.h
@@ -2,16 +2,16 @@
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02110-1301, USA.
@@ -33,30 +33,30 @@
typedef struct _fluid_list_t fluid_list_t;
-typedef int (*fluid_compare_func_t)(void* a, void* b);
+typedef int (*fluid_compare_func_t)(void *a, void *b);
struct _fluid_list_t
{
- void* data;
- fluid_list_t *next;
+ void *data;
+ fluid_list_t *next;
};
-fluid_list_t* new_fluid_list(void);
+fluid_list_t *new_fluid_list(void);
void delete_fluid_list(fluid_list_t *list);
void delete1_fluid_list(fluid_list_t *list);
-fluid_list_t* fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func);
-fluid_list_t* fluid_list_append(fluid_list_t *list, void* data);
-fluid_list_t* fluid_list_prepend(fluid_list_t *list, void* data);
-fluid_list_t* fluid_list_remove(fluid_list_t *list, void* data);
-fluid_list_t* fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink);
-fluid_list_t* fluid_list_nth(fluid_list_t *list, int n);
-fluid_list_t* fluid_list_last(fluid_list_t *list);
-fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data);
+fluid_list_t *fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func);
+fluid_list_t *fluid_list_append(fluid_list_t *list, void *data);
+fluid_list_t *fluid_list_prepend(fluid_list_t *list, void *data);
+fluid_list_t *fluid_list_remove(fluid_list_t *list, void *data);
+fluid_list_t *fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink);
+fluid_list_t *fluid_list_nth(fluid_list_t *list, int n);
+fluid_list_t *fluid_list_last(fluid_list_t *list);
+fluid_list_t *fluid_list_insert_at(fluid_list_t *list, int n, void *data);
int fluid_list_size(fluid_list_t *list);
#define fluid_list_next(slist) ((slist) ? (((fluid_list_t *)(slist))->next) : NULL)
#define fluid_list_get(slist) ((slist) ? ((slist)->data) : NULL)
-int fluid_list_str_compare_func (void *a, void *b);
+int fluid_list_str_compare_func(void *a, void *b);
#endif /* _FLUID_LIST_H */
diff --git a/libs/fluidsynth/src/fluid_midi.c b/libs/fluidsynth/src/fluid_midi.c
index fc58d839ef..bdf72dd681 100644
--- a/libs/fluidsynth/src/fluid_midi.c
+++ b/libs/fluidsynth/src/fluid_midi.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -25,15 +25,56 @@
static int fluid_midi_event_length(unsigned char event);
+static int fluid_isasciistring(char *s);
+static long fluid_getlength(unsigned char *s);
+
/* Read the entire contents of a file into memory, allocating enough memory
* for the file, and returning the length and the buffer.
* Note: This rewinds the file to the start before reading.
* Returns NULL if there was an error reading or allocating memory.
*/
-static char* fluid_file_read_full(fluid_file fp, size_t* length);
+static char *fluid_file_read_full(fluid_file fp, size_t *length);
+static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic);
#define READ_FULL_INITIAL_BUFLEN 1024
+static fluid_track_t *new_fluid_track(int num);
+static void delete_fluid_track(fluid_track_t *track);
+static int fluid_track_set_name(fluid_track_t *track, char *name);
+static int fluid_track_add_event(fluid_track_t *track, fluid_midi_event_t *evt);
+static fluid_midi_event_t *fluid_track_next_event(fluid_track_t *track);
+static int fluid_track_get_duration(fluid_track_t *track);
+static int fluid_track_reset(fluid_track_t *track);
+
+static int fluid_track_send_events(fluid_track_t *track,
+ fluid_synth_t *synth,
+ fluid_player_t *player,
+ unsigned int ticks);
+
+
+static int fluid_player_add_track(fluid_player_t *player, fluid_track_t *track);
+static int fluid_player_callback(void *data, unsigned int msec);
+static int fluid_player_reset(fluid_player_t *player);
+static int fluid_player_load(fluid_player_t *player, fluid_playlist_item *item);
+static void fluid_player_advancefile(fluid_player_t *player);
+static void fluid_player_playlist_load(fluid_player_t *player, unsigned int msec);
+
+static fluid_midi_file *new_fluid_midi_file(const char *buffer, size_t length);
+static void delete_fluid_midi_file(fluid_midi_file *mf);
+static int fluid_midi_file_read_mthd(fluid_midi_file *midifile);
+static int fluid_midi_file_load_tracks(fluid_midi_file *midifile, fluid_player_t *player);
+static int fluid_midi_file_read_track(fluid_midi_file *mf, fluid_player_t *player, int num);
+static int fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track);
+static int fluid_midi_file_read_varlen(fluid_midi_file *mf);
+static int fluid_midi_file_getc(fluid_midi_file *mf);
+static int fluid_midi_file_push(fluid_midi_file *mf, int c);
+static int fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len);
+static int fluid_midi_file_skip(fluid_midi_file *mf, int len);
+static int fluid_midi_file_eof(fluid_midi_file *mf);
+static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
+static int fluid_midi_file_eot(fluid_midi_file *mf);
+static int fluid_midi_file_get_division(fluid_midi_file *midifile);
+
#if 0 // disable file I/O with Ardour
/***************************************************************
*
@@ -49,15 +90,18 @@ static char* fluid_file_read_full(fluid_file fp, size_t* length);
* @return New MIDI file handle or NULL on error.
*/
fluid_midi_file *
-new_fluid_midi_file(const char* buffer, size_t length)
+new_fluid_midi_file(const char *buffer, size_t length)
{
fluid_midi_file *mf;
mf = FLUID_NEW(fluid_midi_file);
- if (mf == NULL) {
+
+ if(mf == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
FLUID_MEMSET(mf, 0, sizeof(fluid_midi_file));
mf->c = -1;
@@ -68,45 +112,58 @@ new_fluid_midi_file(const char* buffer, size_t length)
mf->buf_pos = 0;
mf->eof = FALSE;
- if (fluid_midi_file_read_mthd(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_mthd(mf) != FLUID_OK)
+ {
FLUID_FREE(mf);
return NULL;
}
+
return mf;
}
-static char*
-fluid_file_read_full(fluid_file fp, size_t* length)
+static char *
+fluid_file_read_full(fluid_file fp, size_t *length)
{
size_t buflen;
- char* buffer;
+ char *buffer;
size_t n;
+
/* Work out the length of the file in advance */
- if (FLUID_FSEEK(fp, 0, SEEK_END) != 0)
+ if(FLUID_FSEEK(fp, 0, SEEK_END) != 0)
{
FLUID_LOG(FLUID_ERR, "File load: Could not seek within file");
return NULL;
}
+
buflen = ftell(fp);
- if (FLUID_FSEEK(fp, 0, SEEK_SET) != 0)
+
+ if(FLUID_FSEEK(fp, 0, SEEK_SET) != 0)
{
FLUID_LOG(FLUID_ERR, "File load: Could not seek within file");
return NULL;
}
+
FLUID_LOG(FLUID_DBG, "File load: Allocating %d bytes", buflen);
buffer = FLUID_MALLOC(buflen);
- if (buffer == NULL) {
+
+ if(buffer == NULL)
+ {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
+
n = FLUID_FREAD(buffer, 1, buflen, fp);
- if (n != buflen) {
+
+ if(n != buflen)
+ {
FLUID_LOG(FLUID_ERR, "Only read %d bytes; expected %d", n,
buflen);
FLUID_FREE(buffer);
return NULL;
};
+
*length = n;
+
return buffer;
}
@@ -116,35 +173,40 @@ fluid_file_read_full(fluid_file fp, size_t* length)
* @param mf MIDI file handle to close and free.
*/
void
-delete_fluid_midi_file (fluid_midi_file *mf)
+delete_fluid_midi_file(fluid_midi_file *mf)
{
- if (mf == NULL) {
- return;
- }
+ fluid_return_if_fail(mf != NULL);
+
FLUID_FREE(mf);
- return;
}
/*
* Gets the next byte in a MIDI file, taking into account previous running status.
*
- * returns FLUID_FAILED if EOF or read error
+ * returns -1 if EOF or read error
*/
int
-fluid_midi_file_getc (fluid_midi_file *mf)
+fluid_midi_file_getc(fluid_midi_file *mf)
{
unsigned char c;
- if (mf->c >= 0) {
+
+ if(mf->c >= 0)
+ {
c = mf->c;
mf->c = -1;
- } else {
- if (mf->buf_pos >= mf->buf_len) {
+ }
+ else
+ {
+ if(mf->buf_pos >= mf->buf_len)
+ {
mf->eof = TRUE;
- return FLUID_FAILED;
+ return -1;
}
+
c = mf->buffer[mf->buf_pos++];
mf->trackpos++;
}
+
return (int) c;
}
@@ -166,23 +228,35 @@ int
fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len)
{
int num = len < mf->buf_len - mf->buf_pos
- ? len : mf->buf_len - mf->buf_pos;
- if (num != len) {
+ ? len : mf->buf_len - mf->buf_pos;
+
+ if(num != len)
+ {
mf->eof = TRUE;
}
- if (num < 0) {
+
+ if(num < 0)
+ {
num = 0;
}
+
/* Note: Read bytes, even if there aren't enough, but only increment
* trackpos if successful (emulates old behaviour of fluid_midi_file_read)
*/
- FLUID_MEMCPY(buf, mf->buffer+mf->buf_pos, num);
+ FLUID_MEMCPY(buf, mf->buffer + mf->buf_pos, num);
mf->buf_pos += num;
- if (num == len)
+
+ if(num == len)
+ {
mf->trackpos += num;
+ }
+
#if DEBUG
else
+ {
FLUID_LOG(FLUID_DBG, "Could not read the requested number of bytes");
+ }
+
#endif
return (num != len) ? FLUID_FAILED : FLUID_OK;
}
@@ -191,15 +265,18 @@ fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len)
* fluid_midi_file_skip
*/
int
-fluid_midi_file_skip (fluid_midi_file *mf, int skip)
+fluid_midi_file_skip(fluid_midi_file *mf, int skip)
{
int new_pos = mf->buf_pos + skip;
+
/* Mimic the behaviour of fseek: Error to seek past the start of file, but
* OK to seek past end (this just puts it into the EOF state). */
- if (new_pos < 0) {
+ if(new_pos < 0)
+ {
FLUID_LOG(FLUID_ERR, "Failed to seek position in file");
return FLUID_FAILED;
}
+
/* Clear the EOF flag, even if moved past the end of the file (this is
* consistent with the behaviour of fseek). */
mf->eof = FALSE;
@@ -210,15 +287,15 @@ fluid_midi_file_skip (fluid_midi_file *mf, int skip)
/*
* fluid_midi_file_eof
*/
-int fluid_midi_file_eof(fluid_midi_file* mf)
+int fluid_midi_file_eof(fluid_midi_file *mf)
{
- /* Note: This does not simply test whether the file read pointer is past
- * the end of the file. It mimics the behaviour of feof by actually
- * testing the stateful EOF condition, which is set to TRUE if getc or
- * fread have attempted to read past the end (but not if they have
- * precisely reached the end), but reset to FALSE upon a successful seek.
- */
- return mf->eof;
+ /* Note: This does not simply test whether the file read pointer is past
+ * the end of the file. It mimics the behaviour of feof by actually
+ * testing the stateful EOF condition, which is set to TRUE if getc or
+ * fread have attempted to read past the end (but not if they have
+ * precisely reached the end), but reset to FALSE upon a successful seek.
+ */
+ return mf->eof;
}
/*
@@ -227,30 +304,40 @@ int fluid_midi_file_eof(fluid_midi_file* mf)
int
fluid_midi_file_read_mthd(fluid_midi_file *mf)
{
- char mthd[15];
- if (fluid_midi_file_read(mf, mthd, 14) != FLUID_OK) {
+ char mthd[14];
+
+ if(fluid_midi_file_read(mf, mthd, sizeof(mthd)) != FLUID_OK)
+ {
return FLUID_FAILED;
}
- if ((FLUID_STRNCMP(mthd, "MThd", 4) != 0) || (mthd[7] != 6)
- || (mthd[9] > 2)) {
+
+ if((FLUID_STRNCMP(mthd, "MThd", 4) != 0) || (mthd[7] != 6)
+ || (mthd[9] > 2))
+ {
FLUID_LOG(FLUID_ERR,
- "Doesn't look like a MIDI file: invalid MThd header");
+ "Doesn't look like a MIDI file: invalid MThd header");
return FLUID_FAILED;
}
+
mf->type = mthd[9];
mf->ntracks = (unsigned) mthd[11];
- mf->ntracks += (unsigned int) (mthd[10]) << 16;
- if ((mthd[12]) < 0) {
+ mf->ntracks += (unsigned int)(mthd[10]) << 16;
+
+ if((signed char)mthd[12] < 0)
+ {
mf->uses_smpte = 1;
- mf->smpte_fps = -mthd[12];
+ mf->smpte_fps = -(signed char)mthd[12];
mf->smpte_res = (unsigned) mthd[13];
FLUID_LOG(FLUID_ERR, "File uses SMPTE timing -- Not implemented yet");
return FLUID_FAILED;
- } else {
+ }
+ else
+ {
mf->uses_smpte = 0;
- mf->division = (mthd[12] << 8) | (mthd[13] & 0xff);
+ mf->division = ((unsigned)mthd[12] << 8) | ((unsigned)mthd[13] & 0xff);
FLUID_LOG(FLUID_DBG, "Division=%d", mf->division);
}
+
return FLUID_OK;
}
@@ -261,11 +348,15 @@ int
fluid_midi_file_load_tracks(fluid_midi_file *mf, fluid_player_t *player)
{
int i;
- for (i = 0; i < mf->ntracks; i++) {
- if (fluid_midi_file_read_track(mf, player, i) != FLUID_OK) {
+
+ for(i = 0; i < mf->ntracks; i++)
+ {
+ if(fluid_midi_file_read_track(mf, player, i) != FLUID_OK)
+ {
return FLUID_FAILED;
}
}
+
return FLUID_OK;
}
@@ -275,14 +366,23 @@ fluid_midi_file_load_tracks(fluid_midi_file *mf, fluid_player_t *player)
int
fluid_isasciistring(char *s)
{
+ /* From ctype.h */
+#define fluid_isascii(c) (((c) & ~0x7f) == 0)
+
int i;
int len = (int) FLUID_STRLEN(s);
- for (i = 0; i < len; i++) {
- if (!fluid_isascii(s[i])) {
+
+ for(i = 0; i < len; i++)
+ {
+ if(!fluid_isascii(s[i]))
+ {
return 0;
}
}
+
return 1;
+
+#undef fluid_isascii
}
/*
@@ -303,9 +403,12 @@ int
fluid_midi_file_read_tracklen(fluid_midi_file *mf)
{
unsigned char length[5];
- if (fluid_midi_file_read(mf, length, 4) != FLUID_OK) {
+
+ if(fluid_midi_file_read(mf, length, 4) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
mf->tracklen = fluid_getlength(length);
mf->trackpos = 0;
mf->eot = 0;
@@ -319,9 +422,12 @@ int
fluid_midi_file_eot(fluid_midi_file *mf)
{
#if DEBUG
- if (mf->trackpos > mf->tracklen) {
+
+ if(mf->trackpos > mf->tracklen)
+ {
printf("track overrun: %d > %d\n", mf->trackpos, mf->tracklen);
}
+
#endif
return mf->eot || (mf->trackpos >= mf->tracklen);
}
@@ -337,69 +443,93 @@ fluid_midi_file_read_track(fluid_midi_file *mf, fluid_player_t *player, int num)
int found_track = 0;
int skip;
- if (fluid_midi_file_read(mf, id, 4) != FLUID_OK) {
+ if(fluid_midi_file_read(mf, id, 4) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
id[4] = '\0';
mf->dtime = 0;
- while (!found_track) {
+ while(!found_track)
+ {
- if (fluid_isasciistring((char *) id) == 0) {
+ if(fluid_isasciistring((char *) id) == 0)
+ {
FLUID_LOG(FLUID_ERR,
- "An non-ascii track header found, corrupt file");
+ "An non-ascii track header found, corrupt file");
return FLUID_FAILED;
- } else if (strcmp((char *) id, "MTrk") == 0) {
+ }
+ else if(FLUID_STRCMP((char *) id, "MTrk") == 0)
+ {
found_track = 1;
- if (fluid_midi_file_read_tracklen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_tracklen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
track = new_fluid_track(num);
- if (track == NULL) {
+
+ if(track == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
- while (!fluid_midi_file_eot(mf)) {
- if (fluid_midi_file_read_event(mf, track) != FLUID_OK) {
+ while(!fluid_midi_file_eot(mf))
+ {
+ if(fluid_midi_file_read_event(mf, track) != FLUID_OK)
+ {
delete_fluid_track(track);
return FLUID_FAILED;
}
}
/* Skip remaining track data, if any */
- if (mf->trackpos < mf->tracklen) {
- if (fluid_midi_file_skip(mf, mf->tracklen - mf->trackpos) != FLUID_OK) {
+ if(mf->trackpos < mf->tracklen)
+ {
+ if(fluid_midi_file_skip(mf, mf->tracklen - mf->trackpos) != FLUID_OK)
+ {
delete_fluid_track(track);
return FLUID_FAILED;
}
}
- if (fluid_player_add_track(player, track) != FLUID_OK) {
+ if(fluid_player_add_track(player, track) != FLUID_OK)
+ {
delete_fluid_track(track);
return FLUID_FAILED;
}
- } else {
+ }
+ else
+ {
found_track = 0;
- if (fluid_midi_file_read(mf, length, 4) != FLUID_OK) {
+
+ if(fluid_midi_file_read(mf, length, 4) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
skip = fluid_getlength(length);
+
/* fseek(mf->fp, skip, SEEK_CUR); */
- if (fluid_midi_file_skip(mf, skip) != FLUID_OK) {
+ if(fluid_midi_file_skip(mf, skip) != FLUID_OK)
+ {
return FLUID_FAILED;
}
}
}
- if (fluid_midi_file_eof(mf)) {
+
+ if(fluid_midi_file_eof(mf))
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
+
return FLUID_OK;
}
@@ -412,24 +542,35 @@ fluid_midi_file_read_varlen(fluid_midi_file *mf)
int i;
int c;
mf->varlen = 0;
- for (i = 0;; i++) {
- if (i == 4) {
+
+ for(i = 0;; i++)
+ {
+ if(i == 4)
+ {
FLUID_LOG(FLUID_ERR, "Invalid variable length number");
return FLUID_FAILED;
}
+
c = fluid_midi_file_getc(mf);
- if (c < 0) {
+
+ if(c < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
- if (c & 0x80) {
- mf->varlen |= (int) (c & 0x7F);
+
+ if(c & 0x80)
+ {
+ mf->varlen |= (int)(c & 0x7F);
mf->varlen <<= 7;
- } else {
+ }
+ else
+ {
mf->varlen += c;
break;
}
}
+
return FLUID_OK;
}
@@ -453,24 +594,31 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
int size;
/* read the delta-time of the event */
- if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_varlen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
+
mf->dtime += mf->varlen;
/* read the status byte */
status = fluid_midi_file_getc(mf);
- if (status < 0) {
+
+ if(status < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
/* not a valid status byte: use the running status instead */
- if ((status & 0x80) == 0) {
- if ((mf->running_status & 0x80) == 0) {
+ if((status & 0x80) == 0)
+ {
+ if((mf->running_status & 0x80) == 0)
+ {
FLUID_LOG(FLUID_ERR, "Undefined status and invalid running status");
return FLUID_FAILED;
}
+
fluid_midi_file_push(mf, status);
status = mf->running_status;
}
@@ -479,40 +627,49 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
mf->running_status = status;
- if ((status == MIDI_SYSEX)) { /* system exclusif */
+ if(status == MIDI_SYSEX) /* system exclusif */
+ {
/* read the length of the message */
- if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_varlen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
- if (mf->varlen) {
+ if(mf->varlen)
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__,
- __LINE__, mf->varlen);
+ __LINE__, mf->varlen);
metadata = FLUID_MALLOC(mf->varlen + 1);
- if (metadata == NULL) {
+ if(metadata == NULL)
+ {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
}
/* read the data of the message */
- if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
- FLUID_FREE (metadata);
+ if(fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK)
+ {
+ FLUID_FREE(metadata);
return FLUID_FAILED;
}
evt = new_fluid_midi_event();
- if (evt == NULL) {
+
+ if(evt == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
- FLUID_FREE (metadata);
+ FLUID_FREE(metadata);
return FLUID_FAILED;
}
evt->dtime = mf->dtime;
size = mf->varlen;
- if (metadata[mf->varlen - 1] == MIDI_EOX)
+ if(metadata[mf->varlen - 1] == MIDI_EOX)
+ {
size--;
+ }
/* Add SYSEX event and indicate that its dynamically allocated and should be freed with event */
fluid_midi_event_set_sysex(evt, metadata, size, TRUE);
@@ -522,232 +679,318 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
return FLUID_OK;
- } else if (status == MIDI_META_EVENT) { /* meta events */
+ }
+ else if(status == MIDI_META_EVENT) /* meta events */
+ {
int result = FLUID_OK;
/* get the type of the meta message */
type = fluid_midi_file_getc(mf);
- if (type < 0) {
+
+ if(type < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
/* get the length of the data part */
- if (fluid_midi_file_read_varlen(mf) != FLUID_OK) {
+ if(fluid_midi_file_read_varlen(mf) != FLUID_OK)
+ {
return FLUID_FAILED;
}
- if (mf->varlen < 255) {
+ if(mf->varlen < 255)
+ {
metadata = &static_buf[0];
- } else {
+ }
+ else
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__,
- __LINE__, mf->varlen);
+ __LINE__, mf->varlen);
dyn_buf = FLUID_MALLOC(mf->varlen + 1);
- if (dyn_buf == NULL) {
+
+ if(dyn_buf == NULL)
+ {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
}
+
metadata = dyn_buf;
}
/* read the data */
- if (mf->varlen) {
- if (fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) {
- if (dyn_buf) {
+ if(mf->varlen)
+ {
+ if(fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK)
+ {
+ if(dyn_buf)
+ {
FLUID_FREE(dyn_buf);
}
+
return FLUID_FAILED;
}
}
/* handle meta data */
- switch (type) {
+ switch(type)
+ {
- case MIDI_COPYRIGHT:
- metadata[mf->varlen] = 0;
- break;
+ case MIDI_COPYRIGHT:
+ metadata[mf->varlen] = 0;
+ break;
- case MIDI_TRACK_NAME:
- metadata[mf->varlen] = 0;
- fluid_track_set_name(track, (char *) metadata);
- break;
+ case MIDI_TRACK_NAME:
+ metadata[mf->varlen] = 0;
+ fluid_track_set_name(track, (char *) metadata);
+ break;
- case MIDI_INST_NAME:
- metadata[mf->varlen] = 0;
- break;
+ case MIDI_INST_NAME:
+ metadata[mf->varlen] = 0;
+ break;
+
+ case MIDI_LYRIC:
+ case MIDI_TEXT:
+ {
+ void *tmp;
+ int size = mf->varlen + 1;
+
+ /* NULL terminate strings for safety */
+ metadata[size - 1] = '\0';
+
+ evt = new_fluid_midi_event();
- case MIDI_LYRIC:
+ if(evt == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ result = FLUID_FAILED;
break;
+ }
+
+ evt->dtime = mf->dtime;
- case MIDI_MARKER:
+ tmp = FLUID_MALLOC(size);
+
+ if(tmp == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "Out of memory");
+ delete_fluid_midi_event(evt);
+ evt = NULL;
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_CUE_POINT:
- break; /* don't care much for text events */
+ FLUID_MEMCPY(tmp, metadata, size);
- case MIDI_EOT:
- if (mf->varlen != 0) {
- FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event");
- result = FLUID_FAILED;
- break;
- }
- mf->eot = 1;
- evt = new_fluid_midi_event();
- if (evt == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- result = FLUID_FAILED;
- break;
- }
- evt->dtime = mf->dtime;
- evt->type = MIDI_EOT;
- fluid_track_add_event(track, evt);
- mf->dtime = 0;
+ fluid_midi_event_set_sysex_LOCAL(evt, type, tmp, size, TRUE);
+ fluid_track_add_event(track, evt);
+ mf->dtime = 0;
+ }
+ break;
+
+ case MIDI_MARKER:
+ break;
+
+ case MIDI_CUE_POINT:
+ break; /* don't care much for text events */
+
+ case MIDI_EOT:
+ if(mf->varlen != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_SET_TEMPO:
- if (mf->varlen != 3) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for SetTempo meta event");
- result = FLUID_FAILED;
- break;
- }
- tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
- evt = new_fluid_midi_event();
- if (evt == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- result = FLUID_FAILED;
- break;
- }
- evt->dtime = mf->dtime;
- evt->type = MIDI_SET_TEMPO;
- evt->channel = 0;
- evt->param1 = tempo;
- evt->param2 = 0;
- fluid_track_add_event(track, evt);
- mf->dtime = 0;
+ mf->eot = 1;
+ evt = new_fluid_midi_event();
+
+ if(evt == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_SMPTE_OFFSET:
- if (mf->varlen != 5) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for SMPTE Offset meta event");
- result = FLUID_FAILED;
- break;
- }
- break; /* we don't use smtp */
-
- case MIDI_TIME_SIGNATURE:
- if (mf->varlen != 4) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for TimeSignature meta event");
- result = FLUID_FAILED;
- break;
- }
- nominator = metadata[0];
- denominator = pow(2.0, (double) metadata[1]);
- clocks = metadata[2];
- notes = metadata[3];
+ evt->dtime = mf->dtime;
+ evt->type = MIDI_EOT;
+ fluid_track_add_event(track, evt);
+ mf->dtime = 0;
+ break;
- FLUID_LOG(FLUID_DBG,
- "signature=%d/%d, metronome=%d, 32nd-notes=%d",
- nominator, denominator, clocks, notes);
+ case MIDI_SET_TEMPO:
+ if(mf->varlen != 3)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for SetTempo meta event");
+ result = FLUID_FAILED;
+ break;
+ }
+ tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
+ evt = new_fluid_midi_event();
+
+ if(evt == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_KEY_SIGNATURE:
- if (mf->varlen != 2) {
- FLUID_LOG(FLUID_ERR,
- "Invalid length for KeySignature meta event");
- result = FLUID_FAILED;
- break;
- }
- /* We don't care about key signatures anyway */
- /* sf = metadata[0];
- mi = metadata[1]; */
+ evt->dtime = mf->dtime;
+ evt->type = MIDI_SET_TEMPO;
+ evt->channel = 0;
+ evt->param1 = tempo;
+ evt->param2 = 0;
+ fluid_track_add_event(track, evt);
+ mf->dtime = 0;
+ break;
+
+ case MIDI_SMPTE_OFFSET:
+ if(mf->varlen != 5)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for SMPTE Offset meta event");
+ result = FLUID_FAILED;
break;
+ }
- case MIDI_SEQUENCER_EVENT:
+ break; /* we don't use smtp */
+
+ case MIDI_TIME_SIGNATURE:
+ if(mf->varlen != 4)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for TimeSignature meta event");
+ result = FLUID_FAILED;
break;
+ }
- default:
+ nominator = metadata[0];
+ denominator = pow(2.0, (double) metadata[1]);
+ clocks = metadata[2];
+ notes = metadata[3];
+
+ FLUID_LOG(FLUID_DBG,
+ "signature=%d/%d, metronome=%d, 32nd-notes=%d",
+ nominator, denominator, clocks, notes);
+
+ break;
+
+ case MIDI_KEY_SIGNATURE:
+ if(mf->varlen != 2)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "Invalid length for KeySignature meta event");
+ result = FLUID_FAILED;
break;
+ }
+
+ /* We don't care about key signatures anyway */
+ /* sf = metadata[0];
+ mi = metadata[1]; */
+ break;
+
+ case MIDI_SEQUENCER_EVENT:
+ break;
+
+ default:
+ break;
}
- if (dyn_buf) {
+ if(dyn_buf)
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: free metadata", __FILE__, __LINE__);
FLUID_FREE(dyn_buf);
}
return result;
- } else { /* channel messages */
+ }
+ else /* channel messages */
+ {
type = status & 0xf0;
channel = status & 0x0f;
/* all channel message have at least 1 byte of associated data */
- if ((param1 = fluid_midi_file_getc(mf)) < 0) {
+ if((param1 = fluid_midi_file_getc(mf)) < 0)
+ {
FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
}
- switch (type) {
+ switch(type)
+ {
- case NOTE_ON:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ case NOTE_ON:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- case NOTE_OFF:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ break;
- case KEY_PRESSURE:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ case NOTE_OFF:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- case CONTROL_CHANGE:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
- break;
+ break;
- case PROGRAM_CHANGE:
- break;
+ case KEY_PRESSURE:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- case CHANNEL_PRESSURE:
- break;
+ break;
- case PITCH_BEND:
- if ((param2 = fluid_midi_file_getc(mf)) < 0) {
- FLUID_LOG(FLUID_ERR, "Unexpected end of file");
- return FLUID_FAILED;
- }
+ case CONTROL_CHANGE:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
+ return FLUID_FAILED;
+ }
- param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
- param2 = 0;
- break;
+ break;
+
+ case PROGRAM_CHANGE:
+ break;
+
+ case CHANNEL_PRESSURE:
+ break;
- default:
- /* Can't possibly happen !? */
- FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event");
+ case PITCH_BEND:
+ if((param2 = fluid_midi_file_getc(mf)) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Unexpected end of file");
return FLUID_FAILED;
+ }
+
+ param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
+ param2 = 0;
+ break;
+
+ default:
+ /* Can't possibly happen !? */
+ FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event");
+ return FLUID_FAILED;
}
+
evt = new_fluid_midi_event();
- if (evt == NULL) {
+
+ if(evt == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
+
evt->dtime = mf->dtime;
evt->type = type;
evt->channel = channel;
@@ -756,6 +999,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track)
fluid_track_add_event(track, evt);
mf->dtime = 0;
}
+
return FLUID_OK;
}
@@ -779,14 +1023,17 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
* @return New MIDI event structure or NULL when out of memory.
*/
fluid_midi_event_t *
-new_fluid_midi_event ()
+new_fluid_midi_event()
{
- fluid_midi_event_t* evt;
+ fluid_midi_event_t *evt;
evt = FLUID_NEW(fluid_midi_event_t);
- if (evt == NULL) {
+
+ if(evt == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
evt->dtime = 0;
evt->type = 0;
evt->channel = 0;
@@ -800,24 +1047,27 @@ new_fluid_midi_event ()
/**
* Delete MIDI event structure.
* @param evt MIDI event structure
- * @return Always returns #FLUID_OK
*/
-int
+void
delete_fluid_midi_event(fluid_midi_event_t *evt)
{
fluid_midi_event_t *temp;
+ fluid_return_if_fail(evt != NULL);
- while (evt) {
+ while(evt)
+ {
temp = evt->next;
/* Dynamic SYSEX event? - free (param2 indicates if dynamic) */
- if (evt->type == MIDI_SYSEX && evt->paramptr && evt->param2)
- FLUID_FREE (evt->paramptr);
+ if((evt->type == MIDI_SYSEX || (evt-> type == MIDI_TEXT) || (evt->type == MIDI_LYRIC)) &&
+ evt->paramptr && evt->param2)
+ {
+ FLUID_FREE(evt->paramptr);
+ }
FLUID_FREE(evt);
evt = temp;
}
- return FLUID_OK;
}
/**
@@ -1016,22 +1266,65 @@ fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val)
* Assign sysex data to a MIDI event structure.
* @param evt MIDI event structure
* @param data Pointer to SYSEX data
- * @param size Size of SYSEX data
+ * @param size Size of SYSEX data in bytes
* @param dynamic TRUE if the SYSEX data has been dynamically allocated and
* should be freed when the event is freed (only applies if event gets destroyed
* with delete_fluid_midi_event())
* @return Always returns #FLUID_OK
*
- * NOTE: Unlike the other event assignment functions, this one sets evt->type.
+ * @note Unlike the other event assignment functions, this one sets evt->type.
*/
int
fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, int size, int dynamic)
{
- evt->type = MIDI_SYSEX;
+ fluid_midi_event_set_sysex_LOCAL(evt, MIDI_SYSEX, data, size, dynamic);
+ return FLUID_OK;
+}
+
+/**
+ * Assign text data to a MIDI event structure.
+ * @param evt MIDI event structure
+ * @param data Pointer to text data
+ * @param size Size of text data in bytes
+ * @param dynamic TRUE if the data has been dynamically allocated and
+ * should be freed when the event is freed via delete_fluid_midi_event()
+ * @return Always returns #FLUID_OK
+ *
+ * @since 2.0.0
+ * @note Unlike the other event assignment functions, this one sets evt->type.
+ */
+int
+fluid_midi_event_set_text(fluid_midi_event_t *evt, void *data, int size, int dynamic)
+{
+ fluid_midi_event_set_sysex_LOCAL(evt, MIDI_TEXT, data, size, dynamic);
+ return FLUID_OK;
+}
+
+/**
+ * Assign lyric data to a MIDI event structure.
+ * @param evt MIDI event structure
+ * @param data Pointer to lyric data
+ * @param size Size of lyric data in bytes
+ * @param dynamic TRUE if the data has been dynamically allocated and
+ * should be freed when the event is freed via delete_fluid_midi_event()
+ * @return Always returns #FLUID_OK
+ *
+ * @since 2.0.0
+ * @note Unlike the other event assignment functions, this one sets evt->type.
+ */
+int
+fluid_midi_event_set_lyrics(fluid_midi_event_t *evt, void *data, int size, int dynamic)
+{
+ fluid_midi_event_set_sysex_LOCAL(evt, MIDI_LYRIC, data, size, dynamic);
+ return FLUID_OK;
+}
+
+static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic)
+{
+ evt->type = type;
evt->paramptr = data;
evt->param1 = size;
evt->param2 = dynamic;
- return FLUID_OK;
}
/******************************************************
@@ -1047,9 +1340,12 @@ new_fluid_track(int num)
{
fluid_track_t *track;
track = FLUID_NEW(fluid_track_t);
- if (track == NULL) {
+
+ if(track == NULL)
+ {
return NULL;
}
+
track->name = NULL;
track->num = num;
track->first = NULL;
@@ -1062,17 +1358,14 @@ new_fluid_track(int num)
/*
* delete_fluid_track
*/
-int
+void
delete_fluid_track(fluid_track_t *track)
{
- if (track->name != NULL) {
- FLUID_FREE(track->name);
- }
- if (track->first != NULL) {
- delete_fluid_midi_event(track->first);
- }
+ fluid_return_if_fail(track != NULL);
+
+ FLUID_FREE(track->name);
+ delete_fluid_midi_event(track->first);
FLUID_FREE(track);
- return FLUID_OK;
}
/*
@@ -1082,33 +1375,32 @@ int
fluid_track_set_name(fluid_track_t *track, char *name)
{
int len;
- if (track->name != NULL) {
+
+ if(track->name != NULL)
+ {
FLUID_FREE(track->name);
}
- if (name == NULL) {
+
+ if(name == NULL)
+ {
track->name = NULL;
return FLUID_OK;
}
+
len = FLUID_STRLEN(name);
track->name = FLUID_MALLOC(len + 1);
- if (track->name == NULL) {
+
+ if(track->name == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
+
FLUID_STRCPY(track->name, name);
return FLUID_OK;
}
/*
- * fluid_track_get_name
- */
-char *
-fluid_track_get_name(fluid_track_t *track)
-{
- return track->name;
-}
-
-/*
* fluid_track_get_duration
*/
int
@@ -1116,29 +1408,14 @@ fluid_track_get_duration(fluid_track_t *track)
{
int time = 0;
fluid_midi_event_t *evt = track->first;
- while (evt != NULL) {
+
+ while(evt != NULL)
+ {
time += evt->dtime;
evt = evt->next;
}
- return time;
-}
-/*
- * fluid_track_count_events
- */
-static int
-fluid_track_count_events(fluid_track_t *track, int *on, int *off)
-{
- fluid_midi_event_t *evt = track->first;
- while (evt != NULL) {
- if (evt->type == NOTE_ON) {
- (*on)++;
- } else if (evt->type == NOTE_OFF) {
- (*off)++;
- }
- evt = evt->next;
- }
- return FLUID_OK;
+ return time;
}
/*
@@ -1148,25 +1425,20 @@ int
fluid_track_add_event(fluid_track_t *track, fluid_midi_event_t *evt)
{
evt->next = NULL;
- if (track->first == NULL) {
+
+ if(track->first == NULL)
+ {
track->first = evt;
track->cur = evt;
track->last = evt;
- } else {
+ }
+ else
+ {
track->last->next = evt;
track->last = evt;
}
- return FLUID_OK;
-}
-/*
- * fluid_track_first_event
- */
-fluid_midi_event_t *
-fluid_track_first_event(fluid_track_t *track)
-{
- track->cur = track->first;
- return track->cur;
+ return FLUID_OK;
}
/*
@@ -1175,9 +1447,11 @@ fluid_track_first_event(fluid_track_t *track)
fluid_midi_event_t *
fluid_track_next_event(fluid_track_t *track)
{
- if (track->cur != NULL) {
+ if(track->cur != NULL)
+ {
track->cur = track->cur->next;
}
+
return track->cur;
}
@@ -1197,17 +1471,31 @@ fluid_track_reset(fluid_track_t *track)
*/
int
fluid_track_send_events(fluid_track_t *track,
- fluid_synth_t *synth,
- fluid_player_t *player,
- unsigned int ticks)
+ fluid_synth_t *synth,
+ fluid_player_t *player,
+ unsigned int ticks)
{
int status = FLUID_OK;
fluid_midi_event_t *event;
+ int seeking = player->seek_ticks >= 0;
- while (1) {
+ if(seeking)
+ {
+ ticks = player->seek_ticks; /* update target ticks */
+
+ if(track->ticks > ticks)
+ {
+ fluid_track_reset(track); /* reset track if seeking backwards */
+ }
+ }
+
+ while(1)
+ {
event = track->cur;
- if (event == NULL) {
+
+ if(event == NULL)
+ {
return status;
}
@@ -1218,25 +1506,37 @@ fluid_track_send_events(fluid_track_t *track,
/* event->dtime, */
/* track->ticks + event->dtime); */
- if (track->ticks + event->dtime > ticks) {
+ if(track->ticks + event->dtime > ticks)
+ {
return status;
}
track->ticks += event->dtime;
- if (!player || event->type == MIDI_EOT) {
+ if(!player || event->type == MIDI_EOT)
+ {
}
- else if (event->type == MIDI_SET_TEMPO) {
- fluid_player_set_midi_tempo(player, event->param1);
+ else if(seeking && (event->type == NOTE_ON || event->type == NOTE_OFF))
+ {
+ /* skip on/off messages */
}
- else {
- if (player->playback_callback)
+ else
+ {
+ if(player->playback_callback)
+ {
player->playback_callback(player->playback_userdata, event);
+ }
+ }
+
+ if(event->type == MIDI_SET_TEMPO)
+ {
+ fluid_player_set_midi_tempo(player, event->param1);
}
fluid_track_next_event(track);
}
+
return status;
}
@@ -1244,6 +1544,14 @@ fluid_track_send_events(fluid_track_t *track,
*
* fluid_player
*/
+static void
+fluid_player_handle_reset_synth(void *data, const char *name, int value)
+{
+ fluid_player_t *player = data;
+ fluid_return_if_fail(player != NULL);
+
+ player->reset_synth_between_songs = value;
+}
/**
* Create a new MIDI player.
@@ -1256,16 +1564,22 @@ new_fluid_player(fluid_synth_t *synth)
int i;
fluid_player_t *player;
player = FLUID_NEW(fluid_player_t);
- if (player == NULL) {
+
+ if(player == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
player->status = FLUID_PLAYER_READY;
player->loop = 1;
player->ntracks = 0;
- for (i = 0; i < MAX_NUMBER_OF_TRACKS; i++) {
+
+ for(i = 0; i < MAX_NUMBER_OF_TRACKS; i++)
+ {
player->track[i] = NULL;
}
+
player->synth = synth;
player->system_timer = NULL;
player->sample_timer = NULL;
@@ -1277,13 +1591,16 @@ new_fluid_player(fluid_synth_t *synth)
player->deltatime = 4.0;
player->cur_msec = 0;
player->cur_ticks = 0;
+ player->seek_ticks = -1;
fluid_player_set_playback_callback(player, fluid_synth_handle_midi_event, synth);
-
player->use_system_timer = fluid_settings_str_equal(synth->settings,
- "player.timing-source", "system");
+ "player.timing-source", "system");
fluid_settings_getint(synth->settings, "player.reset-synth", &i);
- player->reset_synth_between_songs = i;
+ fluid_player_handle_reset_synth(player, NULL, i);
+
+ fluid_settings_callback_int(synth->settings, "player.reset-synth",
+ fluid_player_handle_reset_synth, player);
return player;
}
@@ -1291,23 +1608,22 @@ new_fluid_player(fluid_synth_t *synth)
/**
* Delete a MIDI player instance.
* @param player MIDI player instance
- * @return Always returns #FLUID_OK
*/
-int
+void
delete_fluid_player(fluid_player_t *player)
{
fluid_list_t *q;
- fluid_playlist_item* pi;
+ fluid_playlist_item *pi;
+
+ fluid_return_if_fail(player != NULL);
- if (player == NULL) {
- return FLUID_OK;
- }
fluid_player_stop(player);
fluid_player_reset(player);
- while (player->playlist != NULL) {
+ while(player->playlist != NULL)
+ {
q = player->playlist->next;
- pi = (fluid_playlist_item*) player->playlist->data;
+ pi = (fluid_playlist_item *) player->playlist->data;
FLUID_FREE(pi->filename);
FLUID_FREE(pi->buffer);
FLUID_FREE(pi);
@@ -1316,7 +1632,6 @@ delete_fluid_player(fluid_player_t *player)
}
FLUID_FREE(player);
- return FLUID_OK;
}
/**
@@ -1327,14 +1642,12 @@ fluid_player_settings(fluid_settings_t *settings)
{
/* player.timing-source can be either "system" (use system timer)
or "sample" (use timer based on number of written samples) */
- fluid_settings_register_str(settings, "player.timing-source", "sample", 0,
- NULL, NULL);
+ fluid_settings_register_str(settings, "player.timing-source", "sample", 0);
fluid_settings_add_option(settings, "player.timing-source", "sample");
fluid_settings_add_option(settings, "player.timing-source", "system");
/* Selects whether the player should reset the synth between songs, or not. */
- fluid_settings_register_int(settings, "player.reset-synth", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
+ fluid_settings_register_int(settings, "player.reset-synth", 1, 0, 1, FLUID_HINT_TOGGLED);
}
@@ -1343,12 +1656,15 @@ fluid_player_reset(fluid_player_t *player)
{
int i;
- for (i = 0; i < MAX_NUMBER_OF_TRACKS; i++) {
- if (player->track[i] != NULL) {
+ for(i = 0; i < MAX_NUMBER_OF_TRACKS; i++)
+ {
+ if(player->track[i] != NULL)
+ {
delete_fluid_track(player->track[i]);
player->track[i] = NULL;
}
}
+
/* player->current_file = NULL; */
/* player->status = FLUID_PLAYER_READY; */
/* player->loop = 1; */
@@ -1366,52 +1682,33 @@ fluid_player_reset(fluid_player_t *player)
int
fluid_player_add_track(fluid_player_t *player, fluid_track_t *track)
{
- if (player->ntracks < MAX_NUMBER_OF_TRACKS) {
+ if(player->ntracks < MAX_NUMBER_OF_TRACKS)
+ {
player->track[player->ntracks++] = track;
return FLUID_OK;
- } else {
- return FLUID_FAILED;
}
-}
-
-/*
- * fluid_player_count_tracks
- */
-int
-fluid_player_count_tracks(fluid_player_t *player)
-{
- return player->ntracks;
-}
-
-/*
- * fluid_player_get_track
- */
-fluid_track_t *
-fluid_player_get_track(fluid_player_t *player, int i)
-{
- if ((i >= 0) && (i < MAX_NUMBER_OF_TRACKS)) {
- return player->track[i];
- } else {
- return NULL;
+ else
+ {
+ return FLUID_FAILED;
}
}
/**
- * Change the MIDI callback function. This is usually set to
+ * Change the MIDI callback function. This is usually set to
* fluid_synth_handle_midi_event, but can optionally be changed
* to a user-defined function instead, for intercepting all MIDI
- * messages sent to the synth. You can also use a midi router as
+ * messages sent to the synth. You can also use a midi router as
* the callback function to modify the MIDI messages before sending
- * them to the synth.
+ * them to the synth.
* @param player MIDI player instance
* @param handler Pointer to callback function
* @param handler_data Parameter sent to the callback function
* @returns FLUID_OK
* @since 1.1.4
*/
-int
-fluid_player_set_playback_callback(fluid_player_t* player,
- handle_midi_event_func_t handler, void* handler_data)
+int
+fluid_player_set_playback_callback(fluid_player_t *player,
+ handle_midi_event_func_t handler, void *handler_data)
{
player->playback_callback = handler;
player->playback_userdata = handler_data;
@@ -1428,8 +1725,10 @@ int
fluid_player_add(fluid_player_t *player, const char *midifile)
{
fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item));
- char* f = FLUID_STRDUP(midifile);
- if (!pi || !f) {
+ char *f = FLUID_STRDUP(midifile);
+
+ if(!pi || !f)
+ {
FLUID_FREE(pi);
FLUID_FREE(f);
FLUID_LOG(FLUID_PANIC, "Out of memory");
@@ -1453,12 +1752,14 @@ fluid_player_add(fluid_player_t *player, const char *midifile)
* @return #FLUID_OK or #FLUID_FAILED
*/
int
-fluid_player_add_mem(fluid_player_t* player, const void *buffer, size_t len)
+fluid_player_add_mem(fluid_player_t *player, const void *buffer, size_t len)
{
/* Take a copy of the buffer, so the caller can free immediately. */
fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item));
void *buf_copy = FLUID_MALLOC(len);
- if (!pi || !buf_copy) {
+
+ if(!pi || !buf_copy)
+ {
FLUID_FREE(pi);
FLUID_FREE(buf_copy);
FLUID_LOG(FLUID_PANIC, "Out of memory");
@@ -1480,28 +1781,33 @@ int
fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
{
fluid_midi_file *midifile;
- char* buffer;
+ char *buffer;
size_t buffer_length;
int buffer_owned;
- if (item->filename != NULL)
+ if(item->filename != NULL)
{
fluid_file fp;
/* This file is specified by filename; load the file from disk */
FLUID_LOG(FLUID_DBG, "%s: %d: Loading midifile %s", __FILE__, __LINE__,
- item->filename);
+ item->filename);
/* Read the entire contents of the file into the buffer */
fp = FLUID_FOPEN(item->filename, "rb");
- if (fp == NULL) {
+
+ if(fp == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Couldn't open the MIDI file");
return FLUID_FAILED;
}
+
buffer = fluid_file_read_full(fp, &buffer_length);
- if (buffer == NULL)
+
+ if(buffer == NULL)
{
FLUID_FCLOSE(fp);
return FLUID_FAILED;
}
+
buffer_owned = 1;
FLUID_FCLOSE(fp);
}
@@ -1509,7 +1815,7 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
{
/* This file is specified by a pre-loaded buffer; load from memory */
FLUID_LOG(FLUID_DBG, "%s: %d: Loading midifile from memory (%p)",
- __FILE__, __LINE__, item->buffer);
+ __FILE__, __LINE__, item->buffer);
buffer = (char *) item->buffer;
buffer_length = item->buffer_len;
/* Do not free the buffer (it is owned by the playlist) */
@@ -1517,59 +1823,83 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
}
midifile = new_fluid_midi_file(buffer, buffer_length);
- if (midifile == NULL) {
- if (buffer_owned) {
+
+ if(midifile == NULL)
+ {
+ if(buffer_owned)
+ {
FLUID_FREE(buffer);
}
+
return FLUID_FAILED;
}
+
player->division = fluid_midi_file_get_division(midifile);
fluid_player_set_midi_tempo(player, player->miditempo); // Update deltatime
/*FLUID_LOG(FLUID_DBG, "quarter note division=%d\n", player->division); */
- if (fluid_midi_file_load_tracks(midifile, player) != FLUID_OK) {
- if (buffer_owned) {
+ if(fluid_midi_file_load_tracks(midifile, player) != FLUID_OK)
+ {
+ if(buffer_owned)
+ {
FLUID_FREE(buffer);
}
+
delete_fluid_midi_file(midifile);
return FLUID_FAILED;
}
+
delete_fluid_midi_file(midifile);
- if (buffer_owned) {
+
+ if(buffer_owned)
+ {
FLUID_FREE(buffer);
}
+
return FLUID_OK;
}
-static void
+void
fluid_player_advancefile(fluid_player_t *player)
{
- if (player->playlist == NULL) {
+ if(player->playlist == NULL)
+ {
return; /* No files to play */
}
- if (player->currentfile != NULL) {
+
+ if(player->currentfile != NULL)
+ {
player->currentfile = fluid_list_next(player->currentfile);
}
- if (player->currentfile == NULL) {
- if (player->loop == 0) {
+
+ if(player->currentfile == NULL)
+ {
+ if(player->loop == 0)
+ {
return; /* We're done playing */
}
- if (player->loop > 0) {
+
+ if(player->loop > 0)
+ {
player->loop--;
}
+
player->currentfile = player->playlist;
}
}
-static void
+void
fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
{
- fluid_playlist_item* current_playitem;
+ fluid_playlist_item *current_playitem;
int i;
- do {
+ do
+ {
fluid_player_advancefile(player);
- if (player->currentfile == NULL) {
+
+ if(player->currentfile == NULL)
+ {
/* Failed to find next song, probably since we're finished */
player->status = FLUID_PLAYER_DONE;
return;
@@ -1577,7 +1907,8 @@ fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
fluid_player_reset(player);
current_playitem = (fluid_playlist_item *) player->currentfile->data;
- } while (fluid_player_load(player, current_playitem) != FLUID_OK);
+ }
+ while(fluid_player_load(player, current_playitem) != FLUID_OK);
/* Successfully loaded midi file */
@@ -1586,18 +1917,20 @@ fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
player->start_ticks = 0;
player->cur_ticks = 0;
- if (player->reset_synth_between_songs) {
+ if(player->reset_synth_between_songs)
+ {
fluid_synth_system_reset(player->synth);
}
- for (i = 0; i < player->ntracks; i++) {
- if (player->track[i] != NULL) {
+ for(i = 0; i < player->ntracks; i++)
+ {
+ if(player->track[i] != NULL)
+ {
fluid_track_reset(player->track[i]);
}
}
}
-
/*
* fluid_player_callback
*/
@@ -1613,36 +1946,61 @@ fluid_player_callback(void *data, unsigned int msec)
synth = player->synth;
loadnextfile = player->currentfile == NULL ? 1 : 0;
- do {
- if (loadnextfile) {
+
+ do
+ {
+ if(loadnextfile)
+ {
loadnextfile = 0;
fluid_player_playlist_load(player, msec);
- if (player->currentfile == NULL) {
+
+ if(player->currentfile == NULL)
+ {
return 0;
}
}
player->cur_msec = msec;
player->cur_ticks = (player->start_ticks
- + (int) ((double) (player->cur_msec - player->start_msec)
- / player->deltatime));
+ + (int)((double)(player->cur_msec - player->start_msec)
+ / player->deltatime + 0.5)); /* 0.5 to average overall error when casting */
+
+ if(player->seek_ticks >= 0)
+ {
+ fluid_synth_all_sounds_off(synth, -1); /* avoid hanging notes */
+ }
- for (i = 0; i < player->ntracks; i++) {
- if (!fluid_track_eot(player->track[i])) {
+ for(i = 0; i < player->ntracks; i++)
+ {
+ if(!fluid_track_eot(player->track[i]))
+ {
status = FLUID_PLAYER_PLAYING;
- if (fluid_track_send_events(player->track[i], synth, player,
- player->cur_ticks) != FLUID_OK) {
+
+ if(fluid_track_send_events(player->track[i], synth, player,
+ player->cur_ticks) != FLUID_OK)
+ {
/* */
}
}
}
- if (status == FLUID_PLAYER_DONE) {
+ if(player->seek_ticks >= 0)
+ {
+ player->start_ticks = player->seek_ticks; /* tick position of last tempo value (which is now) */
+ player->cur_ticks = player->seek_ticks;
+ player->begin_msec = msec; /* only used to calculate the duration of playing */
+ player->start_msec = msec; /* should be the (synth)-time of the last tempo change */
+ player->seek_ticks = -1; /* clear seek_ticks */
+ }
+
+ if(status == FLUID_PLAYER_DONE)
+ {
FLUID_LOG(FLUID_DBG, "%s: %d: Duration=%.3f sec", __FILE__,
- __LINE__, (msec - player->begin_msec) / 1000.0);
+ __LINE__, (msec - player->begin_msec) / 1000.0);
loadnextfile = 1;
}
- } while (loadnextfile);
+ }
+ while(loadnextfile);
player->status = status;
@@ -1657,30 +2015,39 @@ fluid_player_callback(void *data, unsigned int msec)
int
fluid_player_play(fluid_player_t *player)
{
- if (player->status == FLUID_PLAYER_PLAYING) {
+ if(player->status == FLUID_PLAYER_PLAYING)
+ {
return FLUID_OK;
}
- if (player->playlist == NULL) {
+ if(player->playlist == NULL)
+ {
return FLUID_OK;
}
player->status = FLUID_PLAYER_PLAYING;
- if (player->use_system_timer) {
+ if(player->use_system_timer)
+ {
player->system_timer = new_fluid_timer((int) player->deltatime,
- fluid_player_callback, (void *) player, TRUE, FALSE, TRUE);
- if (player->system_timer == NULL) {
+ fluid_player_callback, (void *) player, TRUE, FALSE, TRUE);
+
+ if(player->system_timer == NULL)
+ {
return FLUID_FAILED;
}
- } else {
+ }
+ else
+ {
player->sample_timer = new_fluid_sample_timer(player->synth,
- fluid_player_callback, (void *) player);
+ fluid_player_callback, (void *) player);
- if (player->sample_timer == NULL) {
+ if(player->sample_timer == NULL)
+ {
return FLUID_FAILED;
}
}
+
return FLUID_OK;
}
@@ -1692,12 +2059,16 @@ fluid_player_play(fluid_player_t *player)
int
fluid_player_stop(fluid_player_t *player)
{
- if (player->system_timer != NULL) {
+ if(player->system_timer != NULL)
+ {
delete_fluid_timer(player->system_timer);
}
- if (player->sample_timer != NULL) {
+
+ if(player->sample_timer != NULL)
+ {
delete_fluid_sample_timer(player->synth, player->sample_timer);
}
+
player->status = FLUID_PLAYER_DONE;
player->sample_timer = NULL;
player->system_timer = NULL;
@@ -1717,13 +2088,35 @@ fluid_player_get_status(fluid_player_t *player)
}
/**
- * Enable looping of a MIDI player
+ * Seek in the currently playing file.
+ * @param player MIDI player instance
+ * @param ticks the position to seek to in the current file
+ * @return #FLUID_FAILED if ticks is negative or after the latest tick of the file,
+ * #FLUID_OK otherwise
+ * @since 2.0.0
+ *
+ * The actual seek is performed during the player_callback.
+ */
+int fluid_player_seek(fluid_player_t *player, int ticks)
+{
+ if(ticks < 0 || ticks > fluid_player_get_total_ticks(player))
+ {
+ return FLUID_FAILED;
+ }
+
+ player->seek_ticks = ticks;
+ return FLUID_OK;
+}
+
+
+/**
+ * Enable looping of a MIDI player
* @param player MIDI player instance
* @param loop Times left to loop the playlist. -1 means loop infinitely.
* @return Always returns #FLUID_OK
* @since 1.1.0
*
- * For example, if you want to loop the playlist twice, set loop to 2
+ * For example, if you want to loop the playlist twice, set loop to 2
* and call this function before you start the player.
*/
int fluid_player_set_loop(fluid_player_t *player, int loop)
@@ -1746,8 +2139,8 @@ int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
player->start_ticks = player->cur_ticks;
FLUID_LOG(FLUID_DBG,
- "tempo=%d, tick time=%f msec, cur time=%d msec, cur tick=%d",
- tempo, player->deltatime, player->cur_msec, player->cur_ticks);
+ "tempo=%d, tick time=%f msec, cur time=%d msec, cur tick=%d",
+ tempo, player->deltatime, player->cur_msec, player->cur_ticks);
return FLUID_OK;
}
@@ -1758,10 +2151,9 @@ int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
* @param bpm Tempo in beats per minute
* @return Always returns #FLUID_OK
*/
-int
-fluid_player_set_bpm(fluid_player_t *player, int bpm)
+int fluid_player_set_bpm(fluid_player_t *player, int bpm)
{
- return fluid_player_set_midi_tempo(player, (int) ((double) 60 * 1e6 / bpm));
+ return fluid_player_set_midi_tempo(player, (int)((double) 60 * 1e6 / bpm));
}
/**
@@ -1772,21 +2164,82 @@ fluid_player_set_bpm(fluid_player_t *player, int bpm)
int
fluid_player_join(fluid_player_t *player)
{
- if (player->system_timer) {
+ if(player->system_timer)
+ {
return fluid_timer_join(player->system_timer);
- } else if (player->sample_timer) {
+ }
+ else if(player->sample_timer)
+ {
/* Busy-wait loop, since there's no thread to wait for... */
- while (player->status != FLUID_PLAYER_DONE) {
-#if defined(WIN32)
- Sleep(10);
-#else
- usleep(10000);
-#endif
+ while(player->status != FLUID_PLAYER_DONE)
+ {
+ fluid_msleep(10);
}
}
+
return FLUID_OK;
}
+/**
+ * Get the number of tempo ticks passed.
+ * @param player MIDI player instance
+ * @return The number of tempo ticks passed
+ * @since 1.1.7
+ */
+int fluid_player_get_current_tick(fluid_player_t *player)
+{
+ return player->cur_ticks;
+}
+
+/**
+ * Looks through all available MIDI tracks and gets the absolute tick of the very last event to play.
+ * @param player MIDI player instance
+ * @return Total tick count of the sequence
+ * @since 1.1.7
+ */
+int fluid_player_get_total_ticks(fluid_player_t *player)
+{
+ int i;
+ int maxTicks = 0;
+
+ for(i = 0; i < player->ntracks; i++)
+ {
+ if(player->track[i] != NULL)
+ {
+ int ticks = fluid_track_get_duration(player->track[i]);
+
+ if(ticks > maxTicks)
+ {
+ maxTicks = ticks;
+ }
+ }
+ }
+
+ return maxTicks;
+}
+
+/**
+ * Get the tempo of a MIDI player in beats per minute.
+ * @param player MIDI player instance
+ * @return MIDI player tempo in BPM
+ * @since 1.1.7
+ */
+int fluid_player_get_bpm(fluid_player_t *player)
+{
+ return (int)(60e6 / player->miditempo);
+}
+
+/**
+ * Get the tempo of a MIDI player.
+ * @param player MIDI player instance
+ * @return Tempo of the MIDI player (in microseconds per quarter note, as per MIDI file spec)
+ * @since 1.1.7
+ */
+int fluid_player_get_midi_tempo(fluid_player_t *player)
+{
+ return player->miditempo;
+}
+
/************************************************************************
* MIDI PARSER
*
@@ -1796,14 +2249,17 @@ fluid_player_join(fluid_player_t *player)
* new_fluid_midi_parser
*/
fluid_midi_parser_t *
-new_fluid_midi_parser ()
+new_fluid_midi_parser()
{
fluid_midi_parser_t *parser;
parser = FLUID_NEW(fluid_midi_parser_t);
- if (parser == NULL) {
+
+ if(parser == NULL)
+ {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
+
parser->status = 0; /* As long as the status is 0, the parser won't do anything -> no need to initialize all the fields. */
return parser;
}
@@ -1811,11 +2267,12 @@ new_fluid_midi_parser ()
/*
* delete_fluid_midi_parser
*/
-int
+void
delete_fluid_midi_parser(fluid_midi_parser_t *parser)
{
+ fluid_return_if_fail(parser != NULL);
+
FLUID_FREE(parser);
- return FLUID_OK;
}
/**
@@ -1824,6 +2281,11 @@ delete_fluid_midi_parser(fluid_midi_parser_t *parser)
* @param c Next character in MIDI stream
* @return A parsed MIDI event or NULL if none. Event is internal and should
* not be modified or freed and is only valid until next call to this function.
+ * @internal Do not expose this function to the public API. It would allow downstream
+ * apps to abuse fluidsynth as midi parser, e.g. feeding it with rawmidi and pull out
+ * the needed midi information using the getter functions of fluid_midi_event_t.
+ * This parser however is incomplete as it e.g. only provides a limited buffer to
+ * store and process SYSEX data (i.e. doesnt allow arbitrary lengths)
*/
fluid_midi_event_t *
fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
@@ -1832,8 +2294,10 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
/* Real-time messages (0xF8-0xFF) can occur anywhere, even in the middle
* of another message. */
- if (c >= 0xF8) {
- if (c == MIDI_SYSTEM_RESET) {
+ if(c >= 0xF8)
+ {
+ if(c == MIDI_SYSTEM_RESET)
+ {
parser->event.type = c;
parser->status = 0; /* clear the status */
return &parser->event;
@@ -1843,30 +2307,40 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
}
/* Status byte? - If previous message not yet complete, it is discarded (re-sync). */
- if (c & 0x80) {
+ if(c & 0x80)
+ {
/* Any status byte terminates SYSEX messages (not just 0xF7) */
- if (parser->status == MIDI_SYSEX && parser->nr_bytes > 0) {
+ if(parser->status == MIDI_SYSEX && parser->nr_bytes > 0)
+ {
event = &parser->event;
fluid_midi_event_set_sysex(event, parser->data, parser->nr_bytes,
- FALSE);
- } else
+ FALSE);
+ }
+ else
+ {
event = NULL;
+ }
- if (c < 0xF0) /* Voice category message? */
+ if(c < 0xF0) /* Voice category message? */
{
parser->channel = c & 0x0F;
parser->status = c & 0xF0;
/* The event consumes x bytes of data... (subtract 1 for the status byte) */
parser->nr_bytes_total = fluid_midi_event_length(parser->status)
- - 1;
+ - 1;
parser->nr_bytes = 0; /* 0 bytes read so far */
- } else if (c == MIDI_SYSEX) {
+ }
+ else if(c == MIDI_SYSEX)
+ {
parser->status = MIDI_SYSEX;
parser->nr_bytes = 0;
- } else
- parser->status = 0; /* Discard other system messages (0xF1-0xF7) */
+ }
+ else
+ {
+ parser->status = 0; /* Discard other system messages (0xF1-0xF7) */
+ }
return event; /* Return SYSEX event or NULL */
}
@@ -1874,11 +2348,14 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
/* Data/parameter byte */
/* Discard data bytes for events we don't care about */
- if (parser->status == 0)
+ if(parser->status == 0)
+ {
return NULL;
+ }
/* Max data size exceeded? (SYSEX messages only really) */
- if (parser->nr_bytes == FLUID_MIDI_PARSER_MAX_DATA_SIZE) {
+ if(parser->nr_bytes == FLUID_MIDI_PARSER_MAX_DATA_SIZE)
+ {
parser->status = 0; /* Discard the rest of the message */
return NULL;
}
@@ -1887,8 +2364,10 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
parser->data[parser->nr_bytes++] = c;
/* Do we still need more data to get this event complete? */
- if (parser->nr_bytes < parser->nr_bytes_total)
+ if(parser->status == MIDI_SYSEX || parser->nr_bytes < parser->nr_bytes_total)
+ {
return NULL;
+ }
/* Event is complete, return it.
* Running status byte MIDI feature is also handled here. */
@@ -1896,22 +2375,25 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
parser->event.channel = parser->channel;
parser->nr_bytes = 0; /* Reset data size, in case there are additional running status messages */
- switch (parser->status) {
- case NOTE_OFF:
- case NOTE_ON:
- case KEY_PRESSURE:
- case CONTROL_CHANGE:
- case PROGRAM_CHANGE:
- case CHANNEL_PRESSURE:
- parser->event.param1 = parser->data[0]; /* For example key number */
- parser->event.param2 = parser->data[1]; /* For example velocity */
- break;
- case PITCH_BEND:
- /* Pitch-bend is transmitted with 14-bit precision. */
- parser->event.param1 = (parser->data[1] << 7) | parser->data[0];
- break;
- default: /* Unlikely */
- return NULL;
+ switch(parser->status)
+ {
+ case NOTE_OFF:
+ case NOTE_ON:
+ case KEY_PRESSURE:
+ case CONTROL_CHANGE:
+ case PROGRAM_CHANGE:
+ case CHANNEL_PRESSURE:
+ parser->event.param1 = parser->data[0]; /* For example key number */
+ parser->event.param2 = parser->data[1]; /* For example velocity */
+ break;
+
+ case PITCH_BEND:
+ /* Pitch-bend is transmitted with 14-bit precision. */
+ parser->event.param1 = (parser->data[1] << 7) | parser->data[0];
+ break;
+
+ default: /* Unlikely */
+ return NULL;
}
return &parser->event;
@@ -1922,28 +2404,35 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
static int
fluid_midi_event_length(unsigned char event)
{
- switch (event & 0xF0) {
- case NOTE_OFF:
- case NOTE_ON:
- case KEY_PRESSURE:
- case CONTROL_CHANGE:
- case PITCH_BEND:
- return 3;
- case PROGRAM_CHANGE:
- case CHANNEL_PRESSURE:
- return 2;
- }
- switch (event) {
- case MIDI_TIME_CODE:
- case MIDI_SONG_SELECT:
- case 0xF4:
- case 0xF5:
- return 2;
- case MIDI_TUNE_REQUEST:
- return 1;
- case MIDI_SONG_POSITION:
- return 3;
+ switch(event & 0xF0)
+ {
+ case NOTE_OFF:
+ case NOTE_ON:
+ case KEY_PRESSURE:
+ case CONTROL_CHANGE:
+ case PITCH_BEND:
+ return 3;
+
+ case PROGRAM_CHANGE:
+ case CHANNEL_PRESSURE:
+ return 2;
+ }
+
+ switch(event)
+ {
+ case MIDI_TIME_CODE:
+ case MIDI_SONG_SELECT:
+ case 0xF4:
+ case 0xF5:
+ return 2;
+
+ case MIDI_TUNE_REQUEST:
+ return 1;
+
+ case MIDI_SONG_POSITION:
+ return 3;
}
+
return 1;
}
#endif
diff --git a/libs/fluidsynth/src/fluid_midi.h b/libs/fluidsynth/src/fluid_midi.h
index 90fcef7c91..9e34a0ffee 100644
--- a/libs/fluidsynth/src/fluid_midi.h
+++ b/libs/fluidsynth/src/fluid_midi.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -27,9 +27,9 @@
typedef struct _fluid_midi_parser_t fluid_midi_parser_t;
-fluid_midi_parser_t* new_fluid_midi_parser(void);
-int delete_fluid_midi_parser(fluid_midi_parser_t* parser);
-fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c);
+fluid_midi_parser_t *new_fluid_midi_parser(void);
+void delete_fluid_midi_parser(fluid_midi_parser_t *parser);
+fluid_midi_event_t *fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c);
/***************************************************************
@@ -40,140 +40,146 @@ fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigne
#define MAX_NUMBER_OF_TRACKS 128
-enum fluid_midi_event_type {
- /* channel messages */
- NOTE_OFF = 0x80,
- NOTE_ON = 0x90,
- KEY_PRESSURE = 0xa0,
- CONTROL_CHANGE = 0xb0,
- PROGRAM_CHANGE = 0xc0,
- CHANNEL_PRESSURE = 0xd0,
- PITCH_BEND = 0xe0,
- /* system exclusive */
- MIDI_SYSEX = 0xf0,
- /* system common - never in midi files */
- MIDI_TIME_CODE = 0xf1,
- MIDI_SONG_POSITION = 0xf2,
- MIDI_SONG_SELECT = 0xf3,
- MIDI_TUNE_REQUEST = 0xf6,
- MIDI_EOX = 0xf7,
- /* system real-time - never in midi files */
- MIDI_SYNC = 0xf8,
- MIDI_TICK = 0xf9,
- MIDI_START = 0xfa,
- MIDI_CONTINUE = 0xfb,
- MIDI_STOP = 0xfc,
- MIDI_ACTIVE_SENSING = 0xfe,
- MIDI_SYSTEM_RESET = 0xff,
- /* meta event - for midi files only */
- MIDI_META_EVENT = 0xff
+enum fluid_midi_event_type
+{
+ /* channel messages */
+ NOTE_OFF = 0x80,
+ NOTE_ON = 0x90,
+ KEY_PRESSURE = 0xa0,
+ CONTROL_CHANGE = 0xb0,
+ PROGRAM_CHANGE = 0xc0,
+ CHANNEL_PRESSURE = 0xd0,
+ PITCH_BEND = 0xe0,
+ /* system exclusive */
+ MIDI_SYSEX = 0xf0,
+ /* system common - never in midi files */
+ MIDI_TIME_CODE = 0xf1,
+ MIDI_SONG_POSITION = 0xf2,
+ MIDI_SONG_SELECT = 0xf3,
+ MIDI_TUNE_REQUEST = 0xf6,
+ MIDI_EOX = 0xf7,
+ /* system real-time - never in midi files */
+ MIDI_SYNC = 0xf8,
+ MIDI_TICK = 0xf9,
+ MIDI_START = 0xfa,
+ MIDI_CONTINUE = 0xfb,
+ MIDI_STOP = 0xfc,
+ MIDI_ACTIVE_SENSING = 0xfe,
+ MIDI_SYSTEM_RESET = 0xff,
+ /* meta event - for midi files only */
+ MIDI_META_EVENT = 0xff
};
-enum fluid_midi_control_change {
- BANK_SELECT_MSB = 0x00,
- MODULATION_MSB = 0x01,
- BREATH_MSB = 0x02,
- FOOT_MSB = 0x04,
- PORTAMENTO_TIME_MSB = 0x05,
- DATA_ENTRY_MSB = 0x06,
- VOLUME_MSB = 0x07,
- BALANCE_MSB = 0x08,
- PAN_MSB = 0x0A,
- EXPRESSION_MSB = 0x0B,
- EFFECTS1_MSB = 0x0C,
- EFFECTS2_MSB = 0x0D,
- GPC1_MSB = 0x10, /* general purpose controller */
- GPC2_MSB = 0x11,
- GPC3_MSB = 0x12,
- GPC4_MSB = 0x13,
- BANK_SELECT_LSB = 0x20,
- MODULATION_WHEEL_LSB = 0x21,
- BREATH_LSB = 0x22,
- FOOT_LSB = 0x24,
- PORTAMENTO_TIME_LSB = 0x25,
- DATA_ENTRY_LSB = 0x26,
- VOLUME_LSB = 0x27,
- BALANCE_LSB = 0x28,
- PAN_LSB = 0x2A,
- EXPRESSION_LSB = 0x2B,
- EFFECTS1_LSB = 0x2C,
- EFFECTS2_LSB = 0x2D,
- GPC1_LSB = 0x30,
- GPC2_LSB = 0x31,
- GPC3_LSB = 0x32,
- GPC4_LSB = 0x33,
- SUSTAIN_SWITCH = 0x40,
- PORTAMENTO_SWITCH = 0x41,
- SOSTENUTO_SWITCH = 0x42,
- SOFT_PEDAL_SWITCH = 0x43,
- LEGATO_SWITCH = 0x45,
- HOLD2_SWITCH = 0x45,
- SOUND_CTRL1 = 0x46,
- SOUND_CTRL2 = 0x47,
- SOUND_CTRL3 = 0x48,
- SOUND_CTRL4 = 0x49,
- SOUND_CTRL5 = 0x4A,
- SOUND_CTRL6 = 0x4B,
- SOUND_CTRL7 = 0x4C,
- SOUND_CTRL8 = 0x4D,
- SOUND_CTRL9 = 0x4E,
- SOUND_CTRL10 = 0x4F,
- GPC5 = 0x50,
- GPC6 = 0x51,
- GPC7 = 0x52,
- GPC8 = 0x53,
- PORTAMENTO_CTRL = 0x54,
- EFFECTS_DEPTH1 = 0x5B,
- EFFECTS_DEPTH2 = 0x5C,
- EFFECTS_DEPTH3 = 0x5D,
- EFFECTS_DEPTH4 = 0x5E,
- EFFECTS_DEPTH5 = 0x5F,
- DATA_ENTRY_INCR = 0x60,
- DATA_ENTRY_DECR = 0x61,
- NRPN_LSB = 0x62,
- NRPN_MSB = 0x63,
- RPN_LSB = 0x64,
- RPN_MSB = 0x65,
- ALL_SOUND_OFF = 0x78,
- ALL_CTRL_OFF = 0x79,
- LOCAL_CONTROL = 0x7A,
- ALL_NOTES_OFF = 0x7B,
- OMNI_OFF = 0x7C,
- OMNI_ON = 0x7D,
- POLY_OFF = 0x7E,
- POLY_ON = 0x7F
+enum fluid_midi_control_change
+{
+ BANK_SELECT_MSB = 0x00,
+ MODULATION_MSB = 0x01,
+ BREATH_MSB = 0x02,
+ FOOT_MSB = 0x04,
+ PORTAMENTO_TIME_MSB = 0x05,
+ DATA_ENTRY_MSB = 0x06,
+ VOLUME_MSB = 0x07,
+ BALANCE_MSB = 0x08,
+ PAN_MSB = 0x0A,
+ EXPRESSION_MSB = 0x0B,
+ EFFECTS1_MSB = 0x0C,
+ EFFECTS2_MSB = 0x0D,
+ GPC1_MSB = 0x10, /* general purpose controller */
+ GPC2_MSB = 0x11,
+ GPC3_MSB = 0x12,
+ GPC4_MSB = 0x13,
+ BANK_SELECT_LSB = 0x20,
+ MODULATION_WHEEL_LSB = 0x21,
+ BREATH_LSB = 0x22,
+ FOOT_LSB = 0x24,
+ PORTAMENTO_TIME_LSB = 0x25,
+ DATA_ENTRY_LSB = 0x26,
+ VOLUME_LSB = 0x27,
+ BALANCE_LSB = 0x28,
+ PAN_LSB = 0x2A,
+ EXPRESSION_LSB = 0x2B,
+ EFFECTS1_LSB = 0x2C,
+ EFFECTS2_LSB = 0x2D,
+ GPC1_LSB = 0x30,
+ GPC2_LSB = 0x31,
+ GPC3_LSB = 0x32,
+ GPC4_LSB = 0x33,
+ SUSTAIN_SWITCH = 0x40,
+ PORTAMENTO_SWITCH = 0x41,
+ SOSTENUTO_SWITCH = 0x42,
+ SOFT_PEDAL_SWITCH = 0x43,
+ LEGATO_SWITCH = 0x44,
+ HOLD2_SWITCH = 0x45,
+ SOUND_CTRL1 = 0x46,
+ SOUND_CTRL2 = 0x47,
+ SOUND_CTRL3 = 0x48,
+ SOUND_CTRL4 = 0x49,
+ SOUND_CTRL5 = 0x4A,
+ SOUND_CTRL6 = 0x4B,
+ SOUND_CTRL7 = 0x4C,
+ SOUND_CTRL8 = 0x4D,
+ SOUND_CTRL9 = 0x4E,
+ SOUND_CTRL10 = 0x4F,
+ GPC5 = 0x50,
+ GPC6 = 0x51,
+ GPC7 = 0x52,
+ GPC8 = 0x53,
+ PORTAMENTO_CTRL = 0x54,
+ EFFECTS_DEPTH1 = 0x5B,
+ EFFECTS_DEPTH2 = 0x5C,
+ EFFECTS_DEPTH3 = 0x5D,
+ EFFECTS_DEPTH4 = 0x5E,
+ EFFECTS_DEPTH5 = 0x5F,
+ DATA_ENTRY_INCR = 0x60,
+ DATA_ENTRY_DECR = 0x61,
+ NRPN_LSB = 0x62,
+ NRPN_MSB = 0x63,
+ RPN_LSB = 0x64,
+ RPN_MSB = 0x65,
+ ALL_SOUND_OFF = 0x78,
+ ALL_CTRL_OFF = 0x79,
+ LOCAL_CONTROL = 0x7A,
+ ALL_NOTES_OFF = 0x7B,
+ OMNI_OFF = 0x7C,
+ OMNI_ON = 0x7D,
+ POLY_OFF = 0x7E,
+ POLY_ON = 0x7F
};
/* General MIDI RPN event numbers (LSB, MSB = 0) */
-enum midi_rpn_event {
- RPN_PITCH_BEND_RANGE = 0x00,
- RPN_CHANNEL_FINE_TUNE = 0x01,
- RPN_CHANNEL_COARSE_TUNE = 0x02,
- RPN_TUNING_PROGRAM_CHANGE = 0x03,
- RPN_TUNING_BANK_SELECT = 0x04,
- RPN_MODULATION_DEPTH_RANGE = 0x05
+enum midi_rpn_event
+{
+ RPN_PITCH_BEND_RANGE = 0x00,
+ RPN_CHANNEL_FINE_TUNE = 0x01,
+ RPN_CHANNEL_COARSE_TUNE = 0x02,
+ RPN_TUNING_PROGRAM_CHANGE = 0x03,
+ RPN_TUNING_BANK_SELECT = 0x04,
+ RPN_MODULATION_DEPTH_RANGE = 0x05
};
-enum midi_meta_event {
- MIDI_COPYRIGHT = 0x02,
- MIDI_TRACK_NAME = 0x03,
- MIDI_INST_NAME = 0x04,
- MIDI_LYRIC = 0x05,
- MIDI_MARKER = 0x06,
- MIDI_CUE_POINT = 0x07,
- MIDI_EOT = 0x2f,
- MIDI_SET_TEMPO = 0x51,
- MIDI_SMPTE_OFFSET = 0x54,
- MIDI_TIME_SIGNATURE = 0x58,
- MIDI_KEY_SIGNATURE = 0x59,
- MIDI_SEQUENCER_EVENT = 0x7f
+enum midi_meta_event
+{
+ MIDI_TEXT = 0x01,
+ MIDI_COPYRIGHT = 0x02,
+ MIDI_TRACK_NAME = 0x03,
+ MIDI_INST_NAME = 0x04,
+ MIDI_LYRIC = 0x05,
+ MIDI_MARKER = 0x06,
+ MIDI_CUE_POINT = 0x07,
+ MIDI_EOT = 0x2f,
+ MIDI_SET_TEMPO = 0x51,
+ MIDI_SMPTE_OFFSET = 0x54,
+ MIDI_TIME_SIGNATURE = 0x58,
+ MIDI_KEY_SIGNATURE = 0x59,
+ MIDI_SEQUENCER_EVENT = 0x7f
};
/* MIDI SYSEX useful manufacturer values */
-enum midi_sysex_manuf {
- MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
- MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
- MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
+enum midi_sysex_manuf
+{
+ MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
+ MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
+ MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
};
#define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */
@@ -185,17 +191,18 @@ enum midi_sysex_manuf {
/**
* SYSEX tuning message IDs.
*/
-enum midi_sysex_tuning_msg_id {
- MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
- MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
- MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
- MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
- MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
- MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
- MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
- MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
- MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
- MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
+enum midi_sysex_tuning_msg_id
+{
+ MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
+ MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
+ MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
+ MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
+ MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
+ MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
+ MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
+ MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
+ MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
+ MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
};
/* General MIDI sub-ID #2 */
@@ -204,9 +211,9 @@ enum midi_sysex_tuning_msg_id {
enum fluid_driver_status
{
- FLUID_MIDI_READY,
- FLUID_MIDI_LISTENING,
- FLUID_MIDI_DONE
+ FLUID_MIDI_READY,
+ FLUID_MIDI_LISTENING,
+ FLUID_MIDI_DONE
};
/***************************************************************
@@ -214,58 +221,40 @@ enum fluid_driver_status
* TYPE DEFINITIONS & FUNCTION DECLARATIONS
*/
-/* From ctype.h */
-#define fluid_isascii(c) (((c) & ~0x7f) == 0)
-
-
-
/*
* fluid_midi_event_t
*/
-struct _fluid_midi_event_t {
- fluid_midi_event_t* next; /* Link to next event */
- void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */
- unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
- unsigned int param1; /* First parameter */
- unsigned int param2; /* Second parameter */
- unsigned char type; /* MIDI event type */
- unsigned char channel; /* MIDI channel */
+struct _fluid_midi_event_t
+{
+ fluid_midi_event_t *next; /* Link to next event */
+ void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */
+ unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
+ unsigned int param1; /* First parameter */
+ unsigned int param2; /* Second parameter */
+ unsigned char type; /* MIDI event type */
+ unsigned char channel; /* MIDI channel */
};
/*
* fluid_track_t
*/
-struct _fluid_track_t {
- char* name;
- int num;
- fluid_midi_event_t *first;
- fluid_midi_event_t *cur;
- fluid_midi_event_t *last;
- unsigned int ticks;
+struct _fluid_track_t
+{
+ char *name;
+ int num;
+ fluid_midi_event_t *first;
+ fluid_midi_event_t *cur;
+ fluid_midi_event_t *last;
+ unsigned int ticks;
};
typedef struct _fluid_track_t fluid_track_t;
-fluid_track_t* new_fluid_track(int num);
-int delete_fluid_track(fluid_track_t* track);
-int fluid_track_set_name(fluid_track_t* track, char* name);
-char* fluid_track_get_name(fluid_track_t* track);
-int fluid_track_add_event(fluid_track_t* track, fluid_midi_event_t* evt);
-fluid_midi_event_t* fluid_track_first_event(fluid_track_t* track);
-fluid_midi_event_t* fluid_track_next_event(fluid_track_t* track);
-int fluid_track_get_duration(fluid_track_t* track);
-int fluid_track_reset(fluid_track_t* track);
-
-int fluid_track_send_events(fluid_track_t* track,
- fluid_synth_t* synth,
- fluid_player_t* player,
- unsigned int ticks);
-
#define fluid_track_eot(track) ((track)->cur == NULL)
-/**
+/*
* fluid_playlist_item
* Used as the `data' elements of the fluid_player.playlist.
* Represents either a filename or a pre-loaded memory buffer.
@@ -273,92 +262,73 @@ int fluid_track_send_events(fluid_track_t* track,
*/
typedef struct
{
- char* filename; /** Name of file (owned); NULL if data pre-loaded */
- void* buffer; /** The MIDI file data (owned); NULL if filename */
+ char *filename; /** Name of file (owned); NULL if data pre-loaded */
+ void *buffer; /** The MIDI file data (owned); NULL if filename */
size_t buffer_len; /** Number of bytes in buffer; 0 if filename */
} fluid_playlist_item;
/*
* fluid_player
*/
-struct _fluid_player_t {
- int status;
- int ntracks;
- fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
- fluid_synth_t* synth;
- fluid_timer_t* system_timer;
- fluid_sample_timer_t* sample_timer;
-
- int loop; /* -1 = loop infinitely, otherwise times left to loop the playlist */
- fluid_list_t* playlist; /* List of fluid_playlist_item* objects */
- fluid_list_t* currentfile; /* points to an item in files, or NULL if not playing */
-
- char send_program_change; /* should we ignore the program changes? */
- char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */
- char reset_synth_between_songs; /* 1 if system reset should be sent to the synth between songs. */
- int start_ticks; /* the number of tempo ticks passed at the last tempo change */
- int cur_ticks; /* the number of tempo ticks passed */
- int begin_msec; /* the time (msec) of the beginning of the file */
- int start_msec; /* the start time of the last tempo change */
- int cur_msec; /* the current time */
- int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */
- double deltatime; /* milliseconds per midi tick. depends on set-tempo */
- unsigned int division;
-
- handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */
- void* playback_userdata; /* pointer to user-defined data passed to playback_callback function */
+struct _fluid_player_t
+{
+ int status;
+ int ntracks;
+ fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
+ fluid_synth_t *synth;
+ fluid_timer_t *system_timer;
+ fluid_sample_timer_t *sample_timer;
+
+ int loop; /* -1 = loop infinitely, otherwise times left to loop the playlist */
+ fluid_list_t *playlist; /* List of fluid_playlist_item* objects */
+ fluid_list_t *currentfile; /* points to an item in files, or NULL if not playing */
+
+ char send_program_change; /* should we ignore the program changes? */
+ char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */
+ char reset_synth_between_songs; /* 1 if system reset should be sent to the synth between songs. */
+ int seek_ticks; /* new position in tempo ticks (midi ticks) for seeking */
+ int start_ticks; /* the number of tempo ticks passed at the last tempo change */
+ int cur_ticks; /* the number of tempo ticks passed */
+ int begin_msec; /* the time (msec) of the beginning of the file */
+ int start_msec; /* the start time of the last tempo change */
+ int cur_msec; /* the current time */
+ int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */
+ double deltatime; /* milliseconds per midi tick. depends on set-tempo */
+ unsigned int division;
+
+ handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */
+ void *playback_userdata; /* pointer to user-defined data passed to playback_callback function */
};
-int fluid_player_add_track(fluid_player_t* player, fluid_track_t* track);
-int fluid_player_callback(void* data, unsigned int msec);
-int fluid_player_count_tracks(fluid_player_t* player);
-fluid_track_t* fluid_player_get_track(fluid_player_t* player, int i);
-int fluid_player_reset(fluid_player_t* player);
-int fluid_player_load(fluid_player_t* player, fluid_playlist_item *item);
-
-void fluid_player_settings(fluid_settings_t* settings);
+void fluid_player_settings(fluid_settings_t *settings);
/*
* fluid_midi_file
*/
-typedef struct {
- const char* buffer; /* Entire contents of MIDI file (borrowed) */
- int buf_len; /* Length of buffer, in bytes */
- int buf_pos; /* Current read position in contents buffer */
- int eof; /* The "end of file" condition */
- int running_status;
- int c;
- int type;
- int ntracks;
- int uses_smpte;
- unsigned int smpte_fps;
- unsigned int smpte_res;
- unsigned int division; /* If uses_SMPTE == 0 then division is
+typedef struct
+{
+ const char *buffer; /* Entire contents of MIDI file (borrowed) */
+ int buf_len; /* Length of buffer, in bytes */
+ int buf_pos; /* Current read position in contents buffer */
+ int eof; /* The "end of file" condition */
+ int running_status;
+ int c;
+ int type;
+ int ntracks;
+ int uses_smpte;
+ unsigned int smpte_fps;
+ unsigned int smpte_res;
+ unsigned int division; /* If uses_SMPTE == 0 then division is
ticks per beat (quarter-note) */
- double tempo; /* Beats per second (SI rules =) */
- int tracklen;
- int trackpos;
- int eot;
- int varlen;
- int dtime;
+ double tempo; /* Beats per second (SI rules =) */
+ int tracklen;
+ int trackpos;
+ int eot;
+ int varlen;
+ int dtime;
} fluid_midi_file;
-fluid_midi_file* new_fluid_midi_file(const char* buffer, size_t length);
-void delete_fluid_midi_file(fluid_midi_file* mf);
-int fluid_midi_file_read_mthd(fluid_midi_file* midifile);
-int fluid_midi_file_load_tracks(fluid_midi_file* midifile, fluid_player_t* player);
-int fluid_midi_file_read_track(fluid_midi_file* mf, fluid_player_t* player, int num);
-int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track);
-int fluid_midi_file_read_varlen(fluid_midi_file* mf);
-int fluid_midi_file_getc(fluid_midi_file* mf);
-int fluid_midi_file_push(fluid_midi_file* mf, int c);
-int fluid_midi_file_read(fluid_midi_file* mf, void* buf, int len);
-int fluid_midi_file_skip(fluid_midi_file* mf, int len);
-int fluid_midi_file_eof(fluid_midi_file* mf);
-int fluid_midi_file_read_tracklen(fluid_midi_file* mf);
-int fluid_midi_file_eot(fluid_midi_file* mf);
-int fluid_midi_file_get_division(fluid_midi_file* midifile);
#define FLUID_MIDI_PARSER_MAX_DATA_SIZE 1024 /**< Maximum size of MIDI parameters/data (largest is SYSEX data) */
@@ -366,17 +336,15 @@ int fluid_midi_file_get_division(fluid_midi_file* midifile);
/*
* fluid_midi_parser_t
*/
-struct _fluid_midi_parser_t {
- unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */
- unsigned char channel; /* The channel of the event that is received (in case of a channel event) */
- unsigned int nr_bytes; /* How many bytes have been read for the current event? */
- unsigned int nr_bytes_total; /* How many bytes does the current event type include? */
- unsigned char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */
- fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */
+struct _fluid_midi_parser_t
+{
+ unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */
+ unsigned char channel; /* The channel of the event that is received (in case of a channel event) */
+ unsigned int nr_bytes; /* How many bytes have been read for the current event? */
+ unsigned int nr_bytes_total; /* How many bytes does the current event type include? */
+ unsigned char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */
+ fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */
};
-int fluid_isasciistring(char* s);
-long fluid_getlength(unsigned char *s);
-
#endif /* _FLUID_MIDI_H */
diff --git a/libs/fluidsynth/src/fluid_mod.c b/libs/fluidsynth/src/fluid_mod.c
index 5931aa52a6..9a48ed45d8 100644
--- a/libs/fluidsynth/src/fluid_mod.c
+++ b/libs/fluidsynth/src/fluid_mod.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -22,389 +22,446 @@
#include "fluid_chan.h"
#include "fluid_voice.h"
-/*
- * fluid_mod_clone
+/**
+ * Clone the modulators destination, sources, flags and amount.
+ * @param mod the modulator to store the copy to
+ * @param src the source modulator to retrieve the information from
+ * @note The \c next member of \c mod will be left unchanged.
*/
void
-fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src)
+fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src)
{
- mod->dest = src->dest;
- mod->src1 = src->src1;
- mod->flags1 = src->flags1;
- mod->src2 = src->src2;
- mod->flags2 = src->flags2;
- mod->amount = src->amount;
+ mod->dest = src->dest;
+ mod->src1 = src->src1;
+ mod->flags1 = src->flags1;
+ mod->src2 = src->src2;
+ mod->flags2 = src->flags2;
+ mod->amount = src->amount;
}
/**
* Set a modulator's primary source controller and flags.
- * @param mod Modulator
+ * @param mod The modulator instance
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
* @param flags Flags determining mapping function and whether the source
* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
* (#FLUID_MOD_CC), see #fluid_mod_flags.
*/
void
-fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags)
+fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags)
{
- mod->src1 = src;
- mod->flags1 = flags;
+ mod->src1 = src;
+ mod->flags1 = flags;
}
/**
* Set a modulator's secondary source controller and flags.
- * @param mod Modulator
+ * @param mod The modulator instance
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
* @param flags Flags determining mapping function and whether the source
* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
* (#FLUID_MOD_CC), see #fluid_mod_flags.
*/
void
-fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags)
+fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags)
{
- mod->src2 = src;
- mod->flags2 = flags;
+ mod->src2 = src;
+ mod->flags2 = flags;
}
/**
* Set the destination effect of a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @param dest Destination generator (#fluid_gen_type)
*/
void
-fluid_mod_set_dest(fluid_mod_t* mod, int dest)
+fluid_mod_set_dest(fluid_mod_t *mod, int dest)
{
- mod->dest = dest;
+ mod->dest = dest;
}
/**
* Set the scale amount of a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @param amount Scale amount to assign
*/
void
-fluid_mod_set_amount(fluid_mod_t* mod, double amount)
+fluid_mod_set_amount(fluid_mod_t *mod, double amount)
{
- mod->amount = (double) amount;
+ mod->amount = (double) amount;
}
/**
* Get the primary source value from a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @return The primary source value (#fluid_mod_src or a MIDI CC controller value).
*/
int
-fluid_mod_get_source1(fluid_mod_t* mod)
+fluid_mod_get_source1(const fluid_mod_t *mod)
{
- return mod->src1;
+ return mod->src1;
}
/**
* Get primary source flags from a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @return The primary source flags (#fluid_mod_flags).
*/
int
-fluid_mod_get_flags1(fluid_mod_t* mod)
+fluid_mod_get_flags1(const fluid_mod_t *mod)
{
- return mod->flags1;
+ return mod->flags1;
}
/**
* Get the secondary source value from a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @return The secondary source value (#fluid_mod_src or a MIDI CC controller value).
*/
int
-fluid_mod_get_source2(fluid_mod_t* mod)
+fluid_mod_get_source2(const fluid_mod_t *mod)
{
- return mod->src2;
+ return mod->src2;
}
/**
* Get secondary source flags from a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @return The secondary source flags (#fluid_mod_flags).
*/
int
-fluid_mod_get_flags2(fluid_mod_t* mod)
+fluid_mod_get_flags2(const fluid_mod_t *mod)
{
- return mod->flags2;
+ return mod->flags2;
}
/**
* Get destination effect from a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @return Destination generator (#fluid_gen_type)
*/
int
-fluid_mod_get_dest(fluid_mod_t* mod)
+fluid_mod_get_dest(const fluid_mod_t *mod)
{
- return mod->dest;
+ return mod->dest;
}
/**
* Get the scale amount from a modulator.
- * @param mod Modulator
+ * @param mod The modulator instance
* @return Scale amount
*/
double
-fluid_mod_get_amount(fluid_mod_t* mod)
+fluid_mod_get_amount(const fluid_mod_t *mod)
+{
+ return (double) mod->amount;
+}
+
+/*
+ * retrieves the initial value from the given source of the modulator
+ */
+static fluid_real_t
+fluid_mod_get_source_value(const unsigned char mod_src,
+ const unsigned char mod_flags,
+ fluid_real_t *range,
+ const fluid_voice_t *voice
+ )
{
- return (fluid_real_t) mod->amount;
+ const fluid_channel_t *chan = voice->channel;
+ fluid_real_t val;
+
+ if(mod_flags & FLUID_MOD_CC)
+ {
+ /* From MIDI Recommended Practice (RP-036) Default Pan Formula:
+ * "Since MIDI controller values range from 0 to 127, the exact center
+ * of the range, 63.5, cannot be represented. Therefore, the effective
+ * range for CC#10 is modified to be 1 to 127, and values 0 and 1 both
+ * pan hard left. The recommended method is to subtract 1 from the
+ * value of CC#10, and saturate the result to be non-negative."
+ *
+ * We treat the balance control in exactly the same way, as the same
+ * problem applies here as well.
+ */
+ if(mod_src == PAN_MSB || mod_src == BALANCE_MSB)
+ {
+ *range = 126;
+ val = fluid_channel_get_cc(chan, mod_src) - 1;
+
+ if(val < 0)
+ {
+ val = 0;
+ }
+ }
+ else
+ {
+ val = fluid_channel_get_cc(chan, mod_src);
+ }
+ }
+ else
+ {
+ switch(mod_src)
+ {
+ case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
+ val = *range;
+ break;
+
+ case FLUID_MOD_VELOCITY:
+ val = fluid_voice_get_actual_velocity(voice);
+ break;
+
+ case FLUID_MOD_KEY:
+ val = fluid_voice_get_actual_key(voice);
+ break;
+
+ case FLUID_MOD_KEYPRESSURE:
+ val = fluid_channel_get_key_pressure(chan, voice->key);
+ break;
+
+ case FLUID_MOD_CHANNELPRESSURE:
+ val = fluid_channel_get_channel_pressure(chan);
+ break;
+
+ case FLUID_MOD_PITCHWHEEL:
+ val = fluid_channel_get_pitch_bend(chan);
+ *range = 0x4000;
+ break;
+
+ case FLUID_MOD_PITCHWHEELSENS:
+ val = fluid_channel_get_pitch_wheel_sensitivity(chan);
+ break;
+
+ default:
+ FLUID_LOG(FLUID_ERR, "Unknown modulator source '%d', disabling modulator.", mod_src);
+ val = 0.0;
+ }
+ }
+
+ return val;
}
+/**
+ * transforms the initial value retrieved by \c fluid_mod_get_source_value into [0.0;1.0]
+ */
+static fluid_real_t
+fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, const fluid_real_t range)
+{
+ /* normalized value, i.e. usually in the range [0;1]
+ *
+ * if val was retrieved from pitch_bend then [-0.5;0.5]
+ */
+ const fluid_real_t val_norm = val / range;
+
+ /* we could also only switch case the lower nibble of mod_flags, however
+ * this would keep us from adding further mod types in the future
+ *
+ * instead just remove the flag(s) we already took care of
+ */
+ mod_flags &= ~FLUID_MOD_CC;
+
+ switch(mod_flags/* & 0x0f*/)
+ {
+ case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =0 */
+ val = val_norm;
+ break;
+
+ case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =1 */
+ val = 1.0f - val_norm;
+ break;
+
+ case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =2 */
+ val = -1.0f + 2.0f * val_norm;
+ break;
+
+ case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =3 */
+ val = 1.0f - 2.0f * val_norm;
+ break;
+
+ case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =4 */
+ val = fluid_concave(127 * (val_norm));
+ break;
+
+ case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =5 */
+ val = fluid_concave(127 * (1.0f - val_norm));
+ break;
+
+ case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =6 */
+ val = (val_norm > 0.5f) ? fluid_concave(127 * 2 * (val_norm - 0.5f))
+ : -fluid_concave(127 * 2 * (0.5f - val_norm));
+ break;
+
+ case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =7 */
+ val = (val_norm > 0.5f) ? -fluid_concave(127 * 2 * (val_norm - 0.5f))
+ : fluid_concave(127 * 2 * (0.5f - val_norm));
+ break;
+
+ case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =8 */
+ val = fluid_convex(127 * (val_norm));
+ break;
+
+ case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =9 */
+ val = fluid_convex(127 * (1.0f - val_norm));
+ break;
+
+ case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =10 */
+ val = (val_norm > 0.5f) ? fluid_convex(127 * 2 * (val_norm - 0.5f))
+ : -fluid_convex(127 * 2 * (0.5f - val_norm));
+ break;
+
+ case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =11 */
+ val = (val_norm > 0.5f) ? -fluid_convex(127 * 2 * (val_norm - 0.5f))
+ : fluid_convex(127 * 2 * (0.5f - val_norm));
+ break;
+
+ case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =12 */
+ val = (val_norm >= 0.5f) ? 1.0f : 0.0f;
+ break;
+
+ case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =13 */
+ val = (val_norm >= 0.5f) ? 0.0f : 1.0f;
+ break;
+
+ case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =14 */
+ val = (val_norm >= 0.5f) ? 1.0f : -1.0f;
+ break;
+
+ case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =15 */
+ val = (val_norm >= 0.5f) ? -1.0f : 1.0f;
+ break;
+
+ /*
+ * MIDI CCs only have a resolution of 7 bits. The closer val_norm gets to 1,
+ * the less will be the resulting change of the sinus. When using this sin()
+ * for scaling the cutoff frequency, there will be no audible difference between
+ * MIDI CCs 118 to 127. To avoid this waste of CCs multiply with 0.87
+ * (at least for unipolar) which makes sin() never get to 1.0 but to 0.98 which
+ * is close enough.
+ */
+ case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* custom sin(x) */
+ val = sin(M_PI / 2 * val_norm * 0.87);
+ break;
+
+ case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* custom */
+ val = sin(M_PI / 2 * (1.0f - val_norm) * 0.87);
+ break;
+
+ case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* custom */
+ val = (val_norm > 0.5f) ? sin(M_PI / 2 * 2 * (val_norm - 0.5f))
+ : -sin(M_PI / 2 * 2 * (0.5f - val_norm));
+ break;
+
+ case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* custom */
+ val = (val_norm > 0.5f) ? -sin(M_PI / 2 * 2 * (val_norm - 0.5f))
+ : sin(M_PI / 2 * 2 * (0.5f - val_norm));
+ break;
+
+ default:
+ FLUID_LOG(FLUID_ERR, "Unknown modulator type '%d', disabling modulator.", mod_flags);
+ val = 0.0f;
+ break;
+ }
+
+ return val;
+}
/*
* fluid_mod_get_value
*/
fluid_real_t
-fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice)
+fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
{
- fluid_real_t v1 = 0.0, v2 = 1.0;
- fluid_real_t range1 = 127.0, range2 = 127.0;
-
- if (chan == NULL) {
- return 0.0f;
- }
-
- /* 'special treatment' for default controller
- *
- * Reference: SF2.01 section 8.4.2
- *
- * The GM default controller 'vel-to-filter cut off' is not clearly
- * defined: If implemented according to the specs, the filter
- * frequency jumps between vel=63 and vel=64. To maintain
- * compatibility with existing sound fonts, the implementation is
- * 'hardcoded', it is impossible to implement using only one
- * modulator otherwise.
- *
- * I assume here, that the 'intention' of the paragraph is one
- * octave (1200 cents) filter frequency shift between vel=127 and
- * vel=64. 'amount' is (-2400), at least as long as the controller
- * is set to default.
- *
- * Further, the 'appearance' of the modulator (source enumerator,
- * destination enumerator, flags etc) is different from that
- * described in section 8.4.2, but it matches the definition used in
- * several SF2.1 sound fonts (where it is used only to turn it off).
- * */
- if ((mod->src2 == FLUID_MOD_VELOCITY) &&
- (mod->src1 == FLUID_MOD_VELOCITY) &&
- (mod->flags1 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
- | FLUID_MOD_NEGATIVE | FLUID_MOD_LINEAR)) &&
- (mod->flags2 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
- | FLUID_MOD_POSITIVE | FLUID_MOD_SWITCH)) &&
- (mod->dest == GEN_FILTERFC)) {
+ extern fluid_mod_t default_vel2filter_mod;
+
+ fluid_real_t v1 = 0.0, v2 = 1.0;
+ fluid_real_t range1 = 127.0, range2 = 127.0;
+
+ /* 'special treatment' for default controller
+ *
+ * Reference: SF2.01 section 8.4.2
+ *
+ * The GM default controller 'vel-to-filter cut off' is not clearly
+ * defined: If implemented according to the specs, the filter
+ * frequency jumps between vel=63 and vel=64. To maintain
+ * compatibility with existing sound fonts, the implementation is
+ * 'hardcoded', it is impossible to implement using only one
+ * modulator otherwise.
+ *
+ * I assume here, that the 'intention' of the paragraph is one
+ * octave (1200 cents) filter frequency shift between vel=127 and
+ * vel=64. 'amount' is (-2400), at least as long as the controller
+ * is set to default.
+ *
+ * Further, the 'appearance' of the modulator (source enumerator,
+ * destination enumerator, flags etc) is different from that
+ * described in section 8.4.2, but it matches the definition used in
+ * several SF2.1 sound fonts (where it is used only to turn it off).
+ * */
+ if(fluid_mod_test_identity(mod, &default_vel2filter_mod))
+ {
// S. Christian Collins' mod, to stop forcing velocity based filtering
-/*
- if (voice->vel < 64){
- return (fluid_real_t) mod->amount / 2.0;
- } else {
- return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
+ /*
+ if (voice->vel < 64){
+ return (fluid_real_t) mod->amount / 2.0;
+ } else {
+ return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
+ }
+ */
+ return 0; // (fluid_real_t) mod->amount / 2.0;
}
-*/
- return 0; // (fluid_real_t) mod->amount / 2.0;
- }
+
// end S. Christian Collins' mod
- /* get the initial value of the first source */
- if (mod->src1 > 0) {
- if (mod->flags1 & FLUID_MOD_CC) {
- v1 = fluid_channel_get_cc(chan, mod->src1);
- } else { /* source 1 is one of the direct controllers */
- switch (mod->src1) {
- case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
- v1 = range1;
- break;
- case FLUID_MOD_VELOCITY:
- v1 = voice->vel;
- break;
- case FLUID_MOD_KEY:
- v1 = voice->key;
- break;
- case FLUID_MOD_KEYPRESSURE:
- v1 = fluid_channel_get_key_pressure (chan);
- break;
- case FLUID_MOD_CHANNELPRESSURE:
- v1 = fluid_channel_get_channel_pressure (chan);
- break;
- case FLUID_MOD_PITCHWHEEL:
- v1 = fluid_channel_get_pitch_bend (chan);
- range1 = 0x4000;
- break;
- case FLUID_MOD_PITCHWHEELSENS:
- v1 = fluid_channel_get_pitch_wheel_sensitivity (chan);
- break;
- default:
- v1 = 0.0;
- }
- }
+ /* get the initial value of the first source */
+ if(mod->src1 > 0)
+ {
+ v1 = fluid_mod_get_source_value(mod->src1, mod->flags1, &range1, voice);
- /* transform the input value */
- switch (mod->flags1 & 0x0f) {
- case 0: /* linear, unipolar, positive */
- v1 /= range1;
- break;
- case 1: /* linear, unipolar, negative */
- v1 = 1.0f - v1 / range1;
- break;
- case 2: /* linear, bipolar, positive */
- v1 = -1.0f + 2.0f * v1 / range1;
- break;
- case 3: /* linear, bipolar, negative */
- v1 = 1.0f - 2.0f * v1 / range1;
- break;
- case 4: /* concave, unipolar, positive */
- v1 = fluid_concave(v1);
- break;
- case 5: /* concave, unipolar, negative */
- v1 = fluid_concave(127 - v1);
- break;
- case 6: /* concave, bipolar, positive */
- v1 = (v1 > 64)? fluid_concave(2 * (v1 - 64)) : -fluid_concave(2 * (64 - v1));
- break;
- case 7: /* concave, bipolar, negative */
- v1 = (v1 > 64)? -fluid_concave(2 * (v1 - 64)) : fluid_concave(2 * (64 - v1));
- break;
- case 8: /* convex, unipolar, positive */
- v1 = fluid_convex(v1);
- break;
- case 9: /* convex, unipolar, negative */
- v1 = fluid_convex(127 - v1);
- break;
- case 10: /* convex, bipolar, positive */
- v1 = (v1 > 64)? fluid_convex(2 * (v1 - 64)) : -fluid_convex(2 * (64 - v1));
- break;
- case 11: /* convex, bipolar, negative */
- v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1));
- break;
- case 12: /* switch, unipolar, positive */
- v1 = (v1 >= 64)? 1.0f : 0.0f;
- break;
- case 13: /* switch, unipolar, negative */
- v1 = (v1 >= 64)? 0.0f : 1.0f;
- break;
- case 14: /* switch, bipolar, positive */
- v1 = (v1 >= 64)? 1.0f : -1.0f;
- break;
- case 15: /* switch, bipolar, negative */
- v1 = (v1 >= 64)? -1.0f : 1.0f;
- break;
+ /* transform the input value */
+ v1 = fluid_mod_transform_source_value(v1, mod->flags1, range1);
}
- } else {
- return 0.0;
- }
-
- /* no need to go further */
- if (v1 == 0.0f) {
- return 0.0f;
- }
-
- /* get the second input source */
- if (mod->src2 > 0) {
- if (mod->flags2 & FLUID_MOD_CC) {
- v2 = fluid_channel_get_cc(chan, mod->src2);
- } else {
- switch (mod->src2) {
- case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
- v2 = range2;
- break;
- case FLUID_MOD_VELOCITY:
- v2 = voice->vel;
- break;
- case FLUID_MOD_KEY:
- v2 = voice->key;
- break;
- case FLUID_MOD_KEYPRESSURE:
- v2 = fluid_channel_get_key_pressure (chan);
- break;
- case FLUID_MOD_CHANNELPRESSURE:
- v2 = fluid_channel_get_channel_pressure (chan);
- break;
- case FLUID_MOD_PITCHWHEEL:
- v2 = fluid_channel_get_pitch_bend (chan);
- break;
- case FLUID_MOD_PITCHWHEELSENS:
- v2 = fluid_channel_get_pitch_wheel_sensitivity (chan);
- break;
- default:
- v1 = 0.0f;
- }
+ else
+ {
+ return 0.0;
}
- /* transform the second input value */
- switch (mod->flags2 & 0x0f) {
- case 0: /* linear, unipolar, positive */
- v2 /= range2;
- break;
- case 1: /* linear, unipolar, negative */
- v2 = 1.0f - v2 / range2;
- break;
- case 2: /* linear, bipolar, positive */
- v2 = -1.0f + 2.0f * v2 / range2;
- break;
- case 3: /* linear, bipolar, negative */
- v2 = -1.0f + 2.0f * v2 / range2;
- break;
- case 4: /* concave, unipolar, positive */
- v2 = fluid_concave(v2);
- break;
- case 5: /* concave, unipolar, negative */
- v2 = fluid_concave(127 - v2);
- break;
- case 6: /* concave, bipolar, positive */
- v2 = (v2 > 64)? fluid_concave(2 * (v2 - 64)) : -fluid_concave(2 * (64 - v2));
- break;
- case 7: /* concave, bipolar, negative */
- v2 = (v2 > 64)? -fluid_concave(2 * (v2 - 64)) : fluid_concave(2 * (64 - v2));
- break;
- case 8: /* convex, unipolar, positive */
- v2 = fluid_convex(v2);
- break;
- case 9: /* convex, unipolar, negative */
- v2 = 1.0f - fluid_convex(v2);
- break;
- case 10: /* convex, bipolar, positive */
- v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
- break;
- case 11: /* convex, bipolar, negative */
- v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
- break;
- case 12: /* switch, unipolar, positive */
- v2 = (v2 >= 64)? 1.0f : 0.0f;
- break;
- case 13: /* switch, unipolar, negative */
- v2 = (v2 >= 64)? 0.0f : 1.0f;
- break;
- case 14: /* switch, bipolar, positive */
- v2 = (v2 >= 64)? 1.0f : -1.0f;
- break;
- case 15: /* switch, bipolar, negative */
- v2 = (v2 >= 64)? -1.0f : 1.0f;
- break;
+ /* no need to go further */
+ if(v1 == 0.0f)
+ {
+ return 0.0f;
+ }
+
+ /* get the second input source */
+ if(mod->src2 > 0)
+ {
+ v2 = fluid_mod_get_source_value(mod->src2, mod->flags2, &range2, voice);
+
+ /* transform the second input value */
+ v2 = fluid_mod_transform_source_value(v2, mod->flags2, range2);
+ }
+ else
+ {
+ v2 = 1.0f;
}
- } else {
- v2 = 1.0f;
- }
- /* it's as simple as that: */
- return (fluid_real_t) mod->amount * v1 * v2;
+ /* it's as simple as that: */
+ return (fluid_real_t) mod->amount * v1 * v2;
}
/**
* Create a new uninitialized modulator structure.
* @return New allocated modulator or NULL if out of memory
*/
-fluid_mod_t*
-fluid_mod_new()
+fluid_mod_t *
+new_fluid_mod()
{
- fluid_mod_t* mod = FLUID_NEW (fluid_mod_t);
- if (mod == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- return mod;
+ fluid_mod_t *mod = FLUID_NEW(fluid_mod_t);
+
+ if(mod == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ return mod;
}
/**
@@ -412,9 +469,21 @@ fluid_mod_new()
* @param mod Modulator to free
*/
void
-fluid_mod_delete (fluid_mod_t *mod)
+delete_fluid_mod(fluid_mod_t *mod)
+{
+ FLUID_FREE(mod);
+}
+
+/**
+ * Returns the size of the fluid_mod_t structure.
+ *
+ * Useful in low latency scenarios e.g. to allocate a modulator on the stack.
+ *
+ * @return Size of fluid_mod_t in bytes
+ */
+size_t fluid_mod_sizeof()
{
- FLUID_FREE(mod);
+ return sizeof(fluid_mod_t);
}
/**
@@ -426,63 +495,181 @@ fluid_mod_delete (fluid_mod_t *mod)
* SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'.
*/
int
-fluid_mod_test_identity (fluid_mod_t *mod1, fluid_mod_t *mod2)
+fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2)
+{
+ return mod1->dest == mod2->dest
+ && mod1->src1 == mod2->src1
+ && mod1->src2 == mod2->src2
+ && mod1->flags1 == mod2->flags1
+ && mod1->flags2 == mod2->flags2;
+}
+
+/**
+ * Check if the modulator has the given source.
+ *
+ * @param mod The modulator instance
+ * @param cc Boolean value indicating if ctrl is a CC controller or not
+ * @param ctrl The source to check for (if \c cc == FALSE : a value of type #fluid_mod_src, else the value of the MIDI CC to check for)
+ *
+ * @return TRUE if the modulator has the given source, FALSE otherwise.
+ */
+int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl)
+{
+ return
+ (
+ (
+ ((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) != 0) && (cc != 0))
+ || ((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) == 0) && (cc == 0))
+ )
+ ||
+ (
+ ((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) != 0) && (cc != 0))
+ || ((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) == 0) && (cc == 0))
+ )
+ );
+}
+
+/**
+ * Check if the modulator has the given destination.
+ * @param mod The modulator instance
+ * @param gen The destination generator of type #fluid_gen_type to check for
+ * @return TRUE if the modulator has the given destination, FALSE otherwise.
+ */
+int fluid_mod_has_dest(const fluid_mod_t *mod, int gen)
{
- return mod1->dest == mod2->dest
- && mod1->src1 == mod2->src1
- && mod1->src2 == mod2->src2
- && mod1->flags1 == mod2->flags1
- && mod1->flags2 == mod2->flags2;
+ return mod->dest == gen;
}
+
/* debug function: Prints the contents of a modulator */
-void fluid_dump_modulator(fluid_mod_t * mod){
- int src1=mod->src1;
- int dest=mod->dest;
- int src2=mod->src2;
- int flags1=mod->flags1;
- int flags2=mod->flags2;
- fluid_real_t amount=(fluid_real_t)mod->amount;
-
- printf("Src: ");
- if (flags1 & FLUID_MOD_CC){
- printf("MIDI CC=%i",src1);
- } else {
- switch(src1){
- case FLUID_MOD_NONE:
- printf("None"); break;
- case FLUID_MOD_VELOCITY:
- printf("note-on velocity"); break;
- case FLUID_MOD_KEY:
- printf("Key nr"); break;
- case FLUID_MOD_KEYPRESSURE:
- printf("Poly pressure"); break;
- case FLUID_MOD_CHANNELPRESSURE:
- printf("Chan pressure"); break;
- case FLUID_MOD_PITCHWHEEL:
- printf("Pitch Wheel"); break;
- case FLUID_MOD_PITCHWHEELSENS:
- printf("Pitch Wheel sens"); break;
- default:
- printf("(unknown: %i)", src1);
- }; /* switch src1 */
- }; /* if not CC */
- if (flags1 & FLUID_MOD_NEGATIVE){printf("- ");} else {printf("+ ");};
- if (flags1 & FLUID_MOD_BIPOLAR){printf("bip ");} else {printf("unip ");};
- printf("-> ");
- switch(dest){
- case GEN_FILTERQ: printf("Q"); break;
- case GEN_FILTERFC: printf("fc"); break;
- case GEN_VIBLFOTOPITCH: printf("VibLFO-to-pitch"); break;
- case GEN_MODENVTOPITCH: printf("ModEnv-to-pitch"); break;
- case GEN_MODLFOTOPITCH: printf("ModLFO-to-pitch"); break;
- case GEN_CHORUSSEND: printf("Chorus send"); break;
- case GEN_REVERBSEND: printf("Reverb send"); break;
- case GEN_PAN: printf("pan"); break;
- case GEN_ATTENUATION: printf("att"); break;
- default: printf("dest %i",dest);
- }; /* switch dest */
- printf(", amount %f flags %i src2 %i flags2 %i\n",amount, flags1, src2, flags2);
-};
+#ifdef DEBUG
+void fluid_dump_modulator(fluid_mod_t *mod)
+{
+ int src1 = mod->src1;
+ int dest = mod->dest;
+ int src2 = mod->src2;
+ int flags1 = mod->flags1;
+ int flags2 = mod->flags2;
+ fluid_real_t amount = (fluid_real_t)mod->amount;
+
+ printf("Src: ");
+ if(flags1 & FLUID_MOD_CC)
+ {
+ printf("MIDI CC=%i", src1);
+ }
+ else
+ {
+ switch(src1)
+ {
+ case FLUID_MOD_NONE:
+ printf("None");
+ break;
+
+ case FLUID_MOD_VELOCITY:
+ printf("note-on velocity");
+ break;
+
+ case FLUID_MOD_KEY:
+ printf("Key nr");
+ break;
+
+ case FLUID_MOD_KEYPRESSURE:
+ printf("Poly pressure");
+ break;
+
+ case FLUID_MOD_CHANNELPRESSURE:
+ printf("Chan pressure");
+ break;
+
+ case FLUID_MOD_PITCHWHEEL:
+ printf("Pitch Wheel");
+ break;
+
+ case FLUID_MOD_PITCHWHEELSENS:
+ printf("Pitch Wheel sens");
+ break;
+
+ default:
+ printf("(unknown: %i)", src1);
+ }; /* switch src1 */
+ }; /* if not CC */
+
+ if(flags1 & FLUID_MOD_NEGATIVE)
+ {
+ printf("- ");
+ }
+ else
+ {
+ printf("+ ");
+ };
+
+ if(flags1 & FLUID_MOD_BIPOLAR)
+ {
+ printf("bip ");
+ }
+ else
+ {
+ printf("unip ");
+ };
+
+ printf("-> ");
+
+ switch(dest)
+ {
+ case GEN_FILTERQ:
+ printf("Q");
+ break;
+
+ case GEN_FILTERFC:
+ printf("fc");
+ break;
+
+ case GEN_CUSTOM_FILTERQ:
+ printf("custom-Q");
+ break;
+
+ case GEN_CUSTOM_FILTERFC:
+ printf("custom-fc");
+ break;
+
+ case GEN_VIBLFOTOPITCH:
+ printf("VibLFO-to-pitch");
+ break;
+
+ case GEN_MODENVTOPITCH:
+ printf("ModEnv-to-pitch");
+ break;
+
+ case GEN_MODLFOTOPITCH:
+ printf("ModLFO-to-pitch");
+ break;
+
+ case GEN_CHORUSSEND:
+ printf("Chorus send");
+ break;
+
+ case GEN_REVERBSEND:
+ printf("Reverb send");
+ break;
+
+ case GEN_PAN:
+ printf("pan");
+ break;
+
+ case GEN_CUSTOM_BALANCE:
+ printf("balance");
+ break;
+
+ case GEN_ATTENUATION:
+ printf("att");
+ break;
+
+ default:
+ printf("dest %i", dest);
+ }; /* switch dest */
+
+ printf(", amount %f flags %i src2 %i flags2 %i\n", amount, flags1, src2, flags2);
+};
+#endif
diff --git a/libs/fluidsynth/src/fluid_mod.h b/libs/fluidsynth/src/fluid_mod.h
index 81c9f76c70..e834baa513 100644
--- a/libs/fluidsynth/src/fluid_mod.h
+++ b/libs/fluidsynth/src/fluid_mod.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -24,17 +24,30 @@
#include "fluidsynth_priv.h"
#include "fluid_conv.h"
-void fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src);
-fluid_real_t fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice);
-void fluid_dump_modulator(fluid_mod_t * mod);
+/*
+ * Modulator structure. See SoundFont 2.04 PDF section 8.2.
+ */
+struct _fluid_mod_t
+{
+ unsigned char dest; /**< Destination generator to control */
+ unsigned char src1; /**< Source controller 1 */
+ unsigned char flags1; /**< Source controller 1 flags */
+ unsigned char src2; /**< Source controller 2 */
+ unsigned char flags2; /**< Source controller 2 flags */
+ double amount; /**< Multiplier amount */
+ /* The 'next' field allows to link modulators into a list. It is
+ * not used in fluid_voice.c, there each voice allocates memory for a
+ * fixed number of modulators. Since there may be a huge number of
+ * different zones, this is more efficient.
+ */
+ fluid_mod_t *next;
+};
-#define fluid_mod_has_source(mod,cc,ctrl) \
-( ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) != 0) && (cc != 0)) \
- || ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) == 0) && (cc == 0)))) \
-|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) != 0) && (cc != 0)) \
- || ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) == 0) && (cc == 0)))))
+fluid_real_t fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice);
-#define fluid_mod_has_dest(mod,gen) ((mod)->dest == gen)
+#ifdef DEBUG
+void fluid_dump_modulator(fluid_mod_t *mod);
+#endif
#endif /* _FLUID_MOD_H */
diff --git a/libs/fluidsynth/src/fluid_phase.h b/libs/fluidsynth/src/fluid_phase.h
index 15f2fa7550..08975cbb17 100644
--- a/libs/fluidsynth/src/fluid_phase.h
+++ b/libs/fluidsynth/src/fluid_phase.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -22,9 +22,7 @@
#ifndef _FLUID_PHASE_H
#define _FLUID_PHASE_H
-#if HAVE_CONFIG_H
#include "config.h"
-#endif
/*
* phase
@@ -47,7 +45,7 @@
* It is a 64 bit number. The higher 32 bits contain the 'index' (number of
* the current sample), the lower 32 bits the fractional part.
*/
-typedef unsigned long long fluid_phase_t;
+typedef uint64_t fluid_phase_t;
/* Purpose:
* Set a to b.
@@ -56,26 +54,26 @@ typedef unsigned long long fluid_phase_t;
*/
#define fluid_phase_set(a,b) a=b;
-#define fluid_phase_set_int(a, b) ((a) = ((unsigned long long)(b)) << 32)
+#define fluid_phase_set_int(a, b) ((a) = ((uint64_t)(b)) << 32)
/* Purpose:
* Sets the phase a to a phase increment given in b.
* For example, assume b is 0.9. After setting a to it, adding a to
* the playing pointer will advance it by 0.9 samples. */
#define fluid_phase_set_float(a, b) \
- (a) = (((unsigned long long)(b)) << 32) \
- | (uint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX)
+ (a) = (((uint64_t)(b)) << 32) \
+ | (uint32_t) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX)
/* create a fluid_phase_t from an index and a fraction value */
#define fluid_phase_from_index_fract(index, fract) \
- ((((unsigned long long)(index)) << 32) + (fract))
+ ((((uint64_t)(index)) << 32) + (fract))
/* Purpose:
* Return the index and the fractional part, respectively. */
#define fluid_phase_index(_x) \
((unsigned int)((_x) >> 32))
#define fluid_phase_fract(_x) \
- ((uint32)((_x) & 0xFFFFFFFF))
+ ((uint32_t)((_x) & 0xFFFFFFFF))
/* Get the phase index with fractional rounding */
#define fluid_phase_index_round(_x) \
@@ -108,7 +106,7 @@ typedef unsigned long long fluid_phase_t;
/* Purpose:
* Subtract b samples from a.
*/
-#define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32)
+#define fluid_phase_sub_int(a, b) ((a) -= (uint64_t)(b) << 32)
/* Purpose:
* Creates the expression a.index++. */
diff --git a/libs/fluidsynth/src/fluid_rev.c b/libs/fluidsynth/src/fluid_rev.c
index 166007da3f..51b4faa252 100644
--- a/libs/fluidsynth/src/fluid_rev.c
+++ b/libs/fluidsynth/src/fluid_rev.c
@@ -9,6 +9,7 @@
Translated to C by Peter Hanappe, Mai 2001
*/
+#include "fluid_sys.h"
#include "fluid_rev.h"
/***************************************************************
@@ -18,98 +19,75 @@
/* Denormalising:
*
- * According to music-dsp thread 'Denormalise', Pentium processors
- * have a hardware 'feature', that is of interest here, related to
- * numeric underflow. We have a recursive filter. The output decays
- * exponentially, if the input stops. So the numbers get smaller and
- * smaller... At some point, they reach 'denormal' level. This will
- * lead to drastic spikes in the CPU load. The effect was reproduced
- * with the reverb - sometimes the average load over 10 s doubles!!.
+ * We have a recursive filter. The output decays exponentially, if the input
+ * stops. So the numbers get smaller and smaller... At some point, they reach
+ * 'denormal' level. On some platforms this will lead to drastic spikes in the
+ * CPU load. This is especially noticable on some older Pentium (especially
+ * Pentium 3) processors, but even more modern Intel Core processors still show
+ * reduced performance with denormals. While there are compile-time switches to
+ * treat denormals as zero for a lot of processors, those are not available or
+ * effective on all platforms.
*
- * The 'undenormalise' macro fixes the problem: As soon as the number
- * is close enough to denormal level, the macro forces the number to
- * 0.0f. The original macro is:
- *
- * #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
- *
- * This will zero out a number when it reaches the denormal level.
- * Advantage: Maximum dynamic range Disadvantage: We'll have to check
- * every sample, expensive. The alternative macro comes from a later
- * mail from Jon Watte. It will zap a number before it reaches
- * denormal level. Jon suggests to run it once per block instead of
- * every sample.
+ * The fix used here: Use a small DC-offset in the filter calculations. Now
+ * the signals converge not against 0, but against the offset. The constant
+ * offset is invisible from the outside world (i.e. it does not appear at the
+ * output. There is a very small turn-on transient response, which should not
+ * cause problems.
*/
-
-# if defined(WITH_FLOATX)
-# define zap_almost_zero(sample) (((*(unsigned int*)&(sample))&0x7f800000) < 0x08000000)?0.0f:(sample)
-# else
-/* 1e-20 was chosen as an arbitrary (small) threshold. */
-#define zap_almost_zero(sample) fabs(sample)<1e-10 ? 0 : sample;
-#endif
-
-/* Denormalising part II:
- *
- * Another method fixes the problem cheaper: Use a small DC-offset in
- * the filter calculations. Now the signals converge not against 0,
- * but against the offset. The constant offset is invisible from the
- * outside world (i.e. it does not appear at the output. There is a
- * very small turn-on transient response, which should not cause
- * problems.
- */
-
-
-//#define DC_OFFSET 0
#define DC_OFFSET 1e-8
-//#define DC_OFFSET 0.001f
+
typedef struct _fluid_allpass fluid_allpass;
typedef struct _fluid_comb fluid_comb;
-struct _fluid_allpass {
- fluid_real_t feedback;
- fluid_real_t *buffer;
- int bufsize;
- int bufidx;
+struct _fluid_allpass
+{
+ fluid_real_t feedback;
+ fluid_real_t *buffer;
+ int bufsize;
+ int bufidx;
};
-void fluid_allpass_init(fluid_allpass* allpass);
-void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
-fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
+void fluid_allpass_init(fluid_allpass *allpass);
+void fluid_allpass_setfeedback(fluid_allpass *allpass, fluid_real_t val);
+fluid_real_t fluid_allpass_getfeedback(fluid_allpass *allpass);
static void
-fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
+fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
{
- allpass->bufidx = 0;
- allpass->buffer = FLUID_ARRAY(fluid_real_t,size);
- allpass->bufsize = size;
+ allpass->bufidx = 0;
+ allpass->buffer = FLUID_ARRAY(fluid_real_t, size);
+ allpass->bufsize = size;
}
static void
-fluid_allpass_release(fluid_allpass* allpass)
+fluid_allpass_release(fluid_allpass *allpass)
{
- FLUID_FREE(allpass->buffer);
+ FLUID_FREE(allpass->buffer);
}
void
-fluid_allpass_init(fluid_allpass* allpass)
+fluid_allpass_init(fluid_allpass *allpass)
{
- int i;
- int len = allpass->bufsize;
- fluid_real_t* buf = allpass->buffer;
- for (i = 0; i < len; i++) {
- buf[i] = DC_OFFSET; /* this is not 100 % correct. */
- }
+ int i;
+ int len = allpass->bufsize;
+ fluid_real_t *buf = allpass->buffer;
+
+ for(i = 0; i < len; i++)
+ {
+ buf[i] = DC_OFFSET; /* this is not 100 % correct. */
+ }
}
void
-fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val)
+fluid_allpass_setfeedback(fluid_allpass *allpass, fluid_real_t val)
{
- allpass->feedback = val;
+ allpass->feedback = val;
}
fluid_real_t
-fluid_allpass_getfeedback(fluid_allpass* allpass)
+fluid_allpass_getfeedback(fluid_allpass *allpass)
{
- return allpass->feedback;
+ return allpass->feedback;
}
#define fluid_allpass_process(_allpass, _input) \
@@ -125,87 +103,76 @@ fluid_allpass_getfeedback(fluid_allpass* allpass)
_input = output; \
}
-/* fluid_real_t fluid_allpass_process(fluid_allpass* allpass, fluid_real_t input) */
-/* { */
-/* fluid_real_t output; */
-/* fluid_real_t bufout; */
-/* bufout = allpass->buffer[allpass->bufidx]; */
-/* undenormalise(bufout); */
-/* output = -input + bufout; */
-/* allpass->buffer[allpass->bufidx] = input + (bufout * allpass->feedback); */
-/* if (++allpass->bufidx >= allpass->bufsize) { */
-/* allpass->bufidx = 0; */
-/* } */
-/* return output; */
-/* } */
-
-struct _fluid_comb {
- fluid_real_t feedback;
- fluid_real_t filterstore;
- fluid_real_t damp1;
- fluid_real_t damp2;
- fluid_real_t *buffer;
- int bufsize;
- int bufidx;
+struct _fluid_comb
+{
+ fluid_real_t feedback;
+ fluid_real_t filterstore;
+ fluid_real_t damp1;
+ fluid_real_t damp2;
+ fluid_real_t *buffer;
+ int bufsize;
+ int bufidx;
};
-void fluid_comb_setbuffer(fluid_comb* comb, int size);
-void fluid_comb_release(fluid_comb* comb);
-void fluid_comb_init(fluid_comb* comb);
-void fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val);
-fluid_real_t fluid_comb_getdamp(fluid_comb* comb);
-void fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val);
-fluid_real_t fluid_comb_getfeedback(fluid_comb* comb);
+void fluid_comb_setbuffer(fluid_comb *comb, int size);
+void fluid_comb_release(fluid_comb *comb);
+void fluid_comb_init(fluid_comb *comb);
+void fluid_comb_setdamp(fluid_comb *comb, fluid_real_t val);
+fluid_real_t fluid_comb_getdamp(fluid_comb *comb);
+void fluid_comb_setfeedback(fluid_comb *comb, fluid_real_t val);
+fluid_real_t fluid_comb_getfeedback(fluid_comb *comb);
void
-fluid_comb_setbuffer(fluid_comb* comb, int size)
+fluid_comb_setbuffer(fluid_comb *comb, int size)
{
- comb->filterstore = 0;
- comb->bufidx = 0;
- comb->buffer = FLUID_ARRAY(fluid_real_t,size);
- comb->bufsize = size;
+ comb->filterstore = 0;
+ comb->bufidx = 0;
+ comb->buffer = FLUID_ARRAY(fluid_real_t, size);
+ comb->bufsize = size;
}
void
-fluid_comb_release(fluid_comb* comb)
+fluid_comb_release(fluid_comb *comb)
{
- FLUID_FREE(comb->buffer);
+ FLUID_FREE(comb->buffer);
}
void
-fluid_comb_init(fluid_comb* comb)
+fluid_comb_init(fluid_comb *comb)
{
- int i;
- fluid_real_t* buf = comb->buffer;
- int len = comb->bufsize;
- for (i = 0; i < len; i++) {
- buf[i] = DC_OFFSET; /* This is not 100 % correct. */
- }
+ int i;
+ fluid_real_t *buf = comb->buffer;
+ int len = comb->bufsize;
+
+ for(i = 0; i < len; i++)
+ {
+ buf[i] = DC_OFFSET; /* This is not 100 % correct. */
+ }
}
void
-fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val)
+fluid_comb_setdamp(fluid_comb *comb, fluid_real_t val)
{
- comb->damp1 = val;
- comb->damp2 = 1 - val;
+ comb->damp1 = val;
+ comb->damp2 = 1 - val;
}
fluid_real_t
-fluid_comb_getdamp(fluid_comb* comb)
+fluid_comb_getdamp(fluid_comb *comb)
{
- return comb->damp1;
+ return comb->damp1;
}
void
-fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val)
+fluid_comb_setfeedback(fluid_comb *comb, fluid_real_t val)
{
- comb->feedback = val;
+ comb->feedback = val;
}
fluid_real_t
-fluid_comb_getfeedback(fluid_comb* comb)
+fluid_comb_getfeedback(fluid_comb *comb)
{
- return comb->feedback;
+ return comb->feedback;
}
#define fluid_comb_process(_comb, _input, _output) \
@@ -219,34 +186,21 @@ fluid_comb_getfeedback(fluid_comb* comb)
_output += _tmp; \
}
-/* fluid_real_t fluid_comb_process(fluid_comb* comb, fluid_real_t input) */
-/* { */
-/* fluid_real_t output; */
-
-/* output = comb->buffer[comb->bufidx]; */
-/* undenormalise(output); */
-/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
-/* undenormalise(comb->filterstore); */
-/* comb->buffer[comb->bufidx] = input + (comb->filterstore * comb->feedback); */
-/* if (++comb->bufidx >= comb->bufsize) { */
-/* comb->bufidx = 0; */
-/* } */
-
-/* return output; */
-/* } */
-
#define numcombs 8
#define numallpasses 4
#define fixedgain 0.015f
+/* scale_wet_width is a compensation weight factor to get an output
+ amplitude (wet) rather independent of the width setting.
+ 0: the output amplitude is fully dependant on the width setting.
+ >0: the output amplitude is less dependant on the width setting.
+ With a scale_wet_width of 0.2 the output amplitude is rather
+ independent of width setting (see fluid_revmodel_update()).
+ */
+#define scale_wet_width 0.2f
#define scalewet 3.0f
#define scaledamp 1.0f
#define scaleroom 0.28f
#define offsetroom 0.7f
-#define initialroom 0.5f
-#define initialdamp 0.2f
-#define initialwet 1
-#define initialdry 0
-#define initialwidth 1
#define stereospread 23
/*
@@ -280,221 +234,255 @@ fluid_comb_getfeedback(fluid_comb* comb)
#define allpasstuningL4 225
#define allpasstuningR4 (225 + stereospread)
-struct _fluid_revmodel_t {
- fluid_real_t roomsize;
- fluid_real_t damp;
- fluid_real_t wet, wet1, wet2;
- fluid_real_t width;
- fluid_real_t gain;
- /*
- The following are all declared inline
- to remove the need for dynamic allocation
- with its subsequent error-checking messiness
- */
- /* Comb filters */
- fluid_comb combL[numcombs];
- fluid_comb combR[numcombs];
- /* Allpass filters */
- fluid_allpass allpassL[numallpasses];
- fluid_allpass allpassR[numallpasses];
+struct _fluid_revmodel_t
+{
+ fluid_real_t roomsize;
+ fluid_real_t damp;
+ fluid_real_t level, wet1, wet2;
+ fluid_real_t width;
+ fluid_real_t gain;
+ /*
+ The following are all declared inline
+ to remove the need for dynamic allocation
+ with its subsequent error-checking messiness
+ */
+ /* Comb filters */
+ fluid_comb combL[numcombs];
+ fluid_comb combR[numcombs];
+ /* Allpass filters */
+ fluid_allpass allpassL[numallpasses];
+ fluid_allpass allpassR[numallpasses];
};
-static void fluid_revmodel_update(fluid_revmodel_t* rev);
-static void fluid_revmodel_init(fluid_revmodel_t* rev);
-void fluid_set_revmodel_buffers(fluid_revmodel_t* rev, fluid_real_t sample_rate);
+static void fluid_revmodel_update(fluid_revmodel_t *rev);
+static void fluid_revmodel_init(fluid_revmodel_t *rev);
+void fluid_set_revmodel_buffers(fluid_revmodel_t *rev, fluid_real_t sample_rate);
-fluid_revmodel_t*
+fluid_revmodel_t *
new_fluid_revmodel(fluid_real_t sample_rate)
{
- fluid_revmodel_t* rev;
- rev = FLUID_NEW(fluid_revmodel_t);
- if (rev == NULL) {
- return NULL;
- }
-
- fluid_set_revmodel_buffers(rev, sample_rate);
-
- /* Set default values */
- fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
- fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
- fluid_allpass_setfeedback(&rev->allpassL[1], 0.5f);
- fluid_allpass_setfeedback(&rev->allpassR[1], 0.5f);
- fluid_allpass_setfeedback(&rev->allpassL[2], 0.5f);
- fluid_allpass_setfeedback(&rev->allpassR[2], 0.5f);
- fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
- fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
-
- rev->gain = fixedgain;
- fluid_revmodel_set(rev,FLUID_REVMODEL_SET_ALL,initialroom,initialdamp,initialwidth,initialwet);
-
- return rev;
+ fluid_revmodel_t *rev;
+ rev = FLUID_NEW(fluid_revmodel_t);
+
+ if(rev == NULL)
+ {
+ return NULL;
+ }
+
+ fluid_set_revmodel_buffers(rev, sample_rate);
+
+ /* Set default values */
+ fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
+ fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
+ fluid_allpass_setfeedback(&rev->allpassL[1], 0.5f);
+ fluid_allpass_setfeedback(&rev->allpassR[1], 0.5f);
+ fluid_allpass_setfeedback(&rev->allpassL[2], 0.5f);
+ fluid_allpass_setfeedback(&rev->allpassR[2], 0.5f);
+ fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
+ fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
+
+ rev->gain = fixedgain;
+
+ return rev;
}
void
-delete_fluid_revmodel(fluid_revmodel_t* rev)
+delete_fluid_revmodel(fluid_revmodel_t *rev)
{
- int i;
- for (i = 0; i < numcombs;i++) {
- fluid_comb_release(&rev->combL[i]);
- fluid_comb_release(&rev->combR[i]);
- }
- for (i = 0; i < numallpasses; i++) {
- fluid_allpass_release(&rev->allpassL[i]);
- fluid_allpass_release(&rev->allpassR[i]);
- }
-
- FLUID_FREE(rev);
+ int i;
+ fluid_return_if_fail(rev != NULL);
+
+ for(i = 0; i < numcombs; i++)
+ {
+ fluid_comb_release(&rev->combL[i]);
+ fluid_comb_release(&rev->combR[i]);
+ }
+
+ for(i = 0; i < numallpasses; i++)
+ {
+ fluid_allpass_release(&rev->allpassL[i]);
+ fluid_allpass_release(&rev->allpassR[i]);
+ }
+
+ FLUID_FREE(rev);
}
void
-fluid_set_revmodel_buffers(fluid_revmodel_t* rev, fluid_real_t sample_rate) {
-
- float srfactor = sample_rate/44100.0f;
-
- fluid_comb_setbuffer(&rev->combL[0], combtuningL1*srfactor);
- fluid_comb_setbuffer(&rev->combR[0], combtuningR1*srfactor);
- fluid_comb_setbuffer(&rev->combL[1], combtuningL2*srfactor);
- fluid_comb_setbuffer(&rev->combR[1], combtuningR2*srfactor);
- fluid_comb_setbuffer(&rev->combL[2], combtuningL3*srfactor);
- fluid_comb_setbuffer(&rev->combR[2], combtuningR3*srfactor);
- fluid_comb_setbuffer(&rev->combL[3], combtuningL4*srfactor);
- fluid_comb_setbuffer(&rev->combR[3], combtuningR4*srfactor);
- fluid_comb_setbuffer(&rev->combL[4], combtuningL5*srfactor);
- fluid_comb_setbuffer(&rev->combR[4], combtuningR5*srfactor);
- fluid_comb_setbuffer(&rev->combL[5], combtuningL6*srfactor);
- fluid_comb_setbuffer(&rev->combR[5], combtuningR6*srfactor);
- fluid_comb_setbuffer(&rev->combL[6], combtuningL7*srfactor);
- fluid_comb_setbuffer(&rev->combR[6], combtuningR7*srfactor);
- fluid_comb_setbuffer(&rev->combL[7], combtuningL8*srfactor);
- fluid_comb_setbuffer(&rev->combR[7], combtuningR8*srfactor);
- fluid_allpass_setbuffer(&rev->allpassL[0], allpasstuningL1*srfactor);
- fluid_allpass_setbuffer(&rev->allpassR[0], allpasstuningR1*srfactor);
- fluid_allpass_setbuffer(&rev->allpassL[1], allpasstuningL2*srfactor);
- fluid_allpass_setbuffer(&rev->allpassR[1], allpasstuningR2*srfactor);
- fluid_allpass_setbuffer(&rev->allpassL[2], allpasstuningL3*srfactor);
- fluid_allpass_setbuffer(&rev->allpassR[2], allpasstuningR3*srfactor);
- fluid_allpass_setbuffer(&rev->allpassL[3], allpasstuningL4*srfactor);
- fluid_allpass_setbuffer(&rev->allpassR[3], allpasstuningR4*srfactor);
-
- /* Clear all buffers */
- fluid_revmodel_init(rev);
+fluid_set_revmodel_buffers(fluid_revmodel_t *rev, fluid_real_t sample_rate)
+{
+
+ float srfactor = sample_rate / 44100.0f;
+
+ fluid_comb_setbuffer(&rev->combL[0], combtuningL1 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[0], combtuningR1 * srfactor);
+ fluid_comb_setbuffer(&rev->combL[1], combtuningL2 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[1], combtuningR2 * srfactor);
+ fluid_comb_setbuffer(&rev->combL[2], combtuningL3 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[2], combtuningR3 * srfactor);
+ fluid_comb_setbuffer(&rev->combL[3], combtuningL4 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[3], combtuningR4 * srfactor);
+ fluid_comb_setbuffer(&rev->combL[4], combtuningL5 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[4], combtuningR5 * srfactor);
+ fluid_comb_setbuffer(&rev->combL[5], combtuningL6 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[5], combtuningR6 * srfactor);
+ fluid_comb_setbuffer(&rev->combL[6], combtuningL7 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[6], combtuningR7 * srfactor);
+ fluid_comb_setbuffer(&rev->combL[7], combtuningL8 * srfactor);
+ fluid_comb_setbuffer(&rev->combR[7], combtuningR8 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassL[0], allpasstuningL1 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassR[0], allpasstuningR1 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassL[1], allpasstuningL2 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassR[1], allpasstuningR2 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassL[2], allpasstuningL3 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassR[2], allpasstuningR3 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassL[3], allpasstuningL4 * srfactor);
+ fluid_allpass_setbuffer(&rev->allpassR[3], allpasstuningR4 * srfactor);
+
+ /* Clear all buffers */
+ fluid_revmodel_init(rev);
}
static void
-fluid_revmodel_init(fluid_revmodel_t* rev)
+fluid_revmodel_init(fluid_revmodel_t *rev)
{
- int i;
- for (i = 0; i < numcombs;i++) {
- fluid_comb_init(&rev->combL[i]);
- fluid_comb_init(&rev->combR[i]);
- }
- for (i = 0; i < numallpasses; i++) {
- fluid_allpass_init(&rev->allpassL[i]);
- fluid_allpass_init(&rev->allpassR[i]);
- }
+ int i;
+
+ for(i = 0; i < numcombs; i++)
+ {
+ fluid_comb_init(&rev->combL[i]);
+ fluid_comb_init(&rev->combR[i]);
+ }
+
+ for(i = 0; i < numallpasses; i++)
+ {
+ fluid_allpass_init(&rev->allpassL[i]);
+ fluid_allpass_init(&rev->allpassR[i]);
+ }
}
void
-fluid_revmodel_reset(fluid_revmodel_t* rev)
+fluid_revmodel_reset(fluid_revmodel_t *rev)
{
- fluid_revmodel_init(rev);
+ fluid_revmodel_init(rev);
}
void
-fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out)
+fluid_revmodel_processreplace(fluid_revmodel_t *rev, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out)
{
- int i, k = 0;
- fluid_real_t outL, outR, input;
-
- for (k = 0; k < FLUID_BUFSIZE; k++) {
-
- outL = outR = 0;
-
- /* The original Freeverb code expects a stereo signal and 'input'
- * is set to the sum of the left and right input sample. Since
- * this code works on a mono signal, 'input' is set to twice the
- * input sample. */
- input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
-
- /* Accumulate comb filters in parallel */
- for (i = 0; i < numcombs; i++) {
- fluid_comb_process(rev->combL[i], input, outL);
- fluid_comb_process(rev->combR[i], input, outR);
+ int i, k = 0;
+ fluid_real_t outL, outR, input;
+
+ for(k = 0; k < FLUID_BUFSIZE; k++)
+ {
+
+ outL = outR = 0;
+
+ /* The original Freeverb code expects a stereo signal and 'input'
+ * is set to the sum of the left and right input sample. Since
+ * this code works on a mono signal, 'input' is set to twice the
+ * input sample. */
+ input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
+
+ /* Accumulate comb filters in parallel */
+ for(i = 0; i < numcombs; i++)
+ {
+ fluid_comb_process(rev->combL[i], input, outL);
+ fluid_comb_process(rev->combR[i], input, outR);
+ }
+
+ /* Feed through allpasses in series */
+ for(i = 0; i < numallpasses; i++)
+ {
+ fluid_allpass_process(rev->allpassL[i], outL);
+ fluid_allpass_process(rev->allpassR[i], outR);
+ }
+
+ /* Remove the DC offset */
+ outL -= DC_OFFSET;
+ outR -= DC_OFFSET;
+
+ /* Calculate output REPLACING anything already there */
+ left_out[k] = outL * rev->wet1 + outR * rev->wet2;
+ right_out[k] = outR * rev->wet1 + outL * rev->wet2;
}
- /* Feed through allpasses in series */
- for (i = 0; i < numallpasses; i++) {
- fluid_allpass_process(rev->allpassL[i], outL);
- fluid_allpass_process(rev->allpassR[i], outR);
- }
-
- /* Remove the DC offset */
- outL -= DC_OFFSET;
- outR -= DC_OFFSET;
-
- /* Calculate output REPLACING anything already there */
- left_out[k] = outL * rev->wet1 + outR * rev->wet2;
- right_out[k] = outR * rev->wet1 + outL * rev->wet2;
- }
}
void
-fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out)
+fluid_revmodel_processmix(fluid_revmodel_t *rev, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out)
{
- int i, k = 0;
- fluid_real_t outL, outR, input;
-
- for (k = 0; k < FLUID_BUFSIZE; k++) {
-
- outL = outR = 0;
-
- /* The original Freeverb code expects a stereo signal and 'input'
- * is set to the sum of the left and right input sample. Since
- * this code works on a mono signal, 'input' is set to twice the
- * input sample. */
- input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
-
- /* Accumulate comb filters in parallel */
- for (i = 0; i < numcombs; i++) {
- fluid_comb_process(rev->combL[i], input, outL);
- fluid_comb_process(rev->combR[i], input, outR);
- }
- /* Feed through allpasses in series */
- for (i = 0; i < numallpasses; i++) {
- fluid_allpass_process(rev->allpassL[i], outL);
- fluid_allpass_process(rev->allpassR[i], outR);
+ int i, k = 0;
+ fluid_real_t outL, outR, input;
+
+ for(k = 0; k < FLUID_BUFSIZE; k++)
+ {
+
+ outL = outR = 0;
+
+ /* The original Freeverb code expects a stereo signal and 'input'
+ * is set to the sum of the left and right input sample. Since
+ * this code works on a mono signal, 'input' is set to twice the
+ * input sample. */
+ input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
+
+ /* Accumulate comb filters in parallel */
+ for(i = 0; i < numcombs; i++)
+ {
+ fluid_comb_process(rev->combL[i], input, outL);
+ fluid_comb_process(rev->combR[i], input, outR);
+ }
+
+ /* Feed through allpasses in series */
+ for(i = 0; i < numallpasses; i++)
+ {
+ fluid_allpass_process(rev->allpassL[i], outL);
+ fluid_allpass_process(rev->allpassR[i], outR);
+ }
+
+ /* Remove the DC offset */
+ outL -= DC_OFFSET;
+ outR -= DC_OFFSET;
+
+ /* Calculate output MIXING with anything already there */
+ left_out[k] += outL * rev->wet1 + outR * rev->wet2;
+ right_out[k] += outR * rev->wet1 + outL * rev->wet2;
}
-
- /* Remove the DC offset */
- outL -= DC_OFFSET;
- outR -= DC_OFFSET;
-
- /* Calculate output MIXING with anything already there */
- left_out[k] += outL * rev->wet1 + outR * rev->wet2;
- right_out[k] += outR * rev->wet1 + outL * rev->wet2;
- }
}
static void
-fluid_revmodel_update(fluid_revmodel_t* rev)
+fluid_revmodel_update(fluid_revmodel_t *rev)
{
- /* Recalculate internal values after parameter change */
- int i;
-
- rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
- rev->wet2 = rev->wet * ((1.0f - rev->width) / 2.0f);
-
- for (i = 0; i < numcombs; i++) {
- fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
- fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
- }
+ /* Recalculate internal values after parameter change */
+ int i;
+
+ /* The stereo amplitude equation (wet1 and wet2 below) have a
+ tendency to produce high amplitude with high width values ( 1 < width < 100).
+ This results in an unwanted noisy output clipped by the audio card.
+ To avoid this dependency, we divide by (1 + rev->width * scale_wet_width)
+ Actually, with a scale_wet_width of 0.2, (regardless of level setting),
+ the output amplitude (wet) seems rather independent of width setting */
+ fluid_real_t wet = (rev->level * scalewet) /
+ (1.0f + rev->width * scale_wet_width);
+
+ /* wet1 and wet2 are used by the stereo effect controled by the width setting
+ for producing a stereo ouptput from a monophonic reverb signal.
+ Please see the note above about a side effect tendency */
+ rev->wet1 = wet * (rev->width / 2.0f + 0.5f);
+ rev->wet2 = wet * ((1.0f - rev->width) / 2.0f);
+
+ for(i = 0; i < numcombs; i++)
+ {
+ fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
+ fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
+ }
- for (i = 0; i < numcombs; i++) {
- fluid_comb_setdamp(&rev->combL[i], rev->damp);
- fluid_comb_setdamp(&rev->combR[i], rev->damp);
- }
+ for(i = 0; i < numcombs; i++)
+ {
+ fluid_comb_setdamp(&rev->combL[i], rev->damp);
+ fluid_comb_setdamp(&rev->combR[i], rev->damp);
+ }
}
/**
@@ -508,37 +496,53 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
* @param level Reverb level
*/
void
-fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
- float damping, float width, float level)
+fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
+ fluid_real_t damping, fluid_real_t width, fluid_real_t level)
{
- if (set & FLUID_REVMODEL_SET_ROOMSIZE)
- rev->roomsize = (roomsize * scaleroom) + offsetroom;
+ if(set & FLUID_REVMODEL_SET_ROOMSIZE)
+ {
+ /* With upper limit above 1.07, the output amplitude will grow
+ exponentially. So, keeping this upper limit to 1.0 seems sufficient
+ as it produces yet a long reverb time */
+ fluid_clip(roomsize, 0.0f, 1.0f);
+ rev->roomsize = (roomsize * scaleroom) + offsetroom;
+ }
- if (set & FLUID_REVMODEL_SET_DAMPING)
- rev->damp = damping * scaledamp;
+ if(set & FLUID_REVMODEL_SET_DAMPING)
+ {
+ rev->damp = damping * scaledamp;
+ }
- if (set & FLUID_REVMODEL_SET_WIDTH)
- rev->width = width;
+ if(set & FLUID_REVMODEL_SET_WIDTH)
+ {
+ rev->width = width;
+ }
- if (set & FLUID_REVMODEL_SET_LEVEL)
- {
- fluid_clip(level, 0.0f, 1.0f);
- rev->wet = level * scalewet;
- }
+ if(set & FLUID_REVMODEL_SET_LEVEL)
+ {
+ fluid_clip(level, 0.0f, 1.0f);
+ rev->level = level;
+ }
- fluid_revmodel_update (rev);
+ fluid_revmodel_update(rev);
}
void
-fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, fluid_real_t sample_rate) {
- int i;
- for (i = 0; i < numcombs;i++) {
- fluid_comb_release(&rev->combL[i]);
- fluid_comb_release(&rev->combR[i]);
- }
- for (i = 0; i < numallpasses; i++) {
- fluid_allpass_release(&rev->allpassL[i]);
- fluid_allpass_release(&rev->allpassR[i]);
- }
- fluid_set_revmodel_buffers(rev, sample_rate);
+fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)
+{
+ int i;
+
+ for(i = 0; i < numcombs; i++)
+ {
+ fluid_comb_release(&rev->combL[i]);
+ fluid_comb_release(&rev->combR[i]);
+ }
+
+ for(i = 0; i < numallpasses; i++)
+ {
+ fluid_allpass_release(&rev->allpassL[i]);
+ fluid_allpass_release(&rev->allpassR[i]);
+ }
+
+ fluid_set_revmodel_buffers(rev, sample_rate);
}
diff --git a/libs/fluidsynth/src/fluid_rev.h b/libs/fluidsynth/src/fluid_rev.h
index f977352cf5..69c00ea71c 100644
--- a/libs/fluidsynth/src/fluid_rev.h
+++ b/libs/fluidsynth/src/fluid_rev.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -30,44 +30,48 @@ typedef struct _fluid_revmodel_t fluid_revmodel_t;
/** Flags for fluid_revmodel_set() */
typedef enum
{
- FLUID_REVMODEL_SET_ROOMSIZE = 1 << 0,
- FLUID_REVMODEL_SET_DAMPING = 1 << 1,
- FLUID_REVMODEL_SET_WIDTH = 1 << 2,
- FLUID_REVMODEL_SET_LEVEL = 1 << 3
+ FLUID_REVMODEL_SET_ROOMSIZE = 1 << 0,
+ FLUID_REVMODEL_SET_DAMPING = 1 << 1,
+ FLUID_REVMODEL_SET_WIDTH = 1 << 2,
+ FLUID_REVMODEL_SET_LEVEL = 1 << 3,
+
+ /** Value for fluid_revmodel_set() which sets all reverb parameters. */
+ FLUID_REVMODEL_SET_ALL = FLUID_REVMODEL_SET_LEVEL
+ | FLUID_REVMODEL_SET_WIDTH
+ | FLUID_REVMODEL_SET_DAMPING
+ | FLUID_REVMODEL_SET_ROOMSIZE,
} fluid_revmodel_set_t;
-/** Value for fluid_revmodel_set() which sets all reverb parameters. */
-#define FLUID_REVMODEL_SET_ALL 0x0F
-
/*
* reverb preset
*/
-typedef struct _fluid_revmodel_presets_t {
- char* name;
- fluid_real_t roomsize;
- fluid_real_t damp;
- fluid_real_t width;
- fluid_real_t level;
+typedef struct _fluid_revmodel_presets_t
+{
+ const char *name;
+ fluid_real_t roomsize;
+ fluid_real_t damp;
+ fluid_real_t width;
+ fluid_real_t level;
} fluid_revmodel_presets_t;
/*
* reverb
*/
-fluid_revmodel_t* new_fluid_revmodel(fluid_real_t sample_rate);
-void delete_fluid_revmodel(fluid_revmodel_t* rev);
+fluid_revmodel_t *new_fluid_revmodel(fluid_real_t sample_rate);
+void delete_fluid_revmodel(fluid_revmodel_t *rev);
-void fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out);
+void fluid_revmodel_processmix(fluid_revmodel_t *rev, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out);
-void fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
- fluid_real_t *left_out, fluid_real_t *right_out);
+void fluid_revmodel_processreplace(fluid_revmodel_t *rev, fluid_real_t *in,
+ fluid_real_t *left_out, fluid_real_t *right_out);
-void fluid_revmodel_reset(fluid_revmodel_t* rev);
+void fluid_revmodel_reset(fluid_revmodel_t *rev);
-void fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
- float damping, float width, float level);
+void fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
+ fluid_real_t damping, fluid_real_t width, fluid_real_t level);
-void fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, fluid_real_t sample_rate);
+void fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate);
#endif /* _FLUID_REV_H */
diff --git a/libs/fluidsynth/src/fluid_ringbuffer.c b/libs/fluidsynth/src/fluid_ringbuffer.c
index f6c06dd76d..71fd1e48a3 100644
--- a/libs/fluidsynth/src/fluid_ringbuffer.c
+++ b/libs/fluidsynth/src/fluid_ringbuffer.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -39,39 +39,39 @@
* only be one producer thread and one consumer thread.
*/
fluid_ringbuffer_t *
-new_fluid_ringbuffer (int count, int elementsize)
+new_fluid_ringbuffer(int count, int elementsize)
{
- fluid_ringbuffer_t *queue;
+ fluid_ringbuffer_t *queue;
- fluid_return_val_if_fail (count > 0, NULL);
+ fluid_return_val_if_fail(count > 0, NULL);
- queue = FLUID_NEW (fluid_ringbuffer_t);
+ queue = FLUID_NEW(fluid_ringbuffer_t);
- if (!queue)
- {
- FLUID_LOG (FLUID_ERR, "Out of memory");
- return NULL;
- }
+ if(!queue)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
- queue->array = FLUID_MALLOC (elementsize * count);
+ queue->array = FLUID_MALLOC(elementsize * count);
- if (!queue->array)
- {
- FLUID_FREE (queue);
- FLUID_LOG (FLUID_ERR, "Out of memory");
- return NULL;
- }
+ if(!queue->array)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ delete_fluid_ringbuffer(queue);
+ return NULL;
+ }
- /* Clear array, in case dynamic pointer reclaiming is being done */
- FLUID_MEMSET (queue->array, 0, elementsize * count);
+ /* Clear array, in case dynamic pointer reclaiming is being done */
+ FLUID_MEMSET(queue->array, 0, elementsize * count);
- queue->totalcount = count;
- queue->elementsize = elementsize;
- queue->count = 0;
- queue->in = 0;
- queue->out = 0;
+ queue->totalcount = count;
+ queue->elementsize = elementsize;
+ fluid_atomic_int_set(&queue->count, 0);
+ queue->in = 0;
+ queue->out = 0;
- return (queue);
+ return (queue);
}
/**
@@ -82,8 +82,9 @@ new_fluid_ringbuffer (int count, int elementsize)
* producer threads will no longer access it.
*/
void
-delete_fluid_ringbuffer (fluid_ringbuffer_t *queue)
+delete_fluid_ringbuffer(fluid_ringbuffer_t *queue)
{
- FLUID_FREE (queue->array);
- FLUID_FREE (queue);
+ fluid_return_if_fail(queue != NULL);
+ FLUID_FREE(queue->array);
+ FLUID_FREE(queue);
}
diff --git a/libs/fluidsynth/src/fluid_ringbuffer.h b/libs/fluidsynth/src/fluid_ringbuffer.h
index bd43f8a250..e78d52291b 100644
--- a/libs/fluidsynth/src/fluid_ringbuffer.h
+++ b/libs/fluidsynth/src/fluid_ringbuffer.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -23,30 +23,30 @@
#include "fluid_sys.h"
-/**
+/*
* Lockless event queue instance.
*/
struct _fluid_ringbuffer_t
{
- char *array; /**< Queue array of arbitrary size elements */
- int totalcount; /**< Total count of elements in array */
- int count; /**< Current count of elements */
- int in; /**< Index in queue to store next pushed element */
- int out; /**< Index in queue of next popped element */
- int elementsize; /**< Size of each element */
- void* userdata;
+ char *array; /**< Queue array of arbitrary size elements */
+ int totalcount; /**< Total count of elements in array */
+ fluid_atomic_int_t count; /**< Current count of elements */
+ int in; /**< Index in queue to store next pushed element */
+ int out; /**< Index in queue of next popped element */
+ int elementsize; /**< Size of each element */
+ void *userdata;
};
typedef struct _fluid_ringbuffer_t fluid_ringbuffer_t;
-fluid_ringbuffer_t *new_fluid_ringbuffer (int count, int elementsize);
-void delete_fluid_ringbuffer (fluid_ringbuffer_t *queue);
+fluid_ringbuffer_t *new_fluid_ringbuffer(int count, int elementsize);
+void delete_fluid_ringbuffer(fluid_ringbuffer_t *queue);
/**
* Get pointer to next input array element in queue.
* @param queue Lockless queue instance
- * @param count Normally zero, or more if you need to push several items at once
+ * @param offset Normally zero, or more if you need to push several items at once
* @return Pointer to array element in queue to store data to or NULL if queue is full
*
* This function along with fluid_ringbuffer_next_inptr() form a queue "push"
@@ -55,11 +55,11 @@ void delete_fluid_ringbuffer (fluid_ringbuffer_t *queue);
* if the queue has wrapped around. This can be used to reclaim pointers to
* allocated memory, etc.
*/
-static FLUID_INLINE void*
-fluid_ringbuffer_get_inptr (fluid_ringbuffer_t *queue, int offset)
+static FLUID_INLINE void *
+fluid_ringbuffer_get_inptr(fluid_ringbuffer_t *queue, int offset)
{
- return fluid_atomic_int_get (&queue->count) + offset >= queue->totalcount ? NULL
- : queue->array + queue->elementsize * ((queue->in + offset) % queue->totalcount);
+ return fluid_atomic_int_get(&queue->count) + offset >= queue->totalcount ? NULL
+ : queue->array + queue->elementsize * ((queue->in + offset) % queue->totalcount);
}
/**
@@ -71,13 +71,16 @@ fluid_ringbuffer_get_inptr (fluid_ringbuffer_t *queue, int offset)
* operation and is split into 2 functions to avoid element copy.
*/
static FLUID_INLINE void
-fluid_ringbuffer_next_inptr (fluid_ringbuffer_t *queue, int count)
+fluid_ringbuffer_next_inptr(fluid_ringbuffer_t *queue, int count)
{
- fluid_atomic_int_add (&queue->count, count);
+ fluid_atomic_int_add(&queue->count, count);
+
+ queue->in += count;
- queue->in += count;
- if (queue->in >= queue->totalcount)
- queue->in -= queue->totalcount;
+ if(queue->in >= queue->totalcount)
+ {
+ queue->in -= queue->totalcount;
+ }
}
/**
@@ -86,9 +89,9 @@ fluid_ringbuffer_next_inptr (fluid_ringbuffer_t *queue, int count)
* @return amount of items currently in queue
*/
static FLUID_INLINE int
-fluid_ringbuffer_get_count (fluid_ringbuffer_t *queue)
+fluid_ringbuffer_get_count(fluid_ringbuffer_t *queue)
{
- return fluid_atomic_int_get (&queue->count);
+ return fluid_atomic_int_get(&queue->count);
}
@@ -101,11 +104,11 @@ fluid_ringbuffer_get_count (fluid_ringbuffer_t *queue)
* This function along with fluid_ringbuffer_next_outptr() form a queue "pop"
* operation and is split into 2 functions to avoid an element copy.
*/
-static FLUID_INLINE void*
-fluid_ringbuffer_get_outptr (fluid_ringbuffer_t *queue)
+static FLUID_INLINE void *
+fluid_ringbuffer_get_outptr(fluid_ringbuffer_t *queue)
{
- return fluid_ringbuffer_get_count(queue) == 0 ? NULL
- : queue->array + queue->elementsize * queue->out;
+ return fluid_ringbuffer_get_count(queue) == 0 ? NULL
+ : queue->array + queue->elementsize * queue->out;
}
@@ -117,12 +120,14 @@ fluid_ringbuffer_get_outptr (fluid_ringbuffer_t *queue)
* operation and is split into 2 functions to avoid an element copy.
*/
static FLUID_INLINE void
-fluid_ringbuffer_next_outptr (fluid_ringbuffer_t *queue)
+fluid_ringbuffer_next_outptr(fluid_ringbuffer_t *queue)
{
- fluid_atomic_int_add (&queue->count, -1);
+ fluid_atomic_int_add(&queue->count, -1);
- if (++queue->out == queue->totalcount)
- queue->out = 0;
+ if(++queue->out == queue->totalcount)
+ {
+ queue->out = 0;
+ }
}
#endif /* _FLUID_ringbuffer_H */
diff --git a/libs/fluidsynth/src/fluid_rvoice.c b/libs/fluidsynth/src/fluid_rvoice.c
index ba8da98333..e768711637 100644
--- a/libs/fluidsynth/src/fluid_rvoice.c
+++ b/libs/fluidsynth/src/fluid_rvoice.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -22,80 +22,91 @@
#include "fluid_conv.h"
#include "fluid_sys.h"
+
+static void fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks);
+
/**
* @return -1 if voice has finished, 0 if it's currently quiet, 1 otherwise
*/
-static inline int
-fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
+static FLUID_INLINE int
+fluid_rvoice_calc_amp(fluid_rvoice_t *voice)
{
- fluid_real_t target_amp; /* target amplitude */
-
- if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVDELAY)
- return -1; /* The volume amplitude is in hold phase. No sound is produced. */
-
- if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
- {
- /* the envelope is in the attack section: ramp linearly to max value.
- * A positive modlfo_to_vol should increase volume (negative attenuation).
- */
- target_amp = fluid_atten2amp (voice->dsp.attenuation)
- * fluid_cb2amp (fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
- * fluid_adsr_env_get_val(&voice->envlfo.volenv);
- }
- else
- {
- fluid_real_t amplitude_that_reaches_noise_floor;
- fluid_real_t amp_max;
-
- target_amp = fluid_atten2amp (voice->dsp.attenuation)
- * fluid_cb2amp (960.0f * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
- + fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);
-
- /* We turn off a voice, if the volume has dropped low enough. */
-
- /* A voice can be turned off, when an estimate for the volume
- * (upper bound) falls below that volume, that will drop the
- * sample below the noise floor.
- */
+ fluid_real_t target_amp; /* target amplitude */
- /* If the loop amplitude is known, we can use it if the voice loop is within
- * the sample loop
- */
+ if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVDELAY)
+ {
+ return -1; /* The volume amplitude is in hold phase. No sound is produced. */
+ }
- /* Is the playing pointer already in the loop? */
- if (voice->dsp.has_looped)
- amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_loop;
+ if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
+ {
+ /* the envelope is in the attack section: ramp linearly to max value.
+ * A positive modlfo_to_vol should increase volume (negative attenuation).
+ */
+ target_amp = fluid_cb2amp(voice->dsp.attenuation)
+ * fluid_cb2amp(fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
+ * fluid_adsr_env_get_val(&voice->envlfo.volenv);
+ }
else
- amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
-
- /* voice->attenuation_min is a lower boundary for the attenuation
- * now and in the future (possibly 0 in the worst case). Now the
- * amplitude of sample and volenv cannot exceed amp_max (since
- * volenv_val can only drop):
- */
-
- amp_max = fluid_atten2amp (voice->dsp.min_attenuation_cB) *
- fluid_adsr_env_get_val(&voice->envlfo.volenv);
-
- /* And if amp_max is already smaller than the known amplitude,
- * which will attenuate the sample below the noise floor, then we
- * can safely turn off the voice. Duh. */
- if (amp_max < amplitude_that_reaches_noise_floor)
{
- return 0;
+ fluid_real_t amplitude_that_reaches_noise_floor;
+ fluid_real_t amp_max;
+
+ target_amp = fluid_cb2amp(voice->dsp.attenuation)
+ * fluid_cb2amp(FLUID_PEAK_ATTENUATION * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
+ + fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);
+
+ /* We turn off a voice, if the volume has dropped low enough. */
+
+ /* A voice can be turned off, when an estimate for the volume
+ * (upper bound) falls below that volume, that will drop the
+ * sample below the noise floor.
+ */
+
+ /* If the loop amplitude is known, we can use it if the voice loop is within
+ * the sample loop
+ */
+
+ /* Is the playing pointer already in the loop? */
+ if(voice->dsp.has_looped)
+ {
+ amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_loop;
+ }
+ else
+ {
+ amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
+ }
+
+ /* voice->attenuation_min is a lower boundary for the attenuation
+ * now and in the future (possibly 0 in the worst case). Now the
+ * amplitude of sample and volenv cannot exceed amp_max (since
+ * volenv_val can only drop):
+ */
+
+ amp_max = fluid_cb2amp(voice->dsp.min_attenuation_cB) *
+ fluid_adsr_env_get_val(&voice->envlfo.volenv);
+
+ /* And if amp_max is already smaller than the known amplitude,
+ * which will attenuate the sample below the noise floor, then we
+ * can safely turn off the voice. Duh. */
+ if(amp_max < amplitude_that_reaches_noise_floor)
+ {
+ return 0;
+ }
}
- }
- /* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
- voice->dsp.amp_incr = (target_amp - voice->dsp.amp) / FLUID_BUFSIZE;
+ /* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
+ voice->dsp.amp_incr = (target_amp - voice->dsp.amp) / FLUID_BUFSIZE;
- fluid_check_fpe ("voice_write amplitude calculation");
+ fluid_check_fpe("voice_write amplitude calculation");
- /* no volume and not changing? - No need to process */
- if ((voice->dsp.amp == 0.0f) && (voice->dsp.amp_incr == 0.0f))
- return -1;
+ /* no volume and not changing? - No need to process */
+ if((voice->dsp.amp == 0.0f) && (voice->dsp.amp_incr == 0.0f))
+ {
+ return -1;
+ }
- return 1;
+ return 1;
}
@@ -113,140 +124,164 @@ fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
* TODO: Investigate whether this can be moved from rvoice to voice.
*/
static void
-fluid_rvoice_check_sample_sanity(fluid_rvoice_t* voice)
+fluid_rvoice_check_sample_sanity(fluid_rvoice_t *voice)
{
- int min_index_nonloop=(int) voice->dsp.sample->start;
- int max_index_nonloop=(int) voice->dsp.sample->end;
+ int min_index_nonloop = (int) voice->dsp.sample->start;
+ int max_index_nonloop = (int) voice->dsp.sample->end;
/* make sure we have enough samples surrounding the loop */
- int min_index_loop=(int) voice->dsp.sample->start + FLUID_MIN_LOOP_PAD;
- int max_index_loop=(int) voice->dsp.sample->end - FLUID_MIN_LOOP_PAD + 1; /* 'end' is last valid sample, loopend can be + 1 */
+ int min_index_loop = (int) voice->dsp.sample->start + FLUID_MIN_LOOP_PAD;
+ int max_index_loop = (int) voice->dsp.sample->end - FLUID_MIN_LOOP_PAD + 1; /* 'end' is last valid sample, loopend can be + 1 */
fluid_check_fpe("voice_check_sample_sanity start");
- if (!voice->dsp.check_sample_sanity_flag){
- return;
- }
-
#if 0
- printf("Sample from %i to %i\n",voice->dsp.sample->start, voice->dsp.sample->end);
- printf("Sample loop from %i %i\n",voice->dsp.sample->loopstart, voice->dsp.sample->loopend);
+ printf("Sample from %i to %i\n", voice->dsp.sample->start, voice->dsp.sample->end);
+ printf("Sample loop from %i %i\n", voice->dsp.sample->loopstart, voice->dsp.sample->loopend);
printf("Playback from %i to %i\n", voice->dsp.start, voice->dsp.end);
- printf("Playback loop from %i to %i\n",voice->dsp.loopstart, voice->dsp.loopend);
+ printf("Playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend);
#endif
/* Keep the start point within the sample data */
- if (voice->dsp.start < min_index_nonloop){
- voice->dsp.start = min_index_nonloop;
- } else if (voice->dsp.start > max_index_nonloop){
- voice->dsp.start = max_index_nonloop;
+ if(voice->dsp.start < min_index_nonloop)
+ {
+ voice->dsp.start = min_index_nonloop;
+ }
+ else if(voice->dsp.start > max_index_nonloop)
+ {
+ voice->dsp.start = max_index_nonloop;
}
/* Keep the end point within the sample data */
- if (voice->dsp.end < min_index_nonloop){
- voice->dsp.end = min_index_nonloop;
- } else if (voice->dsp.end > max_index_nonloop){
- voice->dsp.end = max_index_nonloop;
+ if(voice->dsp.end < min_index_nonloop)
+ {
+ voice->dsp.end = min_index_nonloop;
+ }
+ else if(voice->dsp.end > max_index_nonloop)
+ {
+ voice->dsp.end = max_index_nonloop;
}
/* Keep start and end point in the right order */
- if (voice->dsp.start > voice->dsp.end){
- int temp = voice->dsp.start;
- voice->dsp.start = voice->dsp.end;
- voice->dsp.end = temp;
- /*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
+ if(voice->dsp.start > voice->dsp.end)
+ {
+ int temp = voice->dsp.start;
+ voice->dsp.start = voice->dsp.end;
+ voice->dsp.end = temp;
+ /*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
}
/* Zero length? */
- if (voice->dsp.start == voice->dsp.end){
- fluid_rvoice_voiceoff(voice);
- return;
- }
-
- if ((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
- || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) {
- /* Keep the loop start point within the sample data */
- if (voice->dsp.loopstart < min_index_loop){
- voice->dsp.loopstart = min_index_loop;
- } else if (voice->dsp.loopstart > max_index_loop){
- voice->dsp.loopstart = max_index_loop;
- }
-
- /* Keep the loop end point within the sample data */
- if (voice->dsp.loopend < min_index_loop){
- voice->dsp.loopend = min_index_loop;
- } else if (voice->dsp.loopend > max_index_loop){
- voice->dsp.loopend = max_index_loop;
- }
-
- /* Keep loop start and end point in the right order */
- if (voice->dsp.loopstart > voice->dsp.loopend){
- int temp = voice->dsp.loopstart;
- voice->dsp.loopstart = voice->dsp.loopend;
- voice->dsp.loopend = temp;
- /*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
- }
-
- /* Loop too short? Then don't loop. */
- if (voice->dsp.loopend < voice->dsp.loopstart + FLUID_MIN_LOOP_SIZE){
- voice->dsp.samplemode = FLUID_UNLOOPED;
- }
-
- /* The loop points may have changed. Obtain a new estimate for the loop volume. */
- /* Is the voice loop within the sample loop? */
- if ((int)voice->dsp.loopstart >= (int)voice->dsp.sample->loopstart
- && (int)voice->dsp.loopend <= (int)voice->dsp.sample->loopend){
- /* Is there a valid peak amplitude available for the loop, and can we use it? */
- if (voice->dsp.sample->amplitude_that_reaches_noise_floor_is_valid && voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE){
- voice->dsp.amplitude_that_reaches_noise_floor_loop=voice->dsp.sample->amplitude_that_reaches_noise_floor / voice->dsp.synth_gain;
- } else {
- /* Worst case */
- voice->dsp.amplitude_that_reaches_noise_floor_loop=voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
- };
- };
+ if(voice->dsp.start == voice->dsp.end)
+ {
+ fluid_rvoice_voiceoff(voice, NULL);
+ return;
+ }
+
+ if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
+ || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
+ {
+ /* Keep the loop start point within the sample data */
+ if(voice->dsp.loopstart < min_index_loop)
+ {
+ voice->dsp.loopstart = min_index_loop;
+ }
+ else if(voice->dsp.loopstart > max_index_loop)
+ {
+ voice->dsp.loopstart = max_index_loop;
+ }
+
+ /* Keep the loop end point within the sample data */
+ if(voice->dsp.loopend < min_index_loop)
+ {
+ voice->dsp.loopend = min_index_loop;
+ }
+ else if(voice->dsp.loopend > max_index_loop)
+ {
+ voice->dsp.loopend = max_index_loop;
+ }
+
+ /* Keep loop start and end point in the right order */
+ if(voice->dsp.loopstart > voice->dsp.loopend)
+ {
+ int temp = voice->dsp.loopstart;
+ voice->dsp.loopstart = voice->dsp.loopend;
+ voice->dsp.loopend = temp;
+ /*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
+ }
+
+ /* Loop too short? Then don't loop. */
+ if(voice->dsp.loopend < voice->dsp.loopstart + FLUID_MIN_LOOP_SIZE)
+ {
+ voice->dsp.samplemode = FLUID_UNLOOPED;
+ }
+
+ /* The loop points may have changed. Obtain a new estimate for the loop volume. */
+ /* Is the voice loop within the sample loop? */
+ if((int)voice->dsp.loopstart >= (int)voice->dsp.sample->loopstart
+ && (int)voice->dsp.loopend <= (int)voice->dsp.sample->loopend)
+ {
+ /* Is there a valid peak amplitude available for the loop, and can we use it? */
+ if(voice->dsp.sample->amplitude_that_reaches_noise_floor_is_valid && voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)
+ {
+ voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.sample->amplitude_that_reaches_noise_floor / voice->dsp.synth_gain;
+ }
+ else
+ {
+ /* Worst case */
+ voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
+ };
+ };
} /* if sample mode is looped */
/* Run startup specific code (only once, when the voice is started) */
- if (voice->dsp.check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP){
- if (max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE){
- if ((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
- || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)){
- voice->dsp.samplemode = FLUID_UNLOOPED;
- }
- }
-
- /* Set the initial phase of the voice (using the result from the
- start offset modulators). */
- fluid_phase_set_int(voice->dsp.phase, voice->dsp.start);
+ if(voice->dsp.check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP)
+ {
+ if(max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE)
+ {
+ if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
+ || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
+ {
+ voice->dsp.samplemode = FLUID_UNLOOPED;
+ }
+ }
+
+ /* Set the initial phase of the voice (using the result from the
+ start offset modulators). */
+ fluid_phase_set_int(voice->dsp.phase, voice->dsp.start);
} /* if startup */
/* Is this voice run in loop mode, or does it run straight to the
end of the waveform data? */
- if (((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) &&
- (fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE))
- || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) {
- /* Yes, it will loop as soon as it reaches the loop point. In
- * this case we must prevent, that the playback pointer (phase)
- * happens to end up beyond the 2nd loop point, because the
- * point has moved. The DSP algorithm is unable to cope with
- * that situation. So if the phase is beyond the 2nd loop
- * point, set it to the start of the loop. No way to avoid some
- * noise here. Note: If the sample pointer ends up -before the
- * first loop point- instead, then the DSP loop will just play
- * the sample, enter the loop and proceed as expected => no
- * actions required.
- */
- int index_in_sample = fluid_phase_index(voice->dsp.phase);
- if (index_in_sample >= voice->dsp.loopend){
- /* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
- fluid_phase_set_int(voice->dsp.phase, voice->dsp.loopstart);
- }
- }
-/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->dsp.start, voice->dsp.end, voice->dsp.loopstart, voice->dsp.loopend); */
+ if(((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) &&
+ (fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE))
+ || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
+ {
+ /* Yes, it will loop as soon as it reaches the loop point. In
+ * this case we must prevent, that the playback pointer (phase)
+ * happens to end up beyond the 2nd loop point, because the
+ * point has moved. The DSP algorithm is unable to cope with
+ * that situation. So if the phase is beyond the 2nd loop
+ * point, set it to the start of the loop. No way to avoid some
+ * noise here. Note: If the sample pointer ends up -before the
+ * first loop point- instead, then the DSP loop will just play
+ * the sample, enter the loop and proceed as expected => no
+ * actions required.
+ */
+ int index_in_sample = fluid_phase_index(voice->dsp.phase);
+
+ if(index_in_sample >= voice->dsp.loopend)
+ {
+ /* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
+ fluid_phase_set_int(voice->dsp.phase, voice->dsp.loopstart);
+ }
+ }
+
+ /* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->dsp.start, voice->dsp.end, voice->dsp.loopstart, voice->dsp.loopend); */
/* Sample sanity has been assured. Don't check again, until some
sample parameter is changed by modulation. */
- voice->dsp.check_sample_sanity_flag=0;
+ voice->dsp.check_sample_sanity_flag = 0;
#if 0
printf("Sane? playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend);
#endif
@@ -259,406 +294,603 @@ fluid_rvoice_check_sample_sanity(fluid_rvoice_t* voice)
*
* @param voice rvoice to synthesize
* @param dsp_buf Audio buffer to synthesize to (#FLUID_BUFSIZE in length)
- * @return Count of samples written to dsp_buf. (-1 means voice is currently
+ * @return Count of samples written to dsp_buf. (-1 means voice is currently
* quiet, 0 .. #FLUID_BUFSIZE-1 means voice finished.)
*
* Panning, reverb and chorus are processed separately. The dsp interpolation
- * routine is in (fluid_dsp_float.c).
+ * routine is in (fluid_rvoice_dsp.c).
*/
int
-fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
+fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
{
- int ticks = voice->envlfo.ticks;
- int count;
+ int ticks = voice->envlfo.ticks;
+ int count, is_looping;
- /******************* sample sanity check **********/
+ /******************* sample sanity check **********/
- if (!voice->dsp.sample)
- return 0;
- if (voice->dsp.check_sample_sanity_flag)
- fluid_rvoice_check_sample_sanity(voice);
+ if(!voice->dsp.sample)
+ {
+ return 0;
+ }
- /******************* noteoff check ****************/
+ if(voice->dsp.check_sample_sanity_flag)
+ {
+ fluid_rvoice_check_sample_sanity(voice);
+ }
- if (voice->envlfo.noteoff_ticks != 0 &&
- voice->envlfo.ticks >= voice->envlfo.noteoff_ticks) {
- fluid_rvoice_noteoff(voice, 0);
- }
+ /******************* noteoff check ****************/
- voice->envlfo.ticks += FLUID_BUFSIZE;
+ if(voice->envlfo.noteoff_ticks != 0 &&
+ voice->envlfo.ticks >= voice->envlfo.noteoff_ticks)
+ {
+ fluid_rvoice_noteoff_LOCAL(voice, 0);
+ }
- /******************* vol env **********************/
+ voice->envlfo.ticks += FLUID_BUFSIZE;
- fluid_adsr_env_calc(&voice->envlfo.volenv, 1);
- fluid_check_fpe ("voice_write vol env");
- if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED)
- return 0;
+ /******************* vol env **********************/
- /******************* mod env **********************/
+ fluid_adsr_env_calc(&voice->envlfo.volenv, 1);
+ fluid_check_fpe("voice_write vol env");
- fluid_adsr_env_calc(&voice->envlfo.modenv, 0);
- fluid_check_fpe ("voice_write mod env");
+ if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED)
+ {
+ return 0;
+ }
- /******************* lfo **********************/
+ /******************* mod env **********************/
- fluid_lfo_calc(&voice->envlfo.modlfo, ticks);
- fluid_check_fpe ("voice_write mod LFO");
- fluid_lfo_calc(&voice->envlfo.viblfo, ticks);
- fluid_check_fpe ("voice_write vib LFO");
+ fluid_adsr_env_calc(&voice->envlfo.modenv, 0);
+ fluid_check_fpe("voice_write mod env");
- /******************* amplitude **********************/
+ /******************* lfo **********************/
- count = fluid_rvoice_calc_amp(voice);
- if (count <= 0)
- return count;
+ fluid_lfo_calc(&voice->envlfo.modlfo, ticks);
+ fluid_check_fpe("voice_write mod LFO");
+ fluid_lfo_calc(&voice->envlfo.viblfo, ticks);
+ fluid_check_fpe("voice_write vib LFO");
- /******************* phase **********************/
+ /******************* amplitude **********************/
- /* Calculate the number of samples, that the DSP loop advances
- * through the original waveform with each step in the output
- * buffer. It is the ratio between the frequencies of original
- * waveform and output waveform.*/
- voice->dsp.phase_incr = fluid_ct2hz_real(voice->dsp.pitch +
- fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch
- + fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch
- + fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_pitch)
- / voice->dsp.root_pitch_hz;
+ count = fluid_rvoice_calc_amp(voice);
- fluid_check_fpe ("voice_write phase calculation");
+ if(count <= 0)
+ {
+ return count;
+ }
- /* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
- if (voice->dsp.phase_incr == 0) voice->dsp.phase_incr = 1;
+ /******************* phase **********************/
+
+ /* Calculate the number of samples, that the DSP loop advances
+ * through the original waveform with each step in the output
+ * buffer. It is the ratio between the frequencies of original
+ * waveform and output waveform.*/
+ voice->dsp.phase_incr = fluid_ct2hz_real(voice->dsp.pitch +
+ voice->dsp.pitchoffset +
+ fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch
+ + fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch
+ + fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_pitch)
+ / voice->dsp.root_pitch_hz;
+
+ /******************* portamento ****************/
+ /* pitchoffset is updated if enabled.
+ Pitchoffset will be added to dsp pitch at next phase calculation time */
+
+ /* In most cases portamento will be disabled. Thus first verify that portamento is
+ * enabled before updating pitchoffset and before disabling portamento when necessary,
+ * in order to keep the performance loss at minimum.
+ * If the algorithm would first update pitchoffset and then verify if portamento
+ * needs to be disabled, there would be a significant performance drop on a x87 FPU
+ */
+ if(voice->dsp.pitchinc > 0.0f)
+ {
+ /* portamento is enabled, so update pitchoffset */
+ voice->dsp.pitchoffset += voice->dsp.pitchinc;
+
+ /* when pitchoffset reaches 0.0f, portamento is disabled */
+ if(voice->dsp.pitchoffset > 0.0f)
+ {
+ voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f;
+ }
+ }
+ else if(voice->dsp.pitchinc < 0.0f)
+ {
+ /* portamento is enabled, so update pitchoffset */
+ voice->dsp.pitchoffset += voice->dsp.pitchinc;
+
+ /* when pitchoffset reaches 0.0f, portamento is disabled */
+ if(voice->dsp.pitchoffset < 0.0f)
+ {
+ voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f;
+ }
+ }
+
+ fluid_check_fpe("voice_write phase calculation");
- voice->dsp.is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
- || (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
- && fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
+ /* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
+ if(voice->dsp.phase_incr == 0)
+ {
+ voice->dsp.phase_incr = 1;
+ }
- /*********************** run the dsp chain ************************
- * The sample is mixed with the output buffer.
- * The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
- * Depending on the position in the loop and the loop size, this
- * may require several runs. */
- voice->dsp.dsp_buf = dsp_buf;
+ /* voice is currently looping? */
+ is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
+ || (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
+ && fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
- switch (voice->dsp.interp_method)
- {
+ /*********************** run the dsp chain ************************
+ * The sample is mixed with the output buffer.
+ * The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
+ * Depending on the position in the loop and the loop size, this
+ * may require several runs. */
+
+ switch(voice->dsp.interp_method)
+ {
case FLUID_INTERP_NONE:
- count = fluid_rvoice_dsp_interpolate_none (&voice->dsp);
- break;
+ count = fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping);
+ break;
+
case FLUID_INTERP_LINEAR:
- count = fluid_rvoice_dsp_interpolate_linear (&voice->dsp);
- break;
+ count = fluid_rvoice_dsp_interpolate_linear(&voice->dsp, dsp_buf, is_looping);
+ break;
+
case FLUID_INTERP_4THORDER:
default:
- count = fluid_rvoice_dsp_interpolate_4th_order (&voice->dsp);
- break;
+ count = fluid_rvoice_dsp_interpolate_4th_order(&voice->dsp, dsp_buf, is_looping);
+ break;
+
case FLUID_INTERP_7THORDER:
- count = fluid_rvoice_dsp_interpolate_7th_order (&voice->dsp);
- break;
- }
- fluid_check_fpe ("voice_write interpolation");
- if (count == 0)
- return count;
+ count = fluid_rvoice_dsp_interpolate_7th_order(&voice->dsp, dsp_buf, is_looping);
+ break;
+ }
- /*************** resonant filter ******************/
- fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
- fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
- fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);
+ fluid_check_fpe("voice_write interpolation");
- fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);
+ if(count == 0)
+ {
+ return count;
+ }
- return count;
-}
+ /*************** resonant filter ******************/
+ fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
+ fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
+ fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);
-static inline fluid_real_t*
-get_dest_buf(fluid_rvoice_buffers_t* buffers, int index,
- fluid_real_t** dest_bufs, int dest_bufcount)
-{
- int j = buffers->bufs[index].mapping;
- if (j >= dest_bufcount || j < 0) return NULL;
- return dest_bufs[j];
-}
+ fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);
-/**
- * Mix data down to buffers
- *
- * @param buffers Destination buffer(s)
- * @param dsp_buf Mono sample source
- * @param samplecount Number of samples to process (no FLUID_BUFSIZE restriction)
- * @param dest_bufs Array of buffers to mixdown to
- * @param dest_bufcount Length of dest_bufs
- */
-void
-fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
- fluid_real_t* dsp_buf, int samplecount,
- fluid_real_t** dest_bufs, int dest_bufcount)
-{
- int bufcount = buffers->count;
- int i, dsp_i;
- if (!samplecount || !bufcount || !dest_bufcount)
- return;
-
- for (i=0; i < bufcount; i++) {
- fluid_real_t* buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
- fluid_real_t* next_buf;
- fluid_real_t amp = buffers->bufs[i].amp;
- if (buf == NULL || amp == 0.0f)
- continue;
-
- /* Optimization for centered stereo samples - we can save one
- multiplication per sample */
- next_buf = (i+1 >= bufcount ? NULL : get_dest_buf(buffers, i+1, dest_bufs, dest_bufcount));
- if (next_buf && buffers->bufs[i+1].amp == amp) {
- for (dsp_i = 0; dsp_i < samplecount; dsp_i++) {
- fluid_real_t samp = amp * dsp_buf[dsp_i];
- buf[dsp_i] += samp;
- next_buf[dsp_i] += samp;
- }
- i++;
- }
- else {
- for (dsp_i = 0; dsp_i < samplecount; dsp_i++)
- buf[dsp_i] += amp * dsp_buf[dsp_i];
- }
- }
+ /* additional custom filter - only uses the fixed modulator, no lfos... */
+ fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0);
+ fluid_iir_filter_apply(&voice->resonant_custom_filter, dsp_buf, count);
+
+ return count;
}
/**
* Initialize buffers up to (and including) bufnum
*/
static int
-fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t* buffers, unsigned int bufnum)
+fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t *buffers, unsigned int bufnum)
{
- unsigned int i;
+ unsigned int i;
- if (bufnum < buffers->count) return FLUID_OK;
- if (bufnum >= FLUID_RVOICE_MAX_BUFS) return FLUID_FAILED;
+ if(bufnum < buffers->count)
+ {
+ return FLUID_OK;
+ }
+
+ if(bufnum >= FLUID_RVOICE_MAX_BUFS)
+ {
+ return FLUID_FAILED;
+ }
- for (i = buffers->count; i <= bufnum; i++) {
- buffers->bufs[bufnum].amp = 0.0f;
- buffers->bufs[bufnum].mapping = i;
- }
- buffers->count = bufnum+1;
- return FLUID_OK;
+ for(i = buffers->count; i <= bufnum; i++)
+ {
+ buffers->bufs[i].amp = 0.0f;
+ }
+
+ buffers->count = bufnum + 1;
+ return FLUID_OK;
}
-void
-fluid_rvoice_buffers_set_amp(fluid_rvoice_buffers_t* buffers,
- unsigned int bufnum, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp)
{
- if (fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
- return;
- buffers->bufs[bufnum].amp = value;
+ fluid_rvoice_buffers_t *buffers = obj;
+ unsigned int bufnum = param[0].i;
+ fluid_real_t value = param[1].real;
+
+ if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
+ {
+ return;
+ }
+
+ buffers->bufs[bufnum].amp = value;
}
-void
-fluid_rvoice_buffers_set_mapping(fluid_rvoice_buffers_t* buffers,
- unsigned int bufnum, int mapping)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping)
{
- if (fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
- return;
- buffers->bufs[bufnum].mapping = mapping;
+ fluid_rvoice_buffers_t *buffers = obj;
+ unsigned int bufnum = param[0].i;
+ int mapping = param[1].i;
+
+ if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
+ {
+ return;
+ }
+
+ buffers->bufs[bufnum].mapping = mapping;
}
-void
-fluid_rvoice_reset(fluid_rvoice_t* voice)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_reset)
{
- voice->dsp.has_looped = 0;
- voice->envlfo.ticks = 0;
- voice->envlfo.noteoff_ticks = 0;
- voice->dsp.amp = 0.0f; /* The last value of the volume envelope, used to
+ fluid_rvoice_t *voice = obj;
+
+ voice->dsp.has_looped = 0;
+ voice->envlfo.ticks = 0;
+ voice->envlfo.noteoff_ticks = 0;
+ voice->dsp.amp = 0.0f; /* The last value of the volume envelope, used to
calculate the volume increment during
processing */
- /* mod env initialization*/
- fluid_adsr_env_reset(&voice->envlfo.modenv);
+ /* legato initialization */
+ voice->dsp.pitchoffset = 0.0; /* portamento initialization */
+ voice->dsp.pitchinc = 0.0;
+
+ /* mod env initialization*/
+ fluid_adsr_env_reset(&voice->envlfo.modenv);
- /* vol env initialization */
- fluid_adsr_env_reset(&voice->envlfo.volenv);
+ /* vol env initialization */
+ fluid_adsr_env_reset(&voice->envlfo.volenv);
- /* Fixme: Retrieve from any other existing
- voice on this channel to keep LFOs in
- unison? */
- fluid_lfo_reset(&voice->envlfo.viblfo);
- fluid_lfo_reset(&voice->envlfo.modlfo);
+ /* Fixme: Retrieve from any other existing
+ voice on this channel to keep LFOs in
+ unison? */
+ fluid_lfo_reset(&voice->envlfo.viblfo);
+ fluid_lfo_reset(&voice->envlfo.modlfo);
- /* Clear sample history in filter */
- fluid_iir_filter_reset(&voice->resonant_filter);
+ /* Clear sample history in filter */
+ fluid_iir_filter_reset(&voice->resonant_filter);
+ fluid_iir_filter_reset(&voice->resonant_custom_filter);
- /* Force setting of the phase at the first DSP loop run
- * This cannot be done earlier, because it depends on modulators.
- [DH] Is that comment really true? */
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
+ /* Force setting of the phase at the first DSP loop run
+ * This cannot be done earlier, because it depends on modulators.
+ [DH] Is that comment really true? */
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
}
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_noteoff)
+{
+ fluid_rvoice_t *rvoice = obj;
+ unsigned int min_ticks = param[0].i;
-void
-fluid_rvoice_noteoff(fluid_rvoice_t* voice, unsigned int min_ticks)
+ fluid_rvoice_noteoff_LOCAL(rvoice, min_ticks);
+}
+
+static void
+fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks)
{
- if (min_ticks > voice->envlfo.ticks) {
- /* Delay noteoff */
- voice->envlfo.noteoff_ticks = min_ticks;
- return;
- }
- voice->envlfo.noteoff_ticks = 0;
+ if(min_ticks > voice->envlfo.ticks)
+ {
+ /* Delay noteoff */
+ voice->envlfo.noteoff_ticks = min_ticks;
+ return;
+ }
- if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK) {
- /* A voice is turned off during the attack section of the volume
- * envelope. The attack section ramps up linearly with
- * amplitude. The other sections use logarithmic scaling. Calculate new
- * volenv_val to achieve equievalent amplitude during the release phase
- * for seamless volume transition.
- */
- if (fluid_adsr_env_get_val(&voice->envlfo.volenv) > 0){
- fluid_real_t lfo = fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol;
- fluid_real_t amp = fluid_adsr_env_get_val(&voice->envlfo.volenv) * pow (10.0, lfo / -200);
- fluid_real_t env_value = - ((-200 * log (amp) / log (10.0) - lfo) / 960.0 - 1);
- fluid_clip (env_value, 0.0, 1.0);
- fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
+ voice->envlfo.noteoff_ticks = 0;
+
+ if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
+ {
+ /* A voice is turned off during the attack section of the volume
+ * envelope. The attack section ramps up linearly with
+ * amplitude. The other sections use logarithmic scaling. Calculate new
+ * volenv_val to achieve equievalent amplitude during the release phase
+ * for seamless volume transition.
+ */
+ if(fluid_adsr_env_get_val(&voice->envlfo.volenv) > 0)
+ {
+ fluid_real_t lfo = fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol;
+ fluid_real_t amp = fluid_adsr_env_get_val(&voice->envlfo.volenv) * fluid_cb2amp(lfo);
+ fluid_real_t env_value = - ((-200 * log(amp) / log(10.0) - lfo) / FLUID_PEAK_ATTENUATION - 1);
+ fluid_clip(env_value, 0.0, 1.0);
+ fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
+ }
+ }
+
+ fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVRELEASE);
+ fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVRELEASE);
+}
+
+/**
+ * skips to Attack section
+ *
+ * Updates vol and attack data
+ * Correction on volume val to achieve equivalent amplitude at noteOn legato
+ *
+ * @param voice the synthesis voice to be updated
+*/
+static FLUID_INLINE void fluid_rvoice_local_retrigger_attack(fluid_rvoice_t *voice)
+{
+ /* skips to Attack section */
+ /* Once in Attack section, current count must be reset, to be sure
+ that the section will be not be prematurely finished. */
+ fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVATTACK);
+ {
+ /* Correction on volume val to achieve equivalent amplitude at noteOn legato */
+ fluid_env_data_t *env_data;
+ fluid_real_t peak = fluid_cb2amp(voice->dsp.attenuation);
+ fluid_real_t prev_peak = fluid_cb2amp(voice->dsp.prev_attenuation);
+ voice->envlfo.volenv.val = (voice->envlfo.volenv.val * prev_peak) / peak;
+ /* Correction on slope direction for Attack section */
+ env_data = &voice->envlfo.volenv.data[FLUID_VOICE_ENVATTACK];
+
+ if(voice->envlfo.volenv.val <= 1.0f)
+ {
+ /* slope attack for legato note needs to be positive from val up to 1 */
+ env_data->increment = 1.0f / env_data->count;
+ env_data->min = -1.0f;
+ env_data->max = 1.0f;
+ }
+ else
+ {
+ /* slope attack for legato note needs to be negative: from val down to 1 */
+ env_data->increment = -voice->envlfo.volenv.val / env_data->count;
+ env_data->min = 1.0f;
+ env_data->max = voice->envlfo.volenv.val;
+ }
+ }
+}
+
+/**
+ * Used by legato Mode : multi_retrigger
+ * see fluid_synth_noteon_mono_legato_multi_retrigger()
+ * @param voice the synthesis voice to be updated
+*/
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack)
+{
+ fluid_rvoice_t *voice = obj;
+ int section = fluid_adsr_env_get_section(&voice->envlfo.volenv);
+
+ /*-------------------------------------------------------------------------
+ Section skip for volume envelope
+ --------------------------------------------------------------------------*/
+ if(section >= FLUID_VOICE_ENVHOLD)
+ {
+ /* DECAY, SUSTAIN,RELEASE section use logarithmic scaling. Calculates new
+ volenv_val to achieve equivalent amplitude during the attack phase
+ for seamless volume transition. */
+ fluid_real_t amp_cb, env_value;
+ amp_cb = FLUID_PEAK_ATTENUATION *
+ (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv));
+ env_value = fluid_cb2amp(amp_cb); /* a bit of optimization */
+ fluid_clip(env_value, 0.0, 1.0);
+ fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
+ /* next, skips to Attack section */
}
- }
- fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVRELEASE);
- fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVRELEASE);
+
+ /* skips to Attack section from any section */
+ /* Update vol and attack data */
+ fluid_rvoice_local_retrigger_attack(voice);
+ /*-------------------------------------------------------------------------
+ Section skip for modulation envelope
+ --------------------------------------------------------------------------*/
+ /* Skips from any section to ATTACK section */
+ fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVATTACK);
+ /* Actually (v 1.1.6) all sections are linear, so there is no need to
+ correct val value. However soundfont 2.01/2.4 spec. says that Attack should
+ be convex (see issue #153 from Christian Collins). In the case Attack
+ section would be changed to a non linear shape it will be necessary to do
+ a correction for seamless val transition. Here is the place to do this */
}
+/**
+ * sets the portamento dsp parameters: dsp.pitchoffset, dsp.pitchinc
+ * @param voice rvoice to set portamento.
+ * @param countinc increment count number.
+ * @param pitchoffset pitch offset to apply to voice dsp.pitch.
+ *
+ * Notes:
+ * 1) To get continuous portamento between consecutive noteOn (n1,n2,n3...),
+ * pitchoffset is accumulated in current dsp pitchoffset.
+ * 2) And to get constant portamento duration, dsp pitch increment is updated.
+*/
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_portamento)
+{
+ fluid_rvoice_t *voice = obj;
+ unsigned int countinc = param[0].i;
+ fluid_real_t pitchoffset = param[1].real;
+
+ if(countinc)
+ {
+ voice->dsp.pitchoffset += pitchoffset;
+ voice->dsp.pitchinc = - voice->dsp.pitchoffset / countinc;
+ }
-void
-fluid_rvoice_set_output_rate(fluid_rvoice_t* voice, fluid_real_t value)
+ /* Then during the voice processing (in fluid_rvoice_write()),
+ dsp.pitchoffset will be incremented by dsp pitchinc. */
+}
+
+
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_output_rate)
{
- voice->dsp.output_rate = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->dsp.output_rate = value;
}
-void
-fluid_rvoice_set_interp_method(fluid_rvoice_t* voice, int value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_interp_method)
{
- voice->dsp.interp_method = value;
+ fluid_rvoice_t *voice = obj;
+ int value = param[0].i;
+
+ voice->dsp.interp_method = value;
}
-void
-fluid_rvoice_set_root_pitch_hz(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_root_pitch_hz)
{
- voice->dsp.root_pitch_hz = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->dsp.root_pitch_hz = value;
}
-void
-fluid_rvoice_set_pitch(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_pitch)
{
- voice->dsp.pitch = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->dsp.pitch = value;
}
-void
-fluid_rvoice_set_attenuation(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_attenuation)
{
- voice->dsp.attenuation = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->dsp.prev_attenuation = voice->dsp.attenuation;
+ voice->dsp.attenuation = value;
}
-void
-fluid_rvoice_set_min_attenuation_cB(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_min_attenuation_cB)
{
- voice->dsp.min_attenuation_cB = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->dsp.min_attenuation_cB = value;
}
-void
-fluid_rvoice_set_viblfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_viblfo_to_pitch)
{
- voice->envlfo.viblfo_to_pitch = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->envlfo.viblfo_to_pitch = value;
}
-void fluid_rvoice_set_modlfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_pitch)
{
- voice->envlfo.modlfo_to_pitch = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->envlfo.modlfo_to_pitch = value;
}
-void
-fluid_rvoice_set_modlfo_to_vol(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_vol)
{
- voice->envlfo.modlfo_to_vol = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->envlfo.modlfo_to_vol = value;
}
-void
-fluid_rvoice_set_modlfo_to_fc(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_fc)
{
- voice->envlfo.modlfo_to_fc = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->envlfo.modlfo_to_fc = value;
}
-void
-fluid_rvoice_set_modenv_to_fc(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_fc)
{
- voice->envlfo.modenv_to_fc = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->envlfo.modenv_to_fc = value;
}
-void
-fluid_rvoice_set_modenv_to_pitch(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_pitch)
{
- voice->envlfo.modenv_to_pitch = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
+
+ voice->envlfo.modenv_to_pitch = value;
}
-void
-fluid_rvoice_set_synth_gain(fluid_rvoice_t* voice, fluid_real_t value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_synth_gain)
{
- voice->dsp.synth_gain = value;
+ fluid_rvoice_t *voice = obj;
+ fluid_real_t value = param[0].real;
- /* For a looped sample, this value will be overwritten as soon as the
- * loop parameters are initialized (they may depend on modulators).
- * This value can be kept, it is a worst-case estimate.
- */
- voice->dsp.amplitude_that_reaches_noise_floor_nonloop = FLUID_NOISE_FLOOR / value;
- voice->dsp.amplitude_that_reaches_noise_floor_loop = FLUID_NOISE_FLOOR / value;
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
+ voice->dsp.synth_gain = value;
+
+ /* For a looped sample, this value will be overwritten as soon as the
+ * loop parameters are initialized (they may depend on modulators).
+ * This value can be kept, it is a worst-case estimate.
+ */
+ voice->dsp.amplitude_that_reaches_noise_floor_nonloop = FLUID_NOISE_FLOOR / value;
+ voice->dsp.amplitude_that_reaches_noise_floor_loop = FLUID_NOISE_FLOOR / value;
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
-void
-fluid_rvoice_set_start(fluid_rvoice_t* voice, int value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_start)
{
- voice->dsp.start = value;
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
+ fluid_rvoice_t *voice = obj;
+ int value = param[0].i;
+
+ voice->dsp.start = value;
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
-void
-fluid_rvoice_set_end(fluid_rvoice_t* voice, int value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_end)
{
- voice->dsp.end = value;
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
+ fluid_rvoice_t *voice = obj;
+ int value = param[0].i;
+
+ voice->dsp.end = value;
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
-void
-fluid_rvoice_set_loopstart(fluid_rvoice_t* voice, int value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopstart)
{
- voice->dsp.loopstart = value;
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
+ fluid_rvoice_t *voice = obj;
+ int value = param[0].i;
+
+ voice->dsp.loopstart = value;
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
-void fluid_rvoice_set_loopend(fluid_rvoice_t* voice, int value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopend)
{
- voice->dsp.loopend = value;
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
+ fluid_rvoice_t *voice = obj;
+ int value = param[0].i;
+
+ voice->dsp.loopend = value;
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
-void fluid_rvoice_set_samplemode(fluid_rvoice_t* voice, enum fluid_loop value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_samplemode)
{
- voice->dsp.samplemode = value;
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
+ fluid_rvoice_t *voice = obj;
+ enum fluid_loop value = param[0].i;
+
+ voice->dsp.samplemode = value;
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
-void
-fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample)
{
- voice->dsp.sample = value;
- if (value) {
- voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
- }
+ fluid_rvoice_t *voice = obj;
+ fluid_sample_t *value = param[0].ptr;
+
+ voice->dsp.sample = value;
+
+ if(value)
+ {
+ voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
+ }
}
-void
-fluid_rvoice_voiceoff(fluid_rvoice_t* voice)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_voiceoff)
{
- fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVFINISHED);
- fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVFINISHED);
+ fluid_rvoice_t *voice = obj;
+
+ fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVFINISHED);
+ fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVFINISHED);
}
diff --git a/libs/fluidsynth/src/fluid_rvoice.h b/libs/fluidsynth/src/fluid_rvoice.h
index 4566cb1de3..bae3ac9390 100644
--- a/libs/fluidsynth/src/fluid_rvoice.h
+++ b/libs/fluidsynth/src/fluid_rvoice.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -36,165 +36,190 @@ typedef struct _fluid_rvoice_t fluid_rvoice_t;
/* Smallest amplitude that can be perceived (full scale is +/- 0.5)
* 16 bits => 96+4=100 dB dynamic range => 0.00001
- * 0.00001 * 2 is approximately 0.00003 :)
+ * 24 bits => 144-4 = 140 dB dynamic range => 1.e-7
+ * 1.e-7 * 2 == 2.e-7 :)
*/
-#define FLUID_NOISE_FLOOR 0.00003
+#define FLUID_NOISE_FLOOR 2.e-7
-
-enum fluid_loop {
- FLUID_UNLOOPED = 0,
- FLUID_LOOP_DURING_RELEASE = 1,
- FLUID_NOTUSED = 2,
- FLUID_LOOP_UNTIL_RELEASE = 3
+enum fluid_loop
+{
+ FLUID_UNLOOPED = 0,
+ FLUID_LOOP_DURING_RELEASE = 1,
+ FLUID_NOTUSED = 2,
+ FLUID_LOOP_UNTIL_RELEASE = 3
};
-/**
+/*
* rvoice ticks-based parameters
* These parameters must be updated even if the voice is currently quiet.
*/
struct _fluid_rvoice_envlfo_t
{
- /* Note-off minimum length */
- unsigned int ticks;
- unsigned int noteoff_ticks;
-
- /* vol env */
- fluid_adsr_env_t volenv;
-
- /* mod env */
- fluid_adsr_env_t modenv;
- fluid_real_t modenv_to_fc;
- fluid_real_t modenv_to_pitch;
-
- /* mod lfo */
- fluid_lfo_t modlfo;
- fluid_real_t modlfo_to_fc;
- fluid_real_t modlfo_to_pitch;
- fluid_real_t modlfo_to_vol;
-
- /* vib lfo */
- fluid_lfo_t viblfo;
- fluid_real_t viblfo_to_pitch;
+ /* Note-off minimum length */
+ unsigned int ticks;
+ unsigned int noteoff_ticks;
+
+ /* vol env */
+ fluid_adsr_env_t volenv;
+
+ /* mod env */
+ fluid_adsr_env_t modenv;
+ fluid_real_t modenv_to_fc;
+ fluid_real_t modenv_to_pitch;
+
+ /* mod lfo */
+ fluid_lfo_t modlfo;
+ fluid_real_t modlfo_to_fc;
+ fluid_real_t modlfo_to_pitch;
+ fluid_real_t modlfo_to_vol;
+
+ /* vib lfo */
+ fluid_lfo_t viblfo;
+ fluid_real_t viblfo_to_pitch;
};
-/**
+/*
* rvoice parameters needed for dsp interpolation
*/
struct _fluid_rvoice_dsp_t
{
- /* interpolation method, as in fluid_interp in fluidsynth.h */
- int interp_method;
- fluid_sample_t* sample;
- int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
- have to be checked. */
-
- /* sample and loop start and end points (offset in sample memory). */
- int start;
- int end;
- int loopstart;
- int loopend; /* Note: first point following the loop (superimposed on loopstart) */
- enum fluid_loop samplemode;
-
- /* Stuff needed for phase calculations */
-
- fluid_real_t pitch; /* the pitch in midicents */
- fluid_real_t root_pitch_hz;
- fluid_real_t output_rate;
-
- /* Stuff needed for amplitude calculations */
-
- int has_looped; /* Flag that is set as soon as the first loop is completed. */
- fluid_real_t attenuation; /* the attenuation in centibels */
- fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
- * during the lifetime of the voice */
- fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
- fluid_real_t amplitude_that_reaches_noise_floor_loop;
- fluid_real_t synth_gain; /* master gain */
+ /* interpolation method, as in fluid_interp in fluidsynth.h */
+ enum fluid_interp interp_method;
+ enum fluid_loop samplemode;
+
+ /* Flag that is set as soon as the first loop is completed. */
+ char has_looped;
+ /* Flag that initiates, that sample-related parameters have to be checked. */
+ char check_sample_sanity_flag;
- /* Dynamic input to the interpolator below */
+ fluid_sample_t *sample;
- fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
+ /* sample and loop start and end points (offset in sample memory). */
+ int start;
+ int end;
+ int loopstart;
+ int loopend; /* Note: first point following the loop (superimposed on loopstart) */
- fluid_real_t amp; /* current linear amplitude */
- fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */
+ /* Stuff needed for portamento calculations */
+ fluid_real_t pitchoffset; /* the portamento range in midicents */
+ fluid_real_t pitchinc; /* the portamento increment in midicents */
- fluid_phase_t phase; /* the phase (current sample offset) of the sample wave */
- fluid_real_t phase_incr; /* the phase increment for the next FLUID_BUFSIZE samples */
- int is_looping;
+ /* Stuff needed for phase calculations */
+ fluid_real_t pitch; /* the pitch in midicents */
+ fluid_real_t root_pitch_hz;
+ fluid_real_t output_rate;
+
+ /* Stuff needed for amplitude calculations */
+
+ fluid_real_t attenuation; /* the attenuation in centibels */
+ fluid_real_t prev_attenuation; /* the previous attenuation in centibels
+ used by fluid_rvoice_multi_retrigger_attack() */
+ fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
+ * during the lifetime of the voice */
+ fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
+ fluid_real_t amplitude_that_reaches_noise_floor_loop;
+ fluid_real_t synth_gain; /* master gain */
+
+ /* Dynamic input to the interpolator below */
+
+ fluid_real_t amp; /* current linear amplitude */
+ fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */
+
+ fluid_phase_t phase; /* the phase (current sample offset) of the sample wave */
+ fluid_real_t phase_incr; /* the phase increment for the next FLUID_BUFSIZE samples */
};
/* Currently left, right, reverb, chorus. To be changed if we
ever add surround positioning, or stereo reverb/chorus */
#define FLUID_RVOICE_MAX_BUFS (4)
-/**
+/*
* rvoice mixer-related parameters
*/
struct _fluid_rvoice_buffers_t
{
- unsigned int count; /* Number of records in "bufs" */
- struct {
- fluid_real_t amp;
- int mapping; /* Mapping to mixdown buffer index */
- } bufs[FLUID_RVOICE_MAX_BUFS];
+ unsigned int count; /* Number of records in "bufs" */
+ struct
+ {
+ fluid_real_t amp;
+ int mapping; /* Mapping to mixdown buffer index */
+ } bufs[FLUID_RVOICE_MAX_BUFS];
};
-/**
- * Parameters needed to synthesize a voice
+/*
+ * Hard real-time parameters needed to synthesize a voice
*/
struct _fluid_rvoice_t
{
- fluid_rvoice_envlfo_t envlfo;
- fluid_rvoice_dsp_t dsp;
- fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */
- fluid_rvoice_buffers_t buffers;
+ fluid_rvoice_envlfo_t envlfo;
+ fluid_rvoice_dsp_t dsp;
+ fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */
+ fluid_iir_filter_t resonant_custom_filter; /* optional custom/general-purpose IIR resonant filter */
+ fluid_rvoice_buffers_t buffers;
};
-int fluid_rvoice_write(fluid_rvoice_t* voice, fluid_real_t *dsp_buf);
-
-void fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
- fluid_real_t* dsp_buf, int samplecount,
- fluid_real_t** dest_bufs, int dest_bufcount);
-void fluid_rvoice_buffers_set_amp(fluid_rvoice_buffers_t* buffers,
- unsigned int bufnum, fluid_real_t value);
-void fluid_rvoice_buffers_set_mapping(fluid_rvoice_buffers_t* buffers,
- unsigned int bufnum, int mapping);
-
-/* Dynamic update functions */
-
-void fluid_rvoice_noteoff(fluid_rvoice_t* voice, unsigned int min_ticks);
-void fluid_rvoice_voiceoff(fluid_rvoice_t* voice);
-void fluid_rvoice_reset(fluid_rvoice_t* voice);
-void fluid_rvoice_set_output_rate(fluid_rvoice_t* voice, fluid_real_t output_rate);
-void fluid_rvoice_set_interp_method(fluid_rvoice_t* voice, int interp_method);
-void fluid_rvoice_set_root_pitch_hz(fluid_rvoice_t* voice, fluid_real_t root_pitch_hz);
-void fluid_rvoice_set_pitch(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_synth_gain(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_attenuation(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_min_attenuation_cB(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_viblfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_modlfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_modlfo_to_vol(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_modlfo_to_fc(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_modenv_to_fc(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_modenv_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
-void fluid_rvoice_set_start(fluid_rvoice_t* voice, int value);
-void fluid_rvoice_set_end(fluid_rvoice_t* voice, int value);
-void fluid_rvoice_set_loopstart(fluid_rvoice_t* voice, int value);
-void fluid_rvoice_set_loopend(fluid_rvoice_t* voice, int value);
-void fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value);
-void fluid_rvoice_set_samplemode(fluid_rvoice_t* voice, enum fluid_loop value);
+int fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf);
+
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping);
+
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_noteoff);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_voiceoff);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_reset);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_portamento);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_output_rate);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_interp_method);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_root_pitch_hz);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_pitch);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_attenuation);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_min_attenuation_cB);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_viblfo_to_pitch);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_pitch);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_vol);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_fc);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_fc);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_pitch);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_synth_gain);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_start);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_end);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopstart);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopend);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_samplemode);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample);
/* defined in fluid_rvoice_dsp.c */
+void fluid_rvoice_dsp_config(void);
+int fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
+int fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
+int fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
+int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
-void fluid_rvoice_dsp_config (void);
-int fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice);
-int fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice);
-int fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice);
-int fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice);
+
+/*
+ * Combines the most significant 16 bit part of a sample with a potentially present
+ * least sig. 8 bit part in order to create a 24 bit sample.
+ */
+static FLUID_INLINE int32_t
+fluid_rvoice_get_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx)
+{
+ /* cast sample to unsigned type, so we can safely shift and bitwise or
+ * without relying on undefined behaviour (should never happen anyway ofc...) */
+ uint32_t msb = (uint32_t)dsp_msb[idx];
+ uint8_t lsb = 0U;
+
+ /* most soundfonts have 16 bit samples, assume that it's unlikely we
+ * experience 24 bit samples here */
+ if(FLUID_UNLIKELY(dsp_lsb != NULL))
+ {
+ lsb = (uint8_t)dsp_lsb[idx];
+ }
+
+ return (int32_t)((msb << 8) | lsb);
+}
#endif
diff --git a/libs/fluidsynth/src/fluid_rvoice_dsp.c b/libs/fluidsynth/src/fluid_rvoice_dsp.c
index df7da5022d..cc162829f6 100644
--- a/libs/fluidsynth/src/fluid_rvoice_dsp.c
+++ b/libs/fluidsynth/src/fluid_rvoice_dsp.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -28,7 +28,7 @@
* Interpolates audio data (obtains values between the samples of the original
* waveform data).
*
- * Variables loaded from the voice structure (assigned in fluid_voice_write()):
+ * Variables loaded from the voice structure (assigned in fluid_rvoice_write()):
* - dsp_data: Pointer to the original waveform data
* - dsp_phase: The position in the original waveform data.
* This has an integer and a fractional part (between samples).
@@ -61,122 +61,138 @@ static fluid_real_t sinc_table7[FLUID_INTERP_MAX][7];
/* Initializes interpolation tables */
-void fluid_rvoice_dsp_config (void)
+void fluid_rvoice_dsp_config(void)
{
- int i, i2;
- double x, v;
- double i_shifted;
-
- /* Initialize the coefficients for the interpolation. The math comes
- * from a mail, posted by Olli Niemitalo to the music-dsp mailing
- * list (I found it in the music-dsp archives
- * http://www.smartelectronix.com/musicdsp/). */
-
- for (i = 0; i < FLUID_INTERP_MAX; i++)
- {
- x = (double) i / (double) FLUID_INTERP_MAX;
-
- interp_coeff[i][0] = (fluid_real_t)(x * (-0.5 + x * (1 - 0.5 * x)));
- interp_coeff[i][1] = (fluid_real_t)(1.0 + x * x * (1.5 * x - 2.5));
- interp_coeff[i][2] = (fluid_real_t)(x * (0.5 + x * (2.0 - 1.5 * x)));
- interp_coeff[i][3] = (fluid_real_t)(0.5 * x * x * (x - 1.0));
-
- interp_coeff_linear[i][0] = (fluid_real_t)(1.0 - x);
- interp_coeff_linear[i][1] = (fluid_real_t)x;
- }
-
- /* i: Offset in terms of whole samples */
- for (i = 0; i < SINC_INTERP_ORDER; i++)
- { /* i2: Offset in terms of fractional samples ('subsamples') */
- for (i2 = 0; i2 < FLUID_INTERP_MAX; i2++)
+ int i, i2;
+ double x, v;
+ double i_shifted;
+
+ /* Initialize the coefficients for the interpolation. The math comes
+ * from a mail, posted by Olli Niemitalo to the music-dsp mailing
+ * list (I found it in the music-dsp archives
+ * http://www.smartelectronix.com/musicdsp/). */
+
+ for(i = 0; i < FLUID_INTERP_MAX; i++)
+ {
+ x = (double) i / (double) FLUID_INTERP_MAX;
+
+ interp_coeff[i][0] = (fluid_real_t)(x * (-0.5 + x * (1 - 0.5 * x)));
+ interp_coeff[i][1] = (fluid_real_t)(1.0 + x * x * (1.5 * x - 2.5));
+ interp_coeff[i][2] = (fluid_real_t)(x * (0.5 + x * (2.0 - 1.5 * x)));
+ interp_coeff[i][3] = (fluid_real_t)(0.5 * x * x * (x - 1.0));
+
+ interp_coeff_linear[i][0] = (fluid_real_t)(1.0 - x);
+ interp_coeff_linear[i][1] = (fluid_real_t)x;
+ }
+
+ /* i: Offset in terms of whole samples */
+ for(i = 0; i < SINC_INTERP_ORDER; i++)
{
- /* center on middle of table */
- i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
- + (double)i2 / (double)FLUID_INTERP_MAX;
-
- /* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
- if (fabs (i_shifted) > 0.000001)
- {
- v = (fluid_real_t)sin (i_shifted * M_PI) / (M_PI * i_shifted);
- /* Hamming window */
- v *= (fluid_real_t)0.5 * (1.0 + cos (2.0 * M_PI * i_shifted / (fluid_real_t)SINC_INTERP_ORDER));
- }
- else v = 1.0;
-
- sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
+ /* i2: Offset in terms of fractional samples ('subsamples') */
+ for(i2 = 0; i2 < FLUID_INTERP_MAX; i2++)
+ {
+ /* center on middle of table */
+ i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
+ + (double)i2 / (double)FLUID_INTERP_MAX;
+
+ /* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
+ if(fabs(i_shifted) > 0.000001)
+ {
+ double arg = M_PI * i_shifted;
+ v = (fluid_real_t)sin(arg) / (arg);
+ /* Hanning window */
+ v *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * arg / (fluid_real_t)SINC_INTERP_ORDER));
+ }
+ else
+ {
+ v = 1.0;
+ }
+
+ sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
+ }
}
- }
#if 0
- for (i = 0; i < FLUID_INTERP_MAX; i++)
- {
- printf ("%d %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",
- i, sinc_table7[0][i], sinc_table7[1][i], sinc_table7[2][i],
- sinc_table7[3][i], sinc_table7[4][i], sinc_table7[5][i], sinc_table7[6][i]);
- }
+
+ for(i = 0; i < FLUID_INTERP_MAX; i++)
+ {
+ printf("%d %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",
+ i, sinc_table7[0][i], sinc_table7[1][i], sinc_table7[2][i],
+ sinc_table7[3][i], sinc_table7[4][i], sinc_table7[5][i], sinc_table7[6][i]);
+ }
+
#endif
- fluid_check_fpe("interpolation table calculation");
+ fluid_check_fpe("interpolation table calculation");
+}
+
+static FLUID_INLINE fluid_real_t
+fluid_rvoice_get_float_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx)
+{
+ int32_t sample = fluid_rvoice_get_sample(dsp_msb, dsp_lsb, idx);
+ return (fluid_real_t)sample;
}
/* No interpolation. Just take the sample, which is closest to
* the playback pointer. Questionable quality, but very
* efficient. */
int
-fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice)
+fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
{
- fluid_phase_t dsp_phase = voice->phase;
- fluid_phase_t dsp_phase_incr;
- short int *dsp_data = voice->sample->data;
- fluid_real_t *dsp_buf = voice->dsp_buf;
- fluid_real_t dsp_amp = voice->amp;
- fluid_real_t dsp_amp_incr = voice->amp_incr;
- unsigned int dsp_i = 0;
- unsigned int dsp_phase_index;
- unsigned int end_index;
- int looping;
-
- /* Convert playback "speed" floating point value to phase index/fract */
- fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
-
- /* voice is currently looping? */
- looping = voice->is_looping;
-
- end_index = looping ? voice->loopend - 1 : voice->end;
-
- while (1)
- {
- dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
-
- /* interpolate sequence of sample points */
- for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
+ fluid_phase_t dsp_phase = voice->phase;
+ fluid_phase_t dsp_phase_incr;
+ short int *dsp_data = voice->sample->data;
+ char *dsp_data24 = voice->sample->data24;
+ fluid_real_t dsp_amp = voice->amp;
+ fluid_real_t dsp_amp_incr = voice->amp_incr;
+ unsigned int dsp_i = 0;
+ unsigned int dsp_phase_index;
+ unsigned int end_index;
+
+ /* Convert playback "speed" floating point value to phase index/fract */
+ fluid_phase_set_float(dsp_phase_incr, voice->phase_incr);
+
+ end_index = looping ? voice->loopend - 1 : voice->end;
+
+ while(1)
{
- dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
- dsp_amp += dsp_amp_incr;
+ dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */
+
+ /* interpolate sequence of sample points */
+ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
+ {
+ dsp_buf[dsp_i] = dsp_amp * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index);
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */
+ dsp_amp += dsp_amp_incr;
+ }
+
+ /* break out if not looping (buffer may not be full) */
+ if(!looping)
+ {
+ break;
+ }
+
+ /* go back to loop start */
+ if(dsp_phase_index > end_index)
+ {
+ fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart);
+ voice->has_looped = 1;
+ }
+
+ /* break out if filled buffer */
+ if(dsp_i >= FLUID_BUFSIZE)
+ {
+ break;
+ }
}
- /* break out if not looping (buffer may not be full) */
- if (!looping) break;
-
- /* go back to loop start */
- if (dsp_phase_index > end_index)
- {
- fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
- voice->has_looped = 1;
- }
+ voice->phase = dsp_phase;
+ voice->amp = dsp_amp;
- /* break out if filled buffer */
- if (dsp_i >= FLUID_BUFSIZE) break;
- }
-
- voice->phase = dsp_phase;
- voice->amp = dsp_amp;
-
- return (dsp_i);
+ return (dsp_i);
}
/* Straight line interpolation.
@@ -184,88 +200,99 @@ fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice)
* smaller if end of sample occurs).
*/
int
-fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
+fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
{
- fluid_phase_t dsp_phase = voice->phase;
- fluid_phase_t dsp_phase_incr;
- short int *dsp_data = voice->sample->data;
- fluid_real_t *dsp_buf = voice->dsp_buf;
- fluid_real_t dsp_amp = voice->amp;
- fluid_real_t dsp_amp_incr = voice->amp_incr;
- unsigned int dsp_i = 0;
- unsigned int dsp_phase_index;
- unsigned int end_index;
- short int point;
- fluid_real_t *coeffs;
- int looping;
-
- /* Convert playback "speed" floating point value to phase index/fract */
- fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
-
- /* voice is currently looping? */
- looping = voice->is_looping;
-
- /* last index before 2nd interpolation point must be specially handled */
- end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
-
- /* 2nd interpolation point to use at end of loop or sample */
- if (looping) point = dsp_data[voice->loopstart]; /* loop start */
- else point = dsp_data[voice->end]; /* duplicate end for samples no longer looping */
-
- while (1)
- {
- dsp_phase_index = fluid_phase_index (dsp_phase);
-
- /* interpolate the sequence of sample points */
- for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
+ fluid_phase_t dsp_phase = voice->phase;
+ fluid_phase_t dsp_phase_incr;
+ short int *dsp_data = voice->sample->data;
+ char *dsp_data24 = voice->sample->data24;
+ fluid_real_t dsp_amp = voice->amp;
+ fluid_real_t dsp_amp_incr = voice->amp_incr;
+ unsigned int dsp_i = 0;
+ unsigned int dsp_phase_index;
+ unsigned int end_index;
+ fluid_real_t point;
+ const fluid_real_t *FLUID_RESTRICT coeffs;
+
+ /* Convert playback "speed" floating point value to phase index/fract */
+ fluid_phase_set_float(dsp_phase_incr, voice->phase_incr);
+
+ /* last index before 2nd interpolation point must be specially handled */
+ end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
+
+ /* 2nd interpolation point to use at end of loop or sample */
+ if(looping)
{
- coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
- + coeffs[1] * dsp_data[dsp_phase_index+1]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); /* loop start */
}
-
- /* break out if buffer filled */
- if (dsp_i >= FLUID_BUFSIZE) break;
-
- end_index++; /* we're now interpolating the last point */
-
- /* interpolate within last point */
- for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ else
{
- coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
- + coeffs[1] * point);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr; /* increment amplitude */
+ point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); /* duplicate end for samples no longer looping */
}
- if (!looping) break; /* break out if not looping (end of sample) */
-
- /* go back to loop start (if past */
- if (dsp_phase_index > end_index)
+ while(1)
{
- fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
- voice->has_looped = 1;
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+
+ /* interpolate the sequence of sample points */
+ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
+ {
+ coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)];
+ dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1));
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ /* break out if buffer filled */
+ if(dsp_i >= FLUID_BUFSIZE)
+ {
+ break;
+ }
+
+ end_index++; /* we're now interpolating the last point */
+
+ /* interpolate within last point */
+ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)];
+ dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[1] * point);
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr; /* increment amplitude */
+ }
+
+ if(!looping)
+ {
+ break; /* break out if not looping (end of sample) */
+ }
+
+ /* go back to loop start (if past */
+ if(dsp_phase_index > end_index)
+ {
+ fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart);
+ voice->has_looped = 1;
+ }
+
+ /* break out if filled buffer */
+ if(dsp_i >= FLUID_BUFSIZE)
+ {
+ break;
+ }
+
+ end_index--; /* set end back to second to last sample point */
}
- /* break out if filled buffer */
- if (dsp_i >= FLUID_BUFSIZE) break;
-
- end_index--; /* set end back to second to last sample point */
- }
+ voice->phase = dsp_phase;
+ voice->amp = dsp_amp;
- voice->phase = dsp_phase;
- voice->amp = dsp_amp;
-
- return (dsp_i);
+ return (dsp_i);
}
/* 4th order (cubic) interpolation.
@@ -273,149 +300,158 @@ fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
* smaller if end of sample occurs).
*/
int
-fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
+fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
{
- fluid_phase_t dsp_phase = voice->phase;
- fluid_phase_t dsp_phase_incr;
- short int *dsp_data = voice->sample->data;
- fluid_real_t *dsp_buf = voice->dsp_buf;
- fluid_real_t dsp_amp = voice->amp;
- fluid_real_t dsp_amp_incr = voice->amp_incr;
- unsigned int dsp_i = 0;
- unsigned int dsp_phase_index;
- unsigned int start_index, end_index;
- short int start_point, end_point1, end_point2;
- fluid_real_t *coeffs;
- int looping;
-
- /* Convert playback "speed" floating point value to phase index/fract */
- fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
-
- /* voice is currently looping? */
- looping = voice->is_looping;
-
- /* last index before 4th interpolation point must be specially handled */
- end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
-
- if (voice->has_looped) /* set start_index and start point if looped or not */
- {
- start_index = voice->loopstart;
- start_point = dsp_data[voice->loopend - 1]; /* last point in loop (wrap around) */
- }
- else
- {
- start_index = voice->start;
- start_point = dsp_data[voice->start]; /* just duplicate the point */
- }
-
- /* get points off the end (loop start if looping, duplicate point if end) */
- if (looping)
- {
- end_point1 = dsp_data[voice->loopstart];
- end_point2 = dsp_data[voice->loopstart + 1];
- }
- else
- {
- end_point1 = dsp_data[voice->end];
- end_point2 = end_point1;
- }
-
- while (1)
- {
- dsp_phase_index = fluid_phase_index (dsp_phase);
-
- /* interpolate first sample point (start or loop start) if needed */
- for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ fluid_phase_t dsp_phase = voice->phase;
+ fluid_phase_t dsp_phase_incr;
+ short int *dsp_data = voice->sample->data;
+ char *dsp_data24 = voice->sample->data24;
+ fluid_real_t dsp_amp = voice->amp;
+ fluid_real_t dsp_amp_incr = voice->amp_incr;
+ unsigned int dsp_i = 0;
+ unsigned int dsp_phase_index;
+ unsigned int start_index, end_index;
+ fluid_real_t start_point, end_point1, end_point2;
+ const fluid_real_t *FLUID_RESTRICT coeffs;
+
+ /* Convert playback "speed" floating point value to phase index/fract */
+ fluid_phase_set_float(dsp_phase_incr, voice->phase_incr);
+
+ /* last index before 4th interpolation point must be specially handled */
+ end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
+
+ if(voice->has_looped) /* set start_index and start point if looped or not */
{
- coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * start_point
- + coeffs[1] * dsp_data[dsp_phase_index]
- + coeffs[2] * dsp_data[dsp_phase_index+1]
- + coeffs[3] * dsp_data[dsp_phase_index+2]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ start_index = voice->loopstart;
+ start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); /* last point in loop (wrap around) */
}
-
- /* interpolate the sequence of sample points */
- for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
+ else
{
- coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
- + coeffs[1] * dsp_data[dsp_phase_index]
- + coeffs[2] * dsp_data[dsp_phase_index+1]
- + coeffs[3] * dsp_data[dsp_phase_index+2]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ start_index = voice->start;
+ start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the point */
}
- /* break out if buffer filled */
- if (dsp_i >= FLUID_BUFSIZE) break;
-
- end_index++; /* we're now interpolating the 2nd to last point */
-
- /* interpolate within 2nd to last point */
- for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ /* get points off the end (loop start if looping, duplicate point if end) */
+ if(looping)
{
- coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
- + coeffs[1] * dsp_data[dsp_phase_index]
- + coeffs[2] * dsp_data[dsp_phase_index+1]
- + coeffs[3] * end_point1);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart);
+ end_point2 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1);
}
-
- end_index++; /* we're now interpolating the last point */
-
- /* interpolate within the last point */
- for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ else
{
- coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
- dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
- + coeffs[1] * dsp_data[dsp_phase_index]
- + coeffs[2] * end_point1
- + coeffs[3] * end_point2);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end);
+ end_point2 = end_point1;
}
- if (!looping) break; /* break out if not looping (end of sample) */
-
- /* go back to loop start */
- if (dsp_phase_index > end_index)
+ while(1)
{
- fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
-
- if (!voice->has_looped)
- {
- voice->has_looped = 1;
- start_index = voice->loopstart;
- start_point = dsp_data[voice->loopend - 1];
- }
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+
+ /* interpolate first sample point (start or loop start) if needed */
+ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
+ dsp_buf[dsp_i] = dsp_amp *
+ (coeffs[0] * start_point
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2));
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ /* interpolate the sequence of sample points */
+ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
+ {
+ coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
+ dsp_buf[dsp_i] = dsp_amp *
+ (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2));
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ /* break out if buffer filled */
+ if(dsp_i >= FLUID_BUFSIZE)
+ {
+ break;
+ }
+
+ end_index++; /* we're now interpolating the 2nd to last point */
+
+ /* interpolate within 2nd to last point */
+ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
+ dsp_buf[dsp_i] = dsp_amp *
+ (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[3] * end_point1);
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ end_index++; /* we're now interpolating the last point */
+
+ /* interpolate within the last point */
+ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
+ dsp_buf[dsp_i] = dsp_amp *
+ (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[2] * end_point1
+ + coeffs[3] * end_point2);
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ if(!looping)
+ {
+ break; /* break out if not looping (end of sample) */
+ }
+
+ /* go back to loop start */
+ if(dsp_phase_index > end_index)
+ {
+ fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart);
+
+ if(!voice->has_looped)
+ {
+ voice->has_looped = 1;
+ start_index = voice->loopstart;
+ start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1);
+ }
+ }
+
+ /* break out if filled buffer */
+ if(dsp_i >= FLUID_BUFSIZE)
+ {
+ break;
+ }
+
+ end_index -= 2; /* set end back to third to last sample point */
}
- /* break out if filled buffer */
- if (dsp_i >= FLUID_BUFSIZE) break;
+ voice->phase = dsp_phase;
+ voice->amp = dsp_amp;
- end_index -= 2; /* set end back to third to last sample point */
- }
-
- voice->phase = dsp_phase;
- voice->amp = dsp_amp;
-
- return (dsp_i);
+ return (dsp_i);
}
/* 7th order interpolation.
@@ -423,253 +459,257 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
* smaller if end of sample occurs).
*/
int
-fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
+fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
{
- fluid_phase_t dsp_phase = voice->phase;
- fluid_phase_t dsp_phase_incr;
- short int *dsp_data = voice->sample->data;
- fluid_real_t *dsp_buf = voice->dsp_buf;
- fluid_real_t dsp_amp = voice->amp;
- fluid_real_t dsp_amp_incr = voice->amp_incr;
- unsigned int dsp_i = 0;
- unsigned int dsp_phase_index;
- unsigned int start_index, end_index;
- short int start_points[3];
- short int end_points[3];
- fluid_real_t *coeffs;
- int looping;
-
- /* Convert playback "speed" floating point value to phase index/fract */
- fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
-
- /* add 1/2 sample to dsp_phase since 7th order interpolation is centered on
- * the 4th sample point */
- fluid_phase_incr (dsp_phase, (fluid_phase_t)0x80000000);
-
- /* voice is currently looping? */
- looping = voice->is_looping;
-
- /* last index before 7th interpolation point must be specially handled */
- end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
-
- if (voice->has_looped) /* set start_index and start point if looped or not */
- {
- start_index = voice->loopstart;
- start_points[0] = dsp_data[voice->loopend - 1];
- start_points[1] = dsp_data[voice->loopend - 2];
- start_points[2] = dsp_data[voice->loopend - 3];
- }
- else
- {
- start_index = voice->start;
- start_points[0] = dsp_data[voice->start]; /* just duplicate the start point */
- start_points[1] = start_points[0];
- start_points[2] = start_points[0];
- }
-
- /* get the 3 points off the end (loop start if looping, duplicate point if end) */
- if (looping)
- {
- end_points[0] = dsp_data[voice->loopstart];
- end_points[1] = dsp_data[voice->loopstart + 1];
- end_points[2] = dsp_data[voice->loopstart + 2];
- }
- else
- {
- end_points[0] = dsp_data[voice->end];
- end_points[1] = end_points[0];
- end_points[2] = end_points[0];
- }
-
- while (1)
- {
- dsp_phase_index = fluid_phase_index (dsp_phase);
-
- /* interpolate first sample point (start or loop start) if needed */
- for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
- {
- coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
-
- dsp_buf[dsp_i] = dsp_amp
- * (coeffs[0] * (fluid_real_t)start_points[2]
- + coeffs[1] * (fluid_real_t)start_points[1]
- + coeffs[2] * (fluid_real_t)start_points[0]
- + coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
- + coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
- + coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
- + coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
- }
-
- start_index++;
-
- /* interpolate 2nd to first sample point (start or loop start) if needed */
- for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
- {
- coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
-
- dsp_buf[dsp_i] = dsp_amp
- * (coeffs[0] * (fluid_real_t)start_points[1]
- + coeffs[1] * (fluid_real_t)start_points[0]
- + coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
- + coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
- + coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
- + coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
- + coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
- }
-
- start_index++;
-
- /* interpolate 3rd to first sample point (start or loop start) if needed */
- for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ fluid_phase_t dsp_phase = voice->phase;
+ fluid_phase_t dsp_phase_incr;
+ short int *dsp_data = voice->sample->data;
+ char *dsp_data24 = voice->sample->data24;
+ fluid_real_t dsp_amp = voice->amp;
+ fluid_real_t dsp_amp_incr = voice->amp_incr;
+ unsigned int dsp_i = 0;
+ unsigned int dsp_phase_index;
+ unsigned int start_index, end_index;
+ fluid_real_t start_points[3], end_points[3];
+ const fluid_real_t *FLUID_RESTRICT coeffs;
+
+ /* Convert playback "speed" floating point value to phase index/fract */
+ fluid_phase_set_float(dsp_phase_incr, voice->phase_incr);
+
+ /* add 1/2 sample to dsp_phase since 7th order interpolation is centered on
+ * the 4th sample point */
+ fluid_phase_incr(dsp_phase, (fluid_phase_t)0x80000000);
+
+ /* last index before 7th interpolation point must be specially handled */
+ end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
+
+ if(voice->has_looped) /* set start_index and start point if looped or not */
{
- coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
-
- dsp_buf[dsp_i] = dsp_amp
- * (coeffs[0] * (fluid_real_t)start_points[0]
- + coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
- + coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
- + coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
- + coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
- + coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
- + coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ start_index = voice->loopstart;
+ start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1);
+ start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2);
+ start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3);
}
-
- start_index -= 2; /* set back to original start index */
-
-
- /* interpolate the sequence of sample points */
- for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
- {
- coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
-
- dsp_buf[dsp_i] = dsp_amp
- * (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
- + coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
- + coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
- + coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
- + coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
- + coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
- + coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
- }
-
- /* break out if buffer filled */
- if (dsp_i >= FLUID_BUFSIZE) break;
-
- end_index++; /* we're now interpolating the 3rd to last point */
-
- /* interpolate within 3rd to last point */
- for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ else
{
- coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
-
- dsp_buf[dsp_i] = dsp_amp
- * (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
- + coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
- + coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
- + coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
- + coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
- + coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
- + coeffs[6] * (fluid_real_t)end_points[0]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ start_index = voice->start;
+ start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the start point */
+ start_points[1] = start_points[0];
+ start_points[2] = start_points[0];
}
- end_index++; /* we're now interpolating the 2nd to last point */
-
- /* interpolate within 2nd to last point */
- for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ /* get the 3 points off the end (loop start if looping, duplicate point if end) */
+ if(looping)
{
- coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
-
- dsp_buf[dsp_i] = dsp_amp
- * (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
- + coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
- + coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
- + coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
- + coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
- + coeffs[5] * (fluid_real_t)end_points[0]
- + coeffs[6] * (fluid_real_t)end_points[1]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart);
+ end_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1);
+ end_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 2);
}
-
- end_index++; /* we're now interpolating the last point */
-
- /* interpolate within last point */
- for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ else
{
- coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
-
- dsp_buf[dsp_i] = dsp_amp
- * (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
- + coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
- + coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
- + coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
- + coeffs[4] * (fluid_real_t)end_points[0]
- + coeffs[5] * (fluid_real_t)end_points[1]
- + coeffs[6] * (fluid_real_t)end_points[2]);
-
- /* increment phase and amplitude */
- fluid_phase_incr (dsp_phase, dsp_phase_incr);
- dsp_phase_index = fluid_phase_index (dsp_phase);
- dsp_amp += dsp_amp_incr;
+ end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end);
+ end_points[1] = end_points[0];
+ end_points[2] = end_points[0];
}
- if (!looping) break; /* break out if not looping (end of sample) */
-
- /* go back to loop start */
- if (dsp_phase_index > end_index)
+ while(1)
{
- fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
-
- if (!voice->has_looped)
- {
- voice->has_looped = 1;
- start_index = voice->loopstart;
- start_points[0] = dsp_data[voice->loopend - 1];
- start_points[1] = dsp_data[voice->loopend - 2];
- start_points[2] = dsp_data[voice->loopend - 3];
- }
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+
+ /* interpolate first sample point (start or loop start) if needed */
+ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
+
+ dsp_buf[dsp_i] = dsp_amp
+ * (coeffs[0] * start_points[2]
+ + coeffs[1] * start_points[1]
+ + coeffs[2] * start_points[0]
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)
+ + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3));
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ start_index++;
+
+ /* interpolate 2nd to first sample point (start or loop start) if needed */
+ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
+
+ dsp_buf[dsp_i] = dsp_amp
+ * (coeffs[0] * start_points[1]
+ + coeffs[1] * start_points[0]
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)
+ + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3));
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ start_index++;
+
+ /* interpolate 3rd to first sample point (start or loop start) if needed */
+ for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
+
+ dsp_buf[dsp_i] = dsp_amp
+ * (coeffs[0] * start_points[0]
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)
+ + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3));
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ start_index -= 2; /* set back to original start index */
+
+
+ /* interpolate the sequence of sample points */
+ for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
+ {
+ coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
+
+ dsp_buf[dsp_i] = dsp_amp
+ * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)
+ + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3));
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ /* break out if buffer filled */
+ if(dsp_i >= FLUID_BUFSIZE)
+ {
+ break;
+ }
+
+ end_index++; /* we're now interpolating the 3rd to last point */
+
+ /* interpolate within 3rd to last point */
+ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
+
+ dsp_buf[dsp_i] = dsp_amp
+ * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)
+ + coeffs[6] * end_points[0]);
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ end_index++; /* we're now interpolating the 2nd to last point */
+
+ /* interpolate within 2nd to last point */
+ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
+
+ dsp_buf[dsp_i] = dsp_amp
+ * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)
+ + coeffs[5] * end_points[0]
+ + coeffs[6] * end_points[1]);
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ end_index++; /* we're now interpolating the last point */
+
+ /* interpolate within last point */
+ for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
+ {
+ coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)];
+
+ dsp_buf[dsp_i] = dsp_amp
+ * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3)
+ + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2)
+ + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1)
+ + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
+ + coeffs[4] * end_points[0]
+ + coeffs[5] * end_points[1]
+ + coeffs[6] * end_points[2]);
+
+ /* increment phase and amplitude */
+ fluid_phase_incr(dsp_phase, dsp_phase_incr);
+ dsp_phase_index = fluid_phase_index(dsp_phase);
+ dsp_amp += dsp_amp_incr;
+ }
+
+ if(!looping)
+ {
+ break; /* break out if not looping (end of sample) */
+ }
+
+ /* go back to loop start */
+ if(dsp_phase_index > end_index)
+ {
+ fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart);
+
+ if(!voice->has_looped)
+ {
+ voice->has_looped = 1;
+ start_index = voice->loopstart;
+ start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1);
+ start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2);
+ start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3);
+ }
+ }
+
+ /* break out if filled buffer */
+ if(dsp_i >= FLUID_BUFSIZE)
+ {
+ break;
+ }
+
+ end_index -= 3; /* set end back to 4th to last sample point */
}
- /* break out if filled buffer */
- if (dsp_i >= FLUID_BUFSIZE) break;
-
- end_index -= 3; /* set end back to 4th to last sample point */
- }
-
- /* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on
- * the 4th sample point (correct back to real value) */
- fluid_phase_decr (dsp_phase, (fluid_phase_t)0x80000000);
+ /* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on
+ * the 4th sample point (correct back to real value) */
+ fluid_phase_decr(dsp_phase, (fluid_phase_t)0x80000000);
- voice->phase = dsp_phase;
- voice->amp = dsp_amp;
+ voice->phase = dsp_phase;
+ voice->amp = dsp_amp;
- return (dsp_i);
+ return (dsp_i);
}
diff --git a/libs/fluidsynth/src/fluid_rvoice_event.c b/libs/fluidsynth/src/fluid_rvoice_event.c
index 65edb9dacb..4a513778bd 100644
--- a/libs/fluidsynth/src/fluid_rvoice_event.c
+++ b/libs/fluidsynth/src/fluid_rvoice_event.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -25,242 +25,144 @@
#include "fluid_lfo.h"
#include "fluid_adsr_env.h"
-#define EVENTFUNC_0(proc, type) \
- if (event->method == proc) { \
- proc((type) event->object); \
- return; }
-
-#define EVENTFUNC_R1(proc, type) \
- if (event->method == proc) { \
- if(event->intparam != 0) { FLUID_LOG(FLUID_DBG, "IR-mismatch"); } \
- proc((type) event->object, event->realparams[0]); \
- return; }
-
-#define EVENTFUNC_PTR(proc, type, type2) \
- if (event->method == proc) { \
- proc((type) event->object, (type2) event->ptr); \
- return; }
-
-#define EVENTFUNC_I1(proc, type) \
- if (event->method == proc) { \
- if(event->realparams[0] != 0.0f) { FLUID_LOG(FLUID_DBG, "IR-mismatch"); } \
- proc((type) event->object, event->intparam); \
- return; }
-
-#define EVENTFUNC_IR(proc, type) \
- if (event->method == proc) { \
- proc((type) event->object, event->intparam, event->realparams[0]); \
- return; }
-
-#define EVENTFUNC_ALL(proc, type) \
- if (event->method == proc) { \
- proc((type) event->object, event->intparam, event->realparams[0], \
- event->realparams[1], event->realparams[2], event->realparams[3], \
- event->realparams[4]); \
- return; }
-
-#define EVENTFUNC_R4(proc, type) \
- if (event->method == proc) { \
- proc((type) event->object, event->intparam, event->realparams[0], \
- event->realparams[1], event->realparams[2], event->realparams[3]); \
- return; }
+static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event);
-void
-fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event)
+static FLUID_INLINE void
+fluid_rvoice_event_dispatch(fluid_rvoice_event_t *event)
{
- EVENTFUNC_PTR(fluid_rvoice_mixer_add_voice, fluid_rvoice_mixer_t*, fluid_rvoice_t*);
- EVENTFUNC_I1(fluid_rvoice_noteoff, fluid_rvoice_t*);
- EVENTFUNC_0(fluid_rvoice_voiceoff, fluid_rvoice_t*);
- EVENTFUNC_0(fluid_rvoice_reset, fluid_rvoice_t*);
-
- EVENTFUNC_ALL(fluid_adsr_env_set_data, fluid_adsr_env_t*);
-
- EVENTFUNC_I1(fluid_lfo_set_delay, fluid_lfo_t*);
- EVENTFUNC_R1(fluid_lfo_set_incr, fluid_lfo_t*);
-
- EVENTFUNC_R1(fluid_iir_filter_set_fres, fluid_iir_filter_t*);
- EVENTFUNC_R1(fluid_iir_filter_set_q_dB, fluid_iir_filter_t*);
-
- EVENTFUNC_IR(fluid_rvoice_buffers_set_mapping, fluid_rvoice_buffers_t*);
- EVENTFUNC_IR(fluid_rvoice_buffers_set_amp, fluid_rvoice_buffers_t*);
-
- EVENTFUNC_R1(fluid_rvoice_set_modenv_to_pitch, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_output_rate, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_root_pitch_hz, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_synth_gain, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_pitch, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_attenuation, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_min_attenuation_cB, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_viblfo_to_pitch, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_pitch, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_vol, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_fc, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_modenv_to_fc, fluid_rvoice_t*);
- EVENTFUNC_R1(fluid_rvoice_set_modenv_to_pitch, fluid_rvoice_t*);
- EVENTFUNC_I1(fluid_rvoice_set_interp_method, fluid_rvoice_t*);
- EVENTFUNC_I1(fluid_rvoice_set_start, fluid_rvoice_t*);
- EVENTFUNC_I1(fluid_rvoice_set_end, fluid_rvoice_t*);
- EVENTFUNC_I1(fluid_rvoice_set_loopstart, fluid_rvoice_t*);
- EVENTFUNC_I1(fluid_rvoice_set_loopend, fluid_rvoice_t*);
- EVENTFUNC_I1(fluid_rvoice_set_samplemode, fluid_rvoice_t*);
- EVENTFUNC_PTR(fluid_rvoice_set_sample, fluid_rvoice_t*, fluid_sample_t*);
-
- EVENTFUNC_R1(fluid_rvoice_mixer_set_samplerate, fluid_rvoice_mixer_t*);
- EVENTFUNC_I1(fluid_rvoice_mixer_set_polyphony, fluid_rvoice_mixer_t*);
- EVENTFUNC_I1(fluid_rvoice_mixer_set_reverb_enabled, fluid_rvoice_mixer_t*);
- EVENTFUNC_I1(fluid_rvoice_mixer_set_chorus_enabled, fluid_rvoice_mixer_t*);
- EVENTFUNC_I1(fluid_rvoice_mixer_set_mix_fx, fluid_rvoice_mixer_t*);
- EVENTFUNC_0(fluid_rvoice_mixer_reset_fx, fluid_rvoice_mixer_t*);
- EVENTFUNC_0(fluid_rvoice_mixer_reset_reverb, fluid_rvoice_mixer_t*);
- EVENTFUNC_0(fluid_rvoice_mixer_reset_chorus, fluid_rvoice_mixer_t*);
- EVENTFUNC_IR(fluid_rvoice_mixer_set_threads, fluid_rvoice_mixer_t*);
-
- EVENTFUNC_ALL(fluid_rvoice_mixer_set_chorus_params, fluid_rvoice_mixer_t*);
- EVENTFUNC_R4(fluid_rvoice_mixer_set_reverb_params, fluid_rvoice_mixer_t*);
-
- FLUID_LOG(FLUID_ERR, "fluid_rvoice_event_dispatch: Unknown method %p to dispatch!", event->method);
+ event->method(event->object, event->param);
}
/**
* In order to be able to push more than one event atomically,
- * use push for all events, then use flush to commit them to the
+ * use push for all events, then use flush to commit them to the
* queue. If threadsafe is false, all events are processed immediately. */
int
-fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t* handler,
- void* method, void* object, int intparam,
- fluid_real_t realparam)
+fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler,
+ fluid_rvoice_function_t method, void *object, int intparam,
+ fluid_real_t realparam)
{
- fluid_rvoice_event_t* event;
- fluid_rvoice_event_t local_event;
- event = handler->is_threadsafe ?
- fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
-
- if (event == NULL) {
- FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
- return FLUID_FAILED; // Buffer full...
- }
-
- event->method = method;
- event->object = object;
- event->intparam = intparam;
- event->realparams[0] = realparam;
- if (handler->is_threadsafe)
- handler->queue_stored++;
- else
- fluid_rvoice_event_dispatch(event);
- return FLUID_OK;
-}
+ fluid_rvoice_event_t local_event;
+ local_event.method = method;
+ local_event.object = object;
+ local_event.param[0].i = intparam;
+ local_event.param[1].real = realparam;
-int
-fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t* handler,
- void* method, void* object, void* ptr)
+ return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
+}
+
+int
+fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler, fluid_rvoice_function_t method, void *object, fluid_rvoice_param_t param[MAX_EVENT_PARAMS])
{
- fluid_rvoice_event_t* event;
- fluid_rvoice_event_t local_event;
- event = handler->is_threadsafe ?
- fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
-
- if (event == NULL) {
- FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
- return FLUID_FAILED; // Buffer full...
- }
-
- event->method = method;
- event->object = object;
- event->ptr = ptr;
- if (handler->is_threadsafe)
- handler->queue_stored++;
- else
- fluid_rvoice_event_dispatch(event);
- return FLUID_OK;
+ fluid_rvoice_event_t local_event;
+
+ local_event.method = method;
+ local_event.object = object;
+ FLUID_MEMCPY(&local_event.param, param, sizeof(*param) * MAX_EVENT_PARAMS);
+
+ return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
}
+int
+fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler,
+ fluid_rvoice_function_t method, void *object, void *ptr)
+{
+ fluid_rvoice_event_t local_event;
+
+ local_event.method = method;
+ local_event.object = object;
+ local_event.param[0].ptr = ptr;
-int
-fluid_rvoice_eventhandler_push5(fluid_rvoice_eventhandler_t* handler,
- void* method, void* object, int intparam,
- fluid_real_t r1, fluid_real_t r2,
- fluid_real_t r3, fluid_real_t r4, fluid_real_t r5)
+ return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
+}
+
+static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event)
{
- fluid_rvoice_event_t* event;
- fluid_rvoice_event_t local_event;
- event = handler->is_threadsafe ?
- fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
-
- if (event == NULL) {
- FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
- return FLUID_FAILED; // Buffer full...
- }
-
- event->method = method;
- event->object = object;
- event->intparam = intparam;
- event->realparams[0] = r1;
- event->realparams[1] = r2;
- event->realparams[2] = r3;
- event->realparams[3] = r4;
- event->realparams[4] = r5;
- if (handler->is_threadsafe)
- handler->queue_stored++;
- else
- fluid_rvoice_event_dispatch(event);
- return FLUID_OK;
+ fluid_rvoice_event_t *event;
+ int old_queue_stored = fluid_atomic_int_add(&handler->queue_stored, 1);
+
+ event = fluid_ringbuffer_get_inptr(handler->queue, old_queue_stored);
+
+ if(event == NULL)
+ {
+ fluid_atomic_int_add(&handler->queue_stored, -1);
+ FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
+ return FLUID_FAILED; // Buffer full...
+ }
+
+ FLUID_MEMCPY(event, src_event, sizeof(*event));
+
+ return FLUID_OK;
}
-static void
-finished_voice_callback(void* userdata, fluid_rvoice_t* rvoice)
+void
+fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler, fluid_rvoice_t *rvoice)
{
- fluid_rvoice_eventhandler_t* eventhandler = userdata;
- fluid_rvoice_t** vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
- if (vptr == NULL)
- return; // Buffer full
- *vptr = rvoice;
- fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
+ fluid_rvoice_t **vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
+
+ if(vptr == NULL)
+ {
+ return; // Buffer full
+ }
+
+ *vptr = rvoice;
+ fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
}
-fluid_rvoice_eventhandler_t*
-new_fluid_rvoice_eventhandler(int is_threadsafe, int queuesize,
- int finished_voices_size, int bufs, int fx_bufs, fluid_real_t sample_rate)
+fluid_rvoice_eventhandler_t *
+new_fluid_rvoice_eventhandler(int queuesize,
+ int finished_voices_size, int bufs, int fx_bufs, int fx_units, fluid_real_t sample_rate, int extra_threads, int prio)
{
- fluid_rvoice_eventhandler_t* eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
- if (eventhandler == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- eventhandler->mixer = NULL;
- eventhandler->queue = NULL;
- eventhandler->finished_voices = NULL;
- eventhandler->is_threadsafe = is_threadsafe;
- eventhandler->queue_stored = 0;
-
- eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
- sizeof(fluid_rvoice_t*));
- if (eventhandler->finished_voices == NULL)
- goto error_recovery;
-
- eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t));
- if (eventhandler->queue == NULL)
- goto error_recovery;
-
- eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate);
- if (eventhandler->mixer == NULL)
- goto error_recovery;
- fluid_rvoice_mixer_set_finished_voices_callback(eventhandler->mixer,
- finished_voice_callback, eventhandler);
- return eventhandler;
-
+ fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
+
+ if(eventhandler == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ eventhandler->mixer = NULL;
+ eventhandler->queue = NULL;
+ eventhandler->finished_voices = NULL;
+
+ fluid_atomic_int_set(&eventhandler->queue_stored, 0);
+
+ eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
+ sizeof(fluid_rvoice_t *));
+
+ if(eventhandler->finished_voices == NULL)
+ {
+ goto error_recovery;
+ }
+
+ eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t));
+
+ if(eventhandler->queue == NULL)
+ {
+ goto error_recovery;
+ }
+
+ eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, sample_rate, eventhandler, extra_threads, prio);
+
+ if(eventhandler->mixer == NULL)
+ {
+ goto error_recovery;
+ }
+
+ return eventhandler;
+
error_recovery:
- delete_fluid_rvoice_eventhandler(eventhandler);
- return NULL;
+ delete_fluid_rvoice_eventhandler(eventhandler);
+ return NULL;
}
-int
-fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t* handler)
+int
+fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *handler)
{
- return fluid_ringbuffer_get_count(handler->queue);
+ return fluid_ringbuffer_get_count(handler->queue);
}
@@ -268,26 +170,30 @@ fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t* handler)
* Call fluid_rvoice_event_dispatch for all events in queue
* @return number of events dispatched
*/
-int
-fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t* handler)
+int
+fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *handler)
{
- fluid_rvoice_event_t* event;
- int result = 0;
- while (NULL != (event = fluid_ringbuffer_get_outptr(handler->queue))) {
- fluid_rvoice_event_dispatch(event);
- result++;
- fluid_ringbuffer_next_outptr(handler->queue);
- }
- return result;
+ fluid_rvoice_event_t *event;
+ int result = 0;
+
+ while(NULL != (event = fluid_ringbuffer_get_outptr(handler->queue)))
+ {
+ fluid_rvoice_event_dispatch(event);
+ result++;
+ fluid_ringbuffer_next_outptr(handler->queue);
+ }
+
+ return result;
}
-void
-delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t* handler)
+void
+delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *handler)
{
- if (handler == NULL) return;
- delete_fluid_rvoice_mixer(handler->mixer);
- delete_fluid_ringbuffer(handler->queue);
- delete_fluid_ringbuffer(handler->finished_voices);
- FLUID_FREE(handler);
+ fluid_return_if_fail(handler != NULL);
+
+ delete_fluid_rvoice_mixer(handler->mixer);
+ delete_fluid_ringbuffer(handler->queue);
+ delete_fluid_ringbuffer(handler->finished_voices);
+ FLUID_FREE(handler);
}
diff --git a/libs/fluidsynth/src/fluid_rvoice_event.h b/libs/fluidsynth/src/fluid_rvoice_event.h
index e8693bcd21..d1fd8d62cb 100644
--- a/libs/fluidsynth/src/fluid_rvoice_event.h
+++ b/libs/fluidsynth/src/fluid_rvoice_event.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -26,88 +26,87 @@
#include "fluid_rvoice_mixer.h"
#include "fluid_ringbuffer.h"
-#define EVENT_REAL_PARAMS (5)
-
typedef struct _fluid_rvoice_event_t fluid_rvoice_event_t;
-typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t;
-
-struct _fluid_rvoice_event_t {
- void* method;
- void* object;
- void* ptr;
- int intparam;
- fluid_real_t realparams[EVENT_REAL_PARAMS];
-};
-
-void fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event);
+struct _fluid_rvoice_event_t
+{
+ fluid_rvoice_function_t method;
+ void *object;
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS];
+};
-/**
- * Bridge between the renderer thread and the midi state thread.
- * If is_threadsafe is true, that means fluid_rvoice_eventhandler_fetch_all
- * can be called in parallell with fluid_rvoice_eventhandler_push/flush
+/*
+ * Bridge between the renderer thread and the midi state thread.
+ * fluid_rvoice_eventhandler_fetch_all() can be called in parallell
+ * with fluid_rvoice_eventhandler_push/flush()
*/
-struct _fluid_rvoice_eventhandler_t {
- int is_threadsafe; /* False for optimal performance, true for atomic operations */
- fluid_ringbuffer_t* queue; /**< List of fluid_rvoice_event_t */
- int queue_stored; /**< Extras pushed but not flushed */
- fluid_ringbuffer_t* finished_voices; /**< return queue from handler, list of fluid_rvoice_t* */
- fluid_rvoice_mixer_t* mixer;
+struct _fluid_rvoice_eventhandler_t
+{
+ fluid_ringbuffer_t *queue; /**< List of fluid_rvoice_event_t */
+ fluid_atomic_int_t queue_stored; /**< Extras pushed but not flushed */
+ fluid_ringbuffer_t *finished_voices; /**< return queue from handler, list of fluid_rvoice_t* */
+ fluid_rvoice_mixer_t *mixer;
};
-fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
- int is_threadsafe, int queuesize, int finished_voices_size, int bufs,
- int fx_bufs, fluid_real_t sample_rate);
+fluid_rvoice_eventhandler_t *new_fluid_rvoice_eventhandler(
+ int queuesize, int finished_voices_size, int bufs,
+ int fx_bufs, int fx_units, fluid_real_t sample_rate, int, int);
-void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t*);
+void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *);
-int fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t*);
-int fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t*);
+int fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *);
+int fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *);
+void fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler,
+ fluid_rvoice_t *rvoice);
-static FLUID_INLINE void
-fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t* handler)
+static FLUID_INLINE void
+fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t *handler)
{
- if (handler->queue_stored > 0) {
- fluid_ringbuffer_next_inptr(handler->queue, handler->queue_stored);
- handler->queue_stored = 0;
- }
+ int queue_stored = fluid_atomic_int_get(&handler->queue_stored);
+
+ if(queue_stored > 0)
+ {
+ fluid_atomic_int_set(&handler->queue_stored, 0);
+ fluid_ringbuffer_next_inptr(handler->queue, queue_stored);
+ }
}
/**
* @return next finished voice, or NULL if nothing in queue
*/
-static FLUID_INLINE fluid_rvoice_t*
-fluid_rvoice_eventhandler_get_finished_voice(fluid_rvoice_eventhandler_t* handler)
+static FLUID_INLINE fluid_rvoice_t *
+fluid_rvoice_eventhandler_get_finished_voice(fluid_rvoice_eventhandler_t *handler)
{
- void* result = fluid_ringbuffer_get_outptr(handler->finished_voices);
- if (result == NULL) return NULL;
- result = * (fluid_rvoice_t**) result;
- fluid_ringbuffer_next_outptr(handler->finished_voices);
- return result;
+ void *result = fluid_ringbuffer_get_outptr(handler->finished_voices);
+
+ if(result == NULL)
+ {
+ return NULL;
+ }
+
+ result = * (fluid_rvoice_t **) result;
+ fluid_ringbuffer_next_outptr(handler->finished_voices);
+ return result;
}
-int fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t* handler,
- void* method, void* object, int intparam,
- fluid_real_t realparam);
+int fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler,
+ fluid_rvoice_function_t method, void *object, int intparam,
+ fluid_real_t realparam);
-int fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t* handler,
- void* method, void* object, void* ptr);
+int fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler,
+ fluid_rvoice_function_t method, void *object, void *ptr);
-int fluid_rvoice_eventhandler_push5(fluid_rvoice_eventhandler_t* handler,
- void* method, void* object, int intparam,
- fluid_real_t r1, fluid_real_t r2,
- fluid_real_t r3, fluid_real_t r4, fluid_real_t r5);
+int fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler,
+ fluid_rvoice_function_t method, void *object,
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS]);
static FLUID_INLINE void
-fluid_rvoice_eventhandler_add_rvoice(fluid_rvoice_eventhandler_t* handler,
- fluid_rvoice_t* rvoice)
+fluid_rvoice_eventhandler_add_rvoice(fluid_rvoice_eventhandler_t *handler,
+ fluid_rvoice_t *rvoice)
{
- if (handler->is_threadsafe)
fluid_rvoice_eventhandler_push_ptr(handler, fluid_rvoice_mixer_add_voice,
handler->mixer, rvoice);
- else
- fluid_rvoice_mixer_add_voice(handler->mixer, rvoice);
}
diff --git a/libs/fluidsynth/src/fluid_rvoice_mixer.c b/libs/fluidsynth/src/fluid_rvoice_mixer.c
index d5369aacce..8c5254f269 100644
--- a/libs/fluidsynth/src/fluid_rvoice_mixer.c
+++ b/libs/fluidsynth/src/fluid_rvoice_mixer.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -24,10 +24,7 @@
#include "fluid_rev.h"
#include "fluid_chorus.h"
#include "fluidsynth_priv.h"
-//#include "fluid_ladspa.h"
-
-#define SYNTH_REVERB_CHANNEL 0
-#define SYNTH_CHORUS_CHANNEL 1
+#include "fluid_synth.h"
#undef ENABLE_MIXER_THREADS // Ardour does the multithreading -- synth.cpu-cores defaults to 1
@@ -37,492 +34,651 @@
typedef struct _fluid_mixer_buffers_t fluid_mixer_buffers_t;
-struct _fluid_mixer_buffers_t {
- fluid_rvoice_mixer_t* mixer; /**< Owner of object */
-#ifdef ENABLE_MIXER_THREADS
- fluid_thread_t* thread; /**< Thread object */
+struct _fluid_mixer_buffers_t
+{
+ fluid_rvoice_mixer_t *mixer; /**< Owner of object */
+#if ENABLE_MIXER_THREADS
+ fluid_thread_t *thread; /**< Thread object */
#endif
- fluid_rvoice_t** finished_voices; /* List of voices who have finished */
- int finished_voice_count;
-
- int ready; /**< Atomic: buffers are ready for mixing */
-
- int buf_blocks; /**< Number of blocks allocated in the buffers */
-
- int buf_count;
- fluid_real_t** left_buf;
- fluid_real_t** right_buf;
-
- int fx_buf_count;
- fluid_real_t** fx_left_buf;
- fluid_real_t** fx_right_buf;
+ fluid_rvoice_t **finished_voices; /* List of voices who have finished */
+ int finished_voice_count;
+
+ fluid_atomic_int_t ready; /**< Atomic: buffers are ready for mixing */
+
+ fluid_real_t *local_buf;
+
+ int buf_count;
+ int fx_buf_count;
+
+ /** buffer to store the left part of a stereo channel to.
+ * Specifically a two dimensional array, containing \c buf_count sample buffers
+ * (i.e. for each synth.audio-channels), of which each contains
+ * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT audio items (=samples)
+ * @note Each sample buffer is aligned to the FLUID_DEFAULT_ALIGNMENT
+ * boundary provided that this pointer points to an aligned buffer.
+ * So make sure to access the sample buffer by first aligning this
+ * pointer using fluid_align_ptr()
+ */
+ fluid_real_t *left_buf;
+
+ /** dito, but for right part of a stereo channel */
+ fluid_real_t *right_buf;
+
+ /** buffer to store the left part of a stereo effects channel to.
+ * Specifically a two dimensional array, containing \c fx_buf_count buffers
+ * (i.e. for each synth.effects-channels), of which each buffer contains
+ * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT audio items (=samples)
+ */
+ fluid_real_t *fx_left_buf;
+ fluid_real_t *fx_right_buf;
};
typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t;
-struct _fluid_mixer_fx_t {
- fluid_revmodel_t* reverb; /**< Reverb unit */
- fluid_chorus_t* chorus; /**< Chorus unit */
- int with_reverb; /**< Should the synth use the built-in reverb unit? */
- int with_chorus; /**< Should the synth use the built-in chorus unit? */
- int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
+struct _fluid_mixer_fx_t
+{
+ fluid_revmodel_t *reverb; /**< Reverb unit */
+ fluid_chorus_t *chorus; /**< Chorus unit */
};
-struct _fluid_rvoice_mixer_t {
- fluid_mixer_fx_t fx;
+struct _fluid_rvoice_mixer_t
+{
+ fluid_mixer_fx_t *fx;
- fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
- void (*remove_voice_callback)(void*, fluid_rvoice_t*); /**< Used by mixer only: Receive this callback every time a voice is removed */
- void* remove_voice_callback_userdata;
+ fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
+ fluid_rvoice_eventhandler_t *eventhandler;
- fluid_rvoice_t** rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
- int polyphony; /**< Read-only: Length of voices array */
- int active_voices; /**< Read-only: Number of non-null voices */
- int current_blockcount; /**< Read-only: how many blocks to process this time */
+ fluid_rvoice_t **rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
+ int polyphony; /**< Read-only: Length of voices array */
+ int active_voices; /**< Read-only: Number of non-null voices */
+ int current_blockcount; /**< Read-only: how many blocks to process this time */
+ int fx_units;
+ int with_reverb; /**< Should the synth use the built-in reverb unit? */
+ int with_chorus; /**< Should the synth use the built-in chorus unit? */
+ int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
#ifdef LADSPA
- fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
+ fluid_ladspa_fx_t *ladspa_fx; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
#endif
-#ifdef ENABLE_MIXER_THREADS
+#if ENABLE_MIXER_THREADS
// int sleeping_threads; /**< Atomic: number of threads currently asleep */
// int active_threads; /**< Atomic: number of threads in the thread loop */
- int threads_should_terminate; /**< Atomic: Set to TRUE when threads should terminate */
- int current_rvoice; /**< Atomic: for the threads to know next voice to */
- fluid_cond_t* wakeup_threads; /**< Signalled when the threads should wake up */
- fluid_cond_mutex_t* wakeup_threads_m; /**< wakeup_threads mutex companion */
- fluid_cond_t* thread_ready; /**< Signalled from thread, when the thread has a buffer ready for mixing */
- fluid_cond_mutex_t* thread_ready_m; /**< thread_ready mutex companion */
-
- int thread_count; /**< Number of extra mixer threads for multi-core rendering */
- fluid_mixer_buffers_t* threads; /**< Array of mixer threads (thread_count in length) */
+ fluid_atomic_int_t threads_should_terminate; /**< Atomic: Set to TRUE when threads should terminate */
+ fluid_atomic_int_t current_rvoice; /**< Atomic: for the threads to know next voice to */
+ fluid_cond_t *wakeup_threads; /**< Signalled when the threads should wake up */
+ fluid_cond_mutex_t *wakeup_threads_m; /**< wakeup_threads mutex companion */
+ fluid_cond_t *thread_ready; /**< Signalled from thread, when the thread has a buffer ready for mixing */
+ fluid_cond_mutex_t *thread_ready_m; /**< thread_ready mutex companion */
+
+ int thread_count; /**< Number of extra mixer threads for multi-core rendering */
+ fluid_mixer_buffers_t *threads; /**< Array of mixer threads (thread_count in length) */
#endif
};
-static FLUID_INLINE void
-fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
-{
- int i;
- fluid_profile_ref_var(prof_ref);
- if (mixer->fx.with_reverb) {
- if (mixer->fx.mix_fx_to_out) {
- for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
- fluid_revmodel_processmix(mixer->fx.reverb,
- &mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
- &mixer->buffers.left_buf[0][i],
- &mixer->buffers.right_buf[0][i]);
- }
- else {
- for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
- fluid_revmodel_processreplace(mixer->fx.reverb,
- &mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
- &mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
- &mixer->buffers.fx_right_buf[SYNTH_REVERB_CHANNEL][i]);
- }
- fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref);
- }
-
- if (mixer->fx.with_chorus) {
- if (mixer->fx.mix_fx_to_out) {
- for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
- fluid_chorus_processmix(mixer->fx.chorus,
- &mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
- &mixer->buffers.left_buf[0][i],
- &mixer->buffers.right_buf[0][i]);
- }
- else {
- for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
- fluid_chorus_processreplace(mixer->fx.chorus,
- &mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
- &mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
- &mixer->buffers.fx_right_buf[SYNTH_CHORUS_CHANNEL][i]);
- }
- fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref);
- }
-
-#ifdef LADSPA
- /* Run the signal through the LADSPA Fx unit */
- if (mixer->LADSPA_FxUnit) {
- int j;
- FLUID_DECLARE_VLA(fluid_real_t*, left_buf, mixer->buffers.buf_count);
- FLUID_DECLARE_VLA(fluid_real_t*, right_buf, mixer->buffers.buf_count);
- FLUID_DECLARE_VLA(fluid_real_t*, fx_left_buf, mixer->buffers.fx_buf_count);
- FLUID_DECLARE_VLA(fluid_real_t*, fx_right_buf, mixer->buffers.fx_buf_count);
- for (j=0; j < mixer->buffers.buf_count; j++) {
- left_buf[j] = mixer->buffers.left_buf[j];
- right_buf[j] = mixer->buffers.right_buf[j];
- }
- for (j=0; j < mixer->buffers.fx_buf_count; j++) {
- fx_left_buf[j] = mixer->buffers.fx_left_buf[j];
- fx_right_buf[j] = mixer->buffers.fx_right_buf[j];
- }
- for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE) {
- fluid_LADSPA_run(mixer->LADSPA_FxUnit, left_buf, right_buf, fx_left_buf,
- fx_right_buf);
- for (j=0; j < mixer->buffers.buf_count; j++) {
- left_buf[j] += FLUID_BUFSIZE;
- right_buf[j] += FLUID_BUFSIZE;
- }
- for (j=0; j < mixer->buffers.fx_buf_count; j++) {
- fx_left_buf[j] += FLUID_BUFSIZE;
- fx_right_buf[j] += FLUID_BUFSIZE;
- }
- }
- fluid_check_fpe("LADSPA");
- }
+#if ENABLE_MIXER_THREADS
+static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t *mixer);
+static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t *mixer, int thread_count, int prio_level);
#endif
-}
-/**
- * During rendering, rvoices might be finished. Set this callback
- * for getting a callback any time the rvoice is finished.
- */
-void fluid_rvoice_mixer_set_finished_voices_callback(
- fluid_rvoice_mixer_t* mixer,
- void (*func)(void*, fluid_rvoice_t*),
- void* userdata)
+static FLUID_INLINE void
+fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcount)
{
- mixer->remove_voice_callback_userdata = userdata;
- mixer->remove_voice_callback = func;
-}
+ const int fx_channels_per_unit = mixer->buffers.fx_buf_count / mixer->fx_units;
+ int i, f;
+ void (*reverb_process_func)(fluid_revmodel_t *rev, fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
+ void (*chorus_process_func)(fluid_chorus_t *chorus, fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
+ fluid_real_t *out_rev_l, *out_rev_r, *out_ch_l, *out_ch_r;
-/**
- * Synthesize one voice and add to buffer.
- * NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
- * voice has been finished, removed and possibly replaced with another voice.
- * @return Number of samples written
- */
-static int
-fluid_mix_one(fluid_rvoice_t* rvoice, fluid_real_t** bufs, unsigned int bufcount, int blockcount)
-{
- int i, result = 0;
+ // all dry unprocessed mono input is stored in the left channel
+ fluid_real_t *in_rev = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+ fluid_real_t *in_ch = in_rev;
+
+ fluid_profile_ref_var(prof_ref);
- FLUID_DECLARE_VLA(fluid_real_t, local_buf, FLUID_BUFSIZE*blockcount);
- for (i=0; i < blockcount; i++) {
- int s = fluid_rvoice_write(rvoice, &local_buf[FLUID_BUFSIZE*i]);
- if (s == -1) {
- s = FLUID_BUFSIZE; /* Voice is quiet, TODO: optimize away memset/mix */
- FLUID_MEMSET(&local_buf[FLUID_BUFSIZE*i], 0, FLUID_BUFSIZE*sizeof(fluid_real_t));
- }
- result += s;
- if (s < FLUID_BUFSIZE) {
- break;
+ if(mixer->mix_fx_to_out)
+ {
+ // mix effects to first stereo channel
+ out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
+ out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ reverb_process_func = fluid_revmodel_processmix;
+ chorus_process_func = fluid_chorus_processmix;
+
+ }
+ else
+ {
+ // replace effects into respective stereo effects channel
+ out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+ out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ reverb_process_func = fluid_revmodel_processreplace;
+ chorus_process_func = fluid_chorus_processreplace;
+ }
+
+
+ if(mixer->with_reverb)
+ {
+ for(f = 0; f < mixer->fx_units; f++)
+ {
+ int buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL;
+
+ for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
+ {
+ int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + i;
+
+ reverb_process_func(mixer->fx[f].reverb,
+ &in_rev[samp_idx],
+ mixer->mix_fx_to_out ? &out_rev_l[i] : &out_rev_l[samp_idx],
+ mixer->mix_fx_to_out ? &out_rev_r[i] : &out_rev_r[samp_idx]);
+ }
+ }
+
+ fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref, 0,
+ current_blockcount * FLUID_BUFSIZE);
+ }
+
+ if(mixer->with_chorus)
+ {
+ for(f = 0; f < mixer->fx_units; f++)
+ {
+ int buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL;
+
+ for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
+ {
+ int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + i;
+
+ chorus_process_func(mixer->fx[f].chorus,
+ &in_ch [samp_idx],
+ mixer->mix_fx_to_out ? &out_ch_l[i] : &out_ch_l[samp_idx],
+ mixer->mix_fx_to_out ? &out_ch_r[i] : &out_ch_r[samp_idx]);
+ }
+ }
+
+ fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref, 0,
+ current_blockcount * FLUID_BUFSIZE);
+ }
+
+#ifdef LADSPA
+
+ /* Run the signal through the LADSPA Fx unit. The buffers have already been
+ * set up in fluid_rvoice_mixer_set_ladspa. */
+ if(mixer->ladspa_fx)
+ {
+ fluid_ladspa_run(mixer->ladspa_fx, current_blockcount, FLUID_BUFSIZE);
+ fluid_check_fpe("LADSPA");
}
- }
- fluid_rvoice_buffers_mix(&rvoice->buffers, local_buf, result, bufs, bufcount);
- return result;
+#endif
}
/**
* Glue to get fluid_rvoice_buffers_mix what it wants
* Note: Make sure outbufs has 2 * (buf_count + fx_buf_count) elements before calling
*/
-static FLUID_INLINE int
-fluid_mixer_buffers_prepare(fluid_mixer_buffers_t* buffers, fluid_real_t** outbufs)
-{
- fluid_real_t* reverb_buf, *chorus_buf;
- int i;
-
- /* Set up the reverb / chorus buffers only, when the effect is
- * enabled on synth level. Nonexisting buffers are detected in the
- * DSP loop. Not sending the reverb / chorus signal saves some time
- * in that case. */
- reverb_buf = buffers->mixer->fx.with_reverb ? buffers->fx_left_buf[SYNTH_REVERB_CHANNEL] : NULL;
- chorus_buf = buffers->mixer->fx.with_chorus ? buffers->fx_left_buf[SYNTH_CHORUS_CHANNEL] : NULL;
- outbufs[buffers->buf_count*2 + SYNTH_REVERB_CHANNEL] = reverb_buf;
- outbufs[buffers->buf_count*2 + SYNTH_CHORUS_CHANNEL] = chorus_buf;
-
- /* The output associated with a MIDI channel is wrapped around
- * using the number of audio groups as modulo divider. This is
- * typically the number of output channels on the 'sound card',
- * as long as the LADSPA Fx unit is not used. In case of LADSPA
- * unit, think of it as subgroups on a mixer.
- *
- * For example: Assume that the number of groups is set to 2.
- * Then MIDI channel 1, 3, 5, 7 etc. go to output 1, channels 2,
- * 4, 6, 8 etc to output 2. Or assume 3 groups: Then MIDI
- * channels 1, 4, 7, 10 etc go to output 1; 2, 5, 8, 11 etc to
- * output 2, 3, 6, 9, 12 etc to output 3.
- */
-
- for (i = 0; i < buffers->buf_count; i++) {
- outbufs[i*2] = buffers->left_buf[i];
- outbufs[i*2+1] = buffers->right_buf[i];
- }
- return buffers->buf_count*2 + 2;
+static FLUID_INLINE int
+fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbufs)
+{
+ fluid_real_t *base_ptr;
+ int i;
+ const int fx_channels_per_unit = buffers->fx_buf_count / buffers->mixer->fx_units;
+ const int offset = buffers->buf_count * 2;
+ int with_reverb = buffers->mixer->with_reverb;
+ int with_chorus = buffers->mixer->with_chorus;
+
+ /* Set up the reverb and chorus buffers only when the effect is enabled or
+ * when LADSPA is active. Nonexisting buffers are detected in the DSP loop.
+ * Not sending the effect signals saves some time in that case. */
+#ifdef LADSPA
+ int with_ladspa = (buffers->mixer->ladspa_fx != NULL);
+ with_reverb = (with_reverb | with_ladspa);
+ with_chorus = (with_chorus | with_ladspa);
+#endif
+
+ // all the dry, non-processed mono audio for effects is to be stored in the left buffers
+ base_ptr = fluid_align_ptr(buffers->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < buffers->mixer->fx_units; i++)
+ {
+ int fx_idx = i * fx_channels_per_unit;
+
+ outbufs[offset + fx_idx + SYNTH_REVERB_CHANNEL] =
+ (with_reverb)
+ ? &base_ptr[(fx_idx + SYNTH_REVERB_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
+ : NULL;
+
+ outbufs[offset + fx_idx + SYNTH_CHORUS_CHANNEL] =
+ (with_chorus)
+ ? &base_ptr[(fx_idx + SYNTH_CHORUS_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
+ : NULL;
+ }
+
+ /* The output associated with a MIDI channel is wrapped around
+ * using the number of audio groups as modulo divider. This is
+ * typically the number of output channels on the 'sound card',
+ * as long as the LADSPA Fx unit is not used. In case of LADSPA
+ * unit, think of it as subgroups on a mixer.
+ *
+ * For example: Assume that the number of groups is set to 2.
+ * Then MIDI channel 1, 3, 5, 7 etc. go to output 1, channels 2,
+ * 4, 6, 8 etc to output 2. Or assume 3 groups: Then MIDI
+ * channels 1, 4, 7, 10 etc go to output 1; 2, 5, 8, 11 etc to
+ * output 2, 3, 6, 9, 12 etc to output 3.
+ */
+ base_ptr = fluid_align_ptr(buffers->left_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < buffers->buf_count; i++)
+ {
+ outbufs[i * 2] = &base_ptr[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
+ }
+
+ base_ptr = fluid_align_ptr(buffers->right_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < buffers->buf_count; i++)
+ {
+ outbufs[i * 2 + 1] = &base_ptr[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
+ }
+
+ return offset + buffers->fx_buf_count;
}
static FLUID_INLINE void
-fluid_finish_rvoice(fluid_mixer_buffers_t* buffers, fluid_rvoice_t* rvoice)
-{
- if (buffers->finished_voice_count < buffers->mixer->polyphony)
- buffers->finished_voices[buffers->finished_voice_count++] = rvoice;
- else
- FLUID_LOG(FLUID_ERR, "Exceeded finished voices array, try increasing polyphony");
-}
-
-static void
-fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t* buffers)
-{
- int i,j;
- for (i=0; i < buffers->finished_voice_count; i++) {
- fluid_rvoice_t* v = buffers->finished_voices[i];
- int* av = &buffers->mixer->active_voices;
- for (j=0; j < *av; j++) {
- if (v == buffers->mixer->rvoices[j]) {
- (*av)--;
- /* Pack the array */
- if (j < *av)
- buffers->mixer->rvoices[j] = buffers->mixer->rvoices[*av];
- }
- }
- if (buffers->mixer->remove_voice_callback)
- buffers->mixer->remove_voice_callback(
- buffers->mixer->remove_voice_callback_userdata, v);
- }
- buffers->finished_voice_count = 0;
-}
-
-static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice_mixer_t* mixer)
-{
-#ifdef ENABLE_MIXER_THREADS
- int i;
- for (i=0; i < mixer->thread_count; i++)
- fluid_mixer_buffer_process_finished_voices(&mixer->threads[i]);
+fluid_finish_rvoice(fluid_mixer_buffers_t *buffers, fluid_rvoice_t *rvoice)
+{
+ if(buffers->finished_voice_count < buffers->mixer->polyphony)
+ {
+ buffers->finished_voices[buffers->finished_voice_count++] = rvoice;
+ }
+ else
+ {
+ FLUID_LOG(FLUID_ERR, "Exceeded finished voices array, try increasing polyphony");
+ }
+}
+
+static void
+fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t *buffers)
+{
+ int i, j;
+
+ for(i = 0; i < buffers->finished_voice_count; i++)
+ {
+ fluid_rvoice_t *v = buffers->finished_voices[i];
+ int av = buffers->mixer->active_voices;
+
+ for(j = 0; j < av; j++)
+ {
+ if(v == buffers->mixer->rvoices[j])
+ {
+ av--;
+
+ /* Pack the array */
+ if(j < av)
+ {
+ buffers->mixer->rvoices[j] = buffers->mixer->rvoices[av];
+ }
+ }
+ }
+
+ buffers->mixer->active_voices = av;
+
+ fluid_rvoice_eventhandler_finished_voice_callback(buffers->mixer->eventhandler, v);
+ }
+
+ buffers->finished_voice_count = 0;
+}
+
+static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice_mixer_t *mixer)
+{
+#if ENABLE_MIXER_THREADS
+ int i;
+
+ for(i = 0; i < mixer->thread_count; i++)
+ {
+ fluid_mixer_buffer_process_finished_voices(&mixer->threads[i]);
+ }
+
#endif
- fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
+ fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
}
-static FLUID_INLINE void
-fluid_mixer_buffers_render_one(fluid_mixer_buffers_t* buffers,
- fluid_rvoice_t* voice, fluid_real_t** bufs,
- unsigned int bufcount)
+
+static FLUID_INLINE fluid_real_t *
+get_dest_buf(fluid_rvoice_buffers_t *buffers, int index,
+ fluid_real_t **dest_bufs, int dest_bufcount)
{
- int s = fluid_mix_one(voice, bufs, bufcount, buffers->mixer->current_blockcount);
- if (s < buffers->mixer->current_blockcount * FLUID_BUFSIZE) {
- fluid_finish_rvoice(buffers, voice);
- }
+ int j = buffers->bufs[index].mapping;
+
+ if(j >= dest_bufcount || j < 0)
+ {
+ return NULL;
+ }
+
+ return dest_bufs[j];
}
-/*
-static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
- fluid_rvoice_t* voice)
+
+/**
+ * Mix data down to buffers
+ *
+ * @param buffers Destination buffer(s)
+ * @param dsp_buf Mono sample source
+ * @param start_block Block to start mixing at
+ * @param sample_count number of samples to mix following \c start_block
+ * @param dest_bufs Array of buffers to mixdown to
+ * @param dest_bufcount Length of dest_bufs
+ */
+static void
+fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
+ fluid_real_t *FLUID_RESTRICT dsp_buf,
+ int start_block, int sample_count,
+ fluid_real_t **dest_bufs, int dest_bufcount)
{
- int i, retval=0;
- int fvc = buffers->finished_voice_count;
- for (i=0; i < fvc; i++)
- if (buffers->finished_voices[i] == voice) {
- fvc--;
- if (i < fvc)
- buffers->finished_voices[i] = buffers->finished_voices[fvc];
- retval++;
+ int bufcount = buffers->count;
+ int i, dsp_i;
+
+ if(sample_count <= 0 || dest_bufcount <= 0)
+ {
+ return;
+ }
+
+ FLUID_ASSERT((uintptr_t)dsp_buf % FLUID_DEFAULT_ALIGNMENT == 0);
+ FLUID_ASSERT((uintptr_t)(&dsp_buf[start_block * FLUID_BUFSIZE]) % FLUID_DEFAULT_ALIGNMENT == 0);
+
+ for(i = 0; i < bufcount; i++)
+ {
+ fluid_real_t *FLUID_RESTRICT buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
+ fluid_real_t amp = buffers->bufs[i].amp;
+
+ if(buf == NULL || amp == 0.0f)
+ {
+ continue;
+ }
+
+ FLUID_ASSERT((uintptr_t)buf % FLUID_DEFAULT_ALIGNMENT == 0);
+
+ #pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
+
+ for(dsp_i = (start_block * FLUID_BUFSIZE); dsp_i < sample_count; dsp_i++)
+ {
+ buf[dsp_i] += amp * dsp_buf[dsp_i];
+ }
}
- fvc = buffers->finished_voice_count;
- return retval;
}
-*/
-int
-fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice)
+/**
+ * Synthesize one voice and add to buffer.
+ * NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
+ * voice has been finished, removed and possibly replaced with another voice.
+ */
+static FLUID_INLINE void
+fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers,
+ fluid_rvoice_t *rvoice, fluid_real_t **dest_bufs,
+ unsigned int dest_bufcount, fluid_real_t *src_buf, int blockcount)
{
- int i;
+ int i, total_samples = 0, start_block = 0;
- if (mixer->active_voices < mixer->polyphony) {
- mixer->rvoices[mixer->active_voices++] = voice;
- return FLUID_OK;
- }
-
- /* See if any voices just finished, if so, take its place.
- This can happen in voice overflow conditions. */
- for (i=0; i < mixer->active_voices; i++) {
- if (mixer->rvoices[i] == voice) {
- FLUID_LOG(FLUID_ERR, "Internal error: Trying to replace an existing rvoice in fluid_rvoice_mixer_add_voice?!");
- return FLUID_FAILED;
+ for(i = 0; i < blockcount; i++)
+ {
+ int s = fluid_rvoice_write(rvoice, &src_buf[FLUID_BUFSIZE * i]);
+
+ if(s == -1)
+ {
+ start_block += s;
+ s = FLUID_BUFSIZE;
+ }
+
+ total_samples += s;
+
+ if(s < FLUID_BUFSIZE)
+ {
+ break;
+ }
}
- if (mixer->rvoices[i]->envlfo.volenv.section == FLUID_VOICE_ENVFINISHED) {
- fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]);
- mixer->rvoices[i] = voice;
- return FLUID_OK;
+
+ fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, -start_block, total_samples - ((-start_block)*FLUID_BUFSIZE), dest_bufs, dest_bufcount);
+
+ if(total_samples < blockcount * FLUID_BUFSIZE)
+ {
+ fluid_finish_rvoice(buffers, rvoice);
}
- }
+}
- /* This should never happen */
- FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
- return FLUID_FAILED;
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice)
+{
+ int i;
+ fluid_rvoice_mixer_t *mixer = obj;
+ fluid_rvoice_t *voice = param[0].ptr;
+
+ if(mixer->active_voices < mixer->polyphony)
+ {
+ mixer->rvoices[mixer->active_voices++] = voice;
+ return; // success
+ }
+
+ /* See if any voices just finished, if so, take its place.
+ This can happen in voice overflow conditions. */
+ for(i = 0; i < mixer->active_voices; i++)
+ {
+ if(mixer->rvoices[i] == voice)
+ {
+ FLUID_LOG(FLUID_ERR, "Internal error: Trying to replace an existing rvoice in fluid_rvoice_mixer_add_voice?!");
+ return;
+ }
+
+ if(mixer->rvoices[i]->envlfo.volenv.section == FLUID_VOICE_ENVFINISHED)
+ {
+ fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]);
+ mixer->rvoices[i] = voice;
+ return; // success
+ }
+ }
+
+ /* This should never happen */
+ FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
+ return;
}
-static int
-fluid_mixer_buffers_update_polyphony(fluid_mixer_buffers_t* buffers, int value)
+static int
+fluid_mixer_buffers_update_polyphony(fluid_mixer_buffers_t *buffers, int value)
{
- void* newptr;
+ void *newptr;
- if (buffers->finished_voice_count > value)
- return FLUID_FAILED;
-
- newptr = FLUID_REALLOC(buffers->finished_voices, value * sizeof(fluid_rvoice_t*));
- if (newptr == NULL && value > 0)
- return FLUID_FAILED;
- buffers->finished_voices = newptr;
- return FLUID_OK;
+ if(buffers->finished_voice_count > value)
+ {
+ return FLUID_FAILED;
+ }
+
+ newptr = FLUID_REALLOC(buffers->finished_voices, value * sizeof(fluid_rvoice_t *));
+
+ if(newptr == NULL && value > 0)
+ {
+ return FLUID_FAILED;
+ }
+
+ buffers->finished_voices = newptr;
+ return FLUID_OK;
}
/**
* Update polyphony - max number of voices (NOTE: not hard real-time capable)
* @return FLUID_OK or FLUID_FAILED
*/
-int
-fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony)
{
- void* newptr;
- if (handler->active_voices > value)
- return FLUID_FAILED;
+ void *newptr;
+ fluid_rvoice_mixer_t *handler = obj;
+ int value = param[0].i;
- newptr = FLUID_REALLOC(handler->rvoices, value * sizeof(fluid_rvoice_t*));
- if (newptr == NULL)
- return FLUID_FAILED;
- handler->rvoices = newptr;
+ if(handler->active_voices > value)
+ {
+ return /*FLUID_FAILED*/;
+ }
- if (fluid_mixer_buffers_update_polyphony(&handler->buffers, value)
- == FLUID_FAILED)
- return FLUID_FAILED;
+ newptr = FLUID_REALLOC(handler->rvoices, value * sizeof(fluid_rvoice_t *));
-#ifdef ENABLE_MIXER_THREADS
- {
- int i;
- for (i=0; i < handler->thread_count; i++)
- if (fluid_mixer_buffers_update_polyphony(&handler->threads[i], value)
- == FLUID_FAILED)
- return FLUID_FAILED;
- }
+ if(newptr == NULL)
+ {
+ return /*FLUID_FAILED*/;
+ }
+
+ handler->rvoices = newptr;
+
+ if(fluid_mixer_buffers_update_polyphony(&handler->buffers, value)
+ == FLUID_FAILED)
+ {
+ return /*FLUID_FAILED*/;
+ }
+
+#if ENABLE_MIXER_THREADS
+ {
+ int i;
+
+ for(i = 0; i < handler->thread_count; i++)
+ {
+ if(fluid_mixer_buffers_update_polyphony(&handler->threads[i], value)
+ == FLUID_FAILED)
+ {
+ return /*FLUID_FAILED*/;
+ }
+ }
+ }
#endif
- handler->polyphony = value;
- return FLUID_OK;
+ handler->polyphony = value;
+ return /*FLUID_OK*/;
}
-static void
-fluid_render_loop_singlethread(fluid_rvoice_mixer_t* mixer)
+static void
+fluid_render_loop_singlethread(fluid_rvoice_mixer_t *mixer, int blockcount)
{
- int i;
- FLUID_DECLARE_VLA(fluid_real_t*, bufs,
- mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
- int bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
- fluid_profile_ref_var(prof_ref);
- for (i=0; i < mixer->active_voices; i++) {
- fluid_mixer_buffers_render_one(&mixer->buffers, mixer->rvoices[i], bufs,
- bufcount);
- fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref);
- }
-}
+ int i;
+ FLUID_DECLARE_VLA(fluid_real_t *, bufs,
+ mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
+ int bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
+
+ fluid_real_t *local_buf = fluid_align_ptr(mixer->buffers.local_buf, FLUID_DEFAULT_ALIGNMENT);
+ fluid_profile_ref_var(prof_ref);
+
+ for(i = 0; i < mixer->active_voices; i++)
+ {
+ fluid_mixer_buffers_render_one(&mixer->buffers, mixer->rvoices[i], bufs,
+ bufcount, local_buf, blockcount);
+ fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref, 1,
+ blockcount * FLUID_BUFSIZE);
+ }
+}
static FLUID_INLINE void
-fluid_mixer_buffers_zero(fluid_mixer_buffers_t* buffers)
+fluid_mixer_buffers_zero(fluid_mixer_buffers_t *buffers, int current_blockcount)
{
- int i;
- int size = buffers->mixer->current_blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t);
- /* TODO: Optimize by only zero out the buffers we actually use later on. */
- for (i=0; i < buffers->buf_count; i++) {
- FLUID_MEMSET(buffers->left_buf[i], 0, size);
- FLUID_MEMSET(buffers->right_buf[i], 0, size);
- }
- for (i=0; i < buffers->fx_buf_count; i++) {
- FLUID_MEMSET(buffers->fx_left_buf[i], 0, size);
- FLUID_MEMSET(buffers->fx_right_buf[i], 0, size);
- }
-}
+ int i, size = current_blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t);
+ /* TODO: Optimize by only zero out the buffers we actually use later on. */
+ int buf_count = buffers->buf_count, fx_buf_count = buffers->fx_buf_count;
+ fluid_real_t *FLUID_RESTRICT buf_l = fluid_align_ptr(buffers->left_buf, FLUID_DEFAULT_ALIGNMENT);
+ fluid_real_t *FLUID_RESTRICT buf_r = fluid_align_ptr(buffers->right_buf, FLUID_DEFAULT_ALIGNMENT);
-static int
-fluid_mixer_buffers_init(fluid_mixer_buffers_t* buffers, fluid_rvoice_mixer_t* mixer)
-{
- int i, samplecount;
-
- buffers->mixer = mixer;
- buffers->buf_count = buffers->mixer->buffers.buf_count;
- buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
- buffers->buf_blocks = buffers->mixer->buffers.buf_blocks;
- samplecount = FLUID_BUFSIZE * buffers->buf_blocks;
-
-
- /* Left and right audio buffers */
+ for(i = 0; i < buf_count; i++)
+ {
+ FLUID_MEMSET(&buf_l[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
+ FLUID_MEMSET(&buf_r[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
+ }
+
+ buf_l = fluid_align_ptr(buffers->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+ buf_r = fluid_align_ptr(buffers->fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < fx_buf_count; i++)
+ {
+ FLUID_MEMSET(&buf_l[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
+ FLUID_MEMSET(&buf_r[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
+ }
+}
- buffers->left_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
- buffers->right_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
+static int
+fluid_mixer_buffers_init(fluid_mixer_buffers_t *buffers, fluid_rvoice_mixer_t *mixer)
+{
+ const int samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
- if ((buffers->left_buf == NULL) || (buffers->right_buf == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return 0;
- }
+ buffers->mixer = mixer;
+ buffers->buf_count = mixer->buffers.buf_count;
+ buffers->fx_buf_count = mixer->buffers.fx_buf_count;
- FLUID_MEMSET(buffers->left_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
- FLUID_MEMSET(buffers->right_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
+ /* Local mono voice buf */
+ buffers->local_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, samplecount, FLUID_DEFAULT_ALIGNMENT);
- for (i = 0; i < buffers->buf_count; i++) {
+ /* Left and right audio buffers */
- buffers->left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
- buffers->right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
+ buffers->left_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
+ buffers->right_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
- if ((buffers->left_buf[i] == NULL) || (buffers->right_buf[i] == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return 0;
+ if((buffers->local_buf == NULL) || (buffers->left_buf == NULL) || (buffers->right_buf == NULL))
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return 0;
}
- }
-
- /* Effects audio buffers */
- buffers->fx_left_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
- buffers->fx_right_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
+ /* Effects audio buffers */
- if ((buffers->fx_left_buf == NULL) || (buffers->fx_right_buf == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return 0;
- }
+ buffers->fx_left_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->fx_buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
+ buffers->fx_right_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->fx_buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
- FLUID_MEMSET(buffers->fx_left_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
- FLUID_MEMSET(buffers->fx_right_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
+ if((buffers->fx_left_buf == NULL) || (buffers->fx_right_buf == NULL))
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return 0;
+ }
- for (i = 0; i < buffers->fx_buf_count; i++) {
- buffers->fx_left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
- buffers->fx_right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
+ buffers->finished_voices = NULL;
- if ((buffers->fx_left_buf[i] == NULL) || (buffers->fx_right_buf[i] == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return 0;
+ if(fluid_mixer_buffers_update_polyphony(buffers, mixer->polyphony)
+ == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return 0;
}
- }
-
- buffers->finished_voices = NULL;
- if (fluid_mixer_buffers_update_polyphony(buffers, mixer->polyphony)
- == FLUID_FAILED) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return 0;
- }
-
- return 1;
+
+ return 1;
}
/**
* Note: Not hard real-time capable (calls malloc)
*/
-void
-fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
{
- int i;
- if (mixer->fx.chorus)
- delete_fluid_chorus(mixer->fx.chorus);
- mixer->fx.chorus = new_fluid_chorus(samplerate);
- if (mixer->fx.reverb)
- fluid_revmodel_samplerate_change(mixer->fx.reverb, samplerate);
- for (i=0; i < mixer->active_voices; i++)
- fluid_rvoice_set_output_rate(mixer->rvoices[i], samplerate);
+ fluid_rvoice_mixer_t *mixer = obj;
+ fluid_real_t samplerate = param[1].real; // becausee fluid_synth_update_mixer() puts real into arg2
+
+ int i;
+ for(i = 0; i < mixer->fx_units; i++)
+ {
+ if(mixer->fx[i].chorus)
+ {
+ delete_fluid_chorus(mixer->fx[i].chorus);
+ }
+
+ mixer->fx[i].chorus = new_fluid_chorus(samplerate);
+
+ if(mixer->fx[i].reverb)
+ {
+ fluid_revmodel_samplerate_change(mixer->fx[i].reverb, samplerate);
+ }
+ }
+
+#if LADSPA
+
+ if(mixer->ladspa_fx != NULL)
+ {
+ fluid_ladspa_set_sample_rate(mixer->ladspa_fx, samplerate);
+ }
+
+#endif
}
@@ -530,188 +686,299 @@ fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samp
* @param buf_count number of primary stereo buffers
* @param fx_buf_count number of stereo effect buffers
*/
-fluid_rvoice_mixer_t*
-new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate)
+fluid_rvoice_mixer_t *
+new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, fluid_real_t sample_rate, fluid_rvoice_eventhandler_t *evthandler, int extra_threads, int prio)
{
- fluid_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
- if (mixer == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
- mixer->buffers.buf_count = buf_count;
- mixer->buffers.fx_buf_count = fx_buf_count;
- mixer->buffers.buf_blocks = FLUID_MIXER_MAX_BUFFERS_DEFAULT;
-
- /* allocate the reverb module */
- mixer->fx.reverb = new_fluid_revmodel(sample_rate);
- mixer->fx.chorus = new_fluid_chorus(sample_rate);
- if (mixer->fx.reverb == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- delete_fluid_rvoice_mixer(mixer);
- return NULL;
- }
-
- if (!fluid_mixer_buffers_init(&mixer->buffers, mixer)) {
- delete_fluid_rvoice_mixer(mixer);
- return NULL;
- }
-
-#ifdef ENABLE_MIXER_THREADS
- mixer->thread_ready = new_fluid_cond();
- mixer->wakeup_threads = new_fluid_cond();
- mixer->thread_ready_m = new_fluid_cond_mutex();
- mixer->wakeup_threads_m = new_fluid_cond_mutex();
- if (!mixer->thread_ready || !mixer->wakeup_threads ||
- !mixer->thread_ready_m || !mixer->wakeup_threads_m) {
+ int i;
+ fluid_rvoice_mixer_t *mixer = FLUID_NEW(fluid_rvoice_mixer_t);
+
+ if(mixer == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
+ mixer->eventhandler = evthandler;
+ mixer->fx_units = fx_units;
+ mixer->buffers.buf_count = buf_count;
+ mixer->buffers.fx_buf_count = fx_buf_count * fx_units;
+
+ /* allocate the reverb module */
+ mixer->fx = FLUID_ARRAY(fluid_mixer_fx_t, fx_units);
+ if(mixer->fx == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+
+ FLUID_MEMSET(mixer->fx, 0, fx_units * sizeof(*mixer->fx));
+
+ for(i = 0; i < fx_units; i++)
+ {
+ mixer->fx[i].reverb = new_fluid_revmodel(sample_rate);
+ mixer->fx[i].chorus = new_fluid_chorus(sample_rate);
+
+ if(mixer->fx[i].reverb == NULL || mixer->fx[i].chorus == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+ }
+
+ if(!fluid_mixer_buffers_init(&mixer->buffers, mixer))
+ {
+ goto error_recovery;
+ }
+
+#if ENABLE_MIXER_THREADS
+ mixer->thread_ready = new_fluid_cond();
+ mixer->wakeup_threads = new_fluid_cond();
+ mixer->thread_ready_m = new_fluid_cond_mutex();
+ mixer->wakeup_threads_m = new_fluid_cond_mutex();
+
+ if(!mixer->thread_ready || !mixer->wakeup_threads ||
+ !mixer->thread_ready_m || !mixer->wakeup_threads_m)
+ {
+ goto error_recovery;
+ }
+
+ if(fluid_rvoice_mixer_set_threads(mixer, extra_threads, prio) != FLUID_OK)
+ {
+ goto error_recovery;
+ }
+
+#endif
+
+ return mixer;
+
+error_recovery:
delete_fluid_rvoice_mixer(mixer);
return NULL;
- }
-#endif
-
- return mixer;
}
static void
-fluid_mixer_buffers_free(fluid_mixer_buffers_t* buffers)
-{
- int i;
-
- FLUID_FREE(buffers->finished_voices);
-
- /* free all the sample buffers */
- if (buffers->left_buf != NULL) {
- for (i = 0; i < buffers->buf_count; i++) {
- if (buffers->left_buf[i] != NULL) {
- FLUID_FREE(buffers->left_buf[i]);
- }
- }
+fluid_mixer_buffers_free(fluid_mixer_buffers_t *buffers)
+{
+ FLUID_FREE(buffers->finished_voices);
+
+ /* free all the sample buffers */
+ FLUID_FREE(buffers->local_buf);
FLUID_FREE(buffers->left_buf);
- }
+ FLUID_FREE(buffers->right_buf);
+ FLUID_FREE(buffers->fx_left_buf);
+ FLUID_FREE(buffers->fx_right_buf);
+}
+
+void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer)
+{
+ int i;
+
+ fluid_return_if_fail(mixer != NULL);
- if (buffers->right_buf != NULL) {
- for (i = 0; i < buffers->buf_count; i++) {
- if (buffers->right_buf[i] != NULL) {
- FLUID_FREE(buffers->right_buf[i]);
- }
+#if ENABLE_MIXER_THREADS
+ delete_rvoice_mixer_threads(mixer);
+
+ if(mixer->thread_ready)
+ {
+ delete_fluid_cond(mixer->thread_ready);
}
- FLUID_FREE(buffers->right_buf);
- }
- if (buffers->fx_left_buf != NULL) {
- for (i = 0; i < buffers->fx_buf_count; i++) {
- if (buffers->fx_left_buf[i] != NULL) {
- FLUID_FREE(buffers->fx_left_buf[i]);
- }
+ if(mixer->wakeup_threads)
+ {
+ delete_fluid_cond(mixer->wakeup_threads);
}
- FLUID_FREE(buffers->fx_left_buf);
- }
- if (buffers->fx_right_buf != NULL) {
- for (i = 0; i < buffers->fx_buf_count; i++) {
- if (buffers->fx_right_buf[i] != NULL) {
- FLUID_FREE(buffers->fx_right_buf[i]);
- }
+ if(mixer->thread_ready_m)
+ {
+ delete_fluid_cond_mutex(mixer->thread_ready_m);
+ }
+
+ if(mixer->wakeup_threads_m)
+ {
+ delete_fluid_cond_mutex(mixer->wakeup_threads_m);
}
- FLUID_FREE(buffers->fx_right_buf);
- }
-}
-void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t* mixer)
-{
- if (!mixer)
- return;
- fluid_rvoice_mixer_set_threads(mixer, 0, 0);
-#ifdef ENABLE_MIXER_THREADS
- if (mixer->thread_ready)
- delete_fluid_cond(mixer->thread_ready);
- if (mixer->wakeup_threads)
- delete_fluid_cond(mixer->wakeup_threads);
- if (mixer->thread_ready_m)
- delete_fluid_cond_mutex(mixer->thread_ready_m);
- if (mixer->wakeup_threads_m)
- delete_fluid_cond_mutex(mixer->wakeup_threads_m);
#endif
- fluid_mixer_buffers_free(&mixer->buffers);
- if (mixer->fx.reverb)
- delete_fluid_revmodel(mixer->fx.reverb);
- if (mixer->fx.chorus)
- delete_fluid_chorus(mixer->fx.chorus);
- FLUID_FREE(mixer->rvoices);
- FLUID_FREE(mixer);
+ fluid_mixer_buffers_free(&mixer->buffers);
+
+
+ for(i = 0; i < mixer->fx_units; i++)
+ {
+ if(mixer->fx[i].reverb)
+ {
+ delete_fluid_revmodel(mixer->fx[i].reverb);
+ }
+
+ if(mixer->fx[i].chorus)
+ {
+ delete_fluid_chorus(mixer->fx[i].chorus);
+ }
+ }
+
+ FLUID_FREE(mixer->fx);
+ FLUID_FREE(mixer->rvoices);
+ FLUID_FREE(mixer);
}
-#ifdef LADSPA
-void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
- fluid_LADSPA_FxUnit_t* ladspa)
+#ifdef LADSPA
+/**
+ * Set a LADSPS fx instance to be used by the mixer and assign the mixer buffers
+ * as LADSPA host buffers with sensible names */
+void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer,
+ fluid_ladspa_fx_t *ladspa_fx, int audio_groups)
{
- mixer->LADSPA_FxUnit = ladspa;
+ mixer->ladspa_fx = ladspa_fx;
+
+ if(ladspa_fx == NULL)
+ {
+ return;
+ }
+ else
+ {
+ fluid_real_t *main_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
+ fluid_real_t *main_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ fluid_real_t *rev = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+ fluid_real_t *chor = rev;
+
+ rev = &rev[SYNTH_REVERB_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
+ chor = &chor[SYNTH_CHORUS_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
+
+ fluid_ladspa_add_host_ports(ladspa_fx, "Main:L", audio_groups,
+ main_l,
+ FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
+
+ fluid_ladspa_add_host_ports(ladspa_fx, "Main:R", audio_groups,
+ main_r,
+ FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
+
+ fluid_ladspa_add_host_ports(ladspa_fx, "Reverb:Send", 1,
+ rev,
+ FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
+
+ fluid_ladspa_add_host_ports(ladspa_fx, "Chorus:Send", 1,
+ chor,
+ FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
+ }
}
#endif
-void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled)
{
- mixer->fx.with_reverb = on;
+ fluid_rvoice_mixer_t *mixer = obj;
+ int on = param[0].i;
+
+ mixer->with_reverb = on;
}
-void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled)
{
- mixer->fx.with_chorus = on;
+ fluid_rvoice_mixer_t *mixer = obj;
+ int on = param[0].i;
+ mixer->with_chorus = on;
}
-void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on)
+void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on)
{
- mixer->fx.mix_fx_to_out = on;
+ mixer->mix_fx_to_out = on;
}
-void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
- int nr, double level, double speed,
- double depth_ms, int type)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params)
{
- fluid_chorus_set(mixer->fx.chorus, set, nr, level, speed, depth_ms, type);
+ fluid_rvoice_mixer_t *mixer = obj;
+ int set = param[0].i;
+ int nr = param[1].i;
+ fluid_real_t level = param[2].real;
+ fluid_real_t speed = param[3].real;
+ fluid_real_t depth_ms = param[4].real;
+ int type = param[5].i;
+
+ int i;
+ for(i = 0; i < mixer->fx_units; i++)
+ {
+ fluid_chorus_set(mixer->fx[i].chorus, set, nr, level, speed, depth_ms, type);
+ }
}
-void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
- double roomsize, double damping,
- double width, double level)
+
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params)
{
- fluid_revmodel_set(mixer->fx.reverb, set, roomsize, damping, width, level);
+ fluid_rvoice_mixer_t *mixer = obj;
+ int set = param[0].i;
+ fluid_real_t roomsize = param[1].real;
+ fluid_real_t damping = param[2].real;
+ fluid_real_t width = param[3].real;
+ fluid_real_t level = param[4].real;
+
+ int i;
+ for(i = 0; i < mixer->fx_units; i++)
+ {
+ fluid_revmodel_set(mixer->fx[i].reverb, set, roomsize, damping, width, level);
+ }
}
-void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer)
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb)
{
- fluid_revmodel_reset(mixer->fx.reverb);
- fluid_chorus_reset(mixer->fx.chorus);
+ fluid_rvoice_mixer_t *mixer = obj;
+ int i;
+ for(i = 0; i < mixer->fx_units; i++)
+ {
+ fluid_revmodel_reset(mixer->fx[i].reverb);
+ }
+}
+
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus)
+{
+ fluid_rvoice_mixer_t *mixer = obj;
+ int i;
+ for(i = 0; i < mixer->fx_units; i++)
+ {
+ fluid_chorus_reset(mixer->fx[i].chorus);
+ }
}
-void fluid_rvoice_mixer_reset_reverb(fluid_rvoice_mixer_t* mixer)
+int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t *mixer,
+ fluid_real_t **left, fluid_real_t **right)
{
- fluid_revmodel_reset(mixer->fx.reverb);
+ *left = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
+ *right = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
+ return mixer->buffers.buf_count;
}
-void fluid_rvoice_mixer_reset_chorus(fluid_rvoice_mixer_t* mixer)
+int fluid_rvoice_mixer_get_fx_bufs(fluid_rvoice_mixer_t *mixer,
+ fluid_real_t **fx_left, fluid_real_t **fx_right)
{
- fluid_chorus_reset(mixer->fx.chorus);
+ *fx_left = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+ *fx_right = fluid_align_ptr(mixer->buffers.fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
+ return mixer->buffers.fx_buf_count;
}
-int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
- fluid_real_t*** left, fluid_real_t*** right)
+int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer)
{
- *left = mixer->buffers.left_buf;
- *right = mixer->buffers.right_buf;
- return mixer->buffers.buf_count;
+ return FLUID_MIXER_MAX_BUFFERS_DEFAULT;
}
+#if WITH_PROFILING
+int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer)
+{
+ return mixer->active_voices;
+}
+#endif
-#ifdef ENABLE_MIXER_THREADS
+#if ENABLE_MIXER_THREADS
-static FLUID_INLINE fluid_rvoice_t*
-fluid_mixer_get_mt_rvoice(fluid_rvoice_mixer_t* mixer)
+static FLUID_INLINE fluid_rvoice_t *
+fluid_mixer_get_mt_rvoice(fluid_rvoice_mixer_t *mixer)
{
- int i = fluid_atomic_int_exchange_and_add(&mixer->current_rvoice, 1);
- if (i >= mixer->active_voices)
- return NULL;
- return mixer->rvoices[i];
+ int i = fluid_atomic_int_exchange_and_add(&mixer->current_rvoice, 1);
+
+ if(i >= mixer->active_voices)
+ {
+ return NULL;
+ }
+
+ return mixer->rvoices[i];
}
#define THREAD_BUF_PROCESSING 0
@@ -720,255 +987,391 @@ fluid_mixer_get_mt_rvoice(fluid_rvoice_mixer_t* mixer)
#define THREAD_BUF_TERMINATE 3
/* Core thread function (processes voices in parallel to primary synthesis thread) */
-static void
-fluid_mixer_thread_func (void* data)
-{
- fluid_mixer_buffers_t* buffers = data;
- fluid_rvoice_mixer_t* mixer = buffers->mixer;
- int hasValidData = 0;
- FLUID_DECLARE_VLA(fluid_real_t*, bufs, buffers->buf_count*2 + buffers->fx_buf_count*2);
- int bufcount = 0;
-
- while (!fluid_atomic_int_get(&mixer->threads_should_terminate)) {
- fluid_rvoice_t* rvoice = fluid_mixer_get_mt_rvoice(mixer);
- if (rvoice == NULL) {
- // if no voices: signal rendered buffers, sleep
- fluid_atomic_int_set(&buffers->ready, hasValidData ? THREAD_BUF_VALID : THREAD_BUF_NODATA);
- fluid_cond_mutex_lock(mixer->thread_ready_m);
- fluid_cond_signal(mixer->thread_ready);
- fluid_cond_mutex_unlock(mixer->thread_ready_m);
-
- fluid_cond_mutex_lock(mixer->wakeup_threads_m);
- while (1) {
- int j = fluid_atomic_int_get(&buffers->ready);
- if (j == THREAD_BUF_PROCESSING || j == THREAD_BUF_TERMINATE)
- break;
- fluid_cond_wait(mixer->wakeup_threads, mixer->wakeup_threads_m);
- }
- fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
-
- hasValidData = 0;
- }
- else {
- // else: if buffer is not zeroed, zero buffers
- if (!hasValidData) {
- fluid_mixer_buffers_zero(buffers);
- bufcount = fluid_mixer_buffers_prepare(buffers, bufs);
- hasValidData = 1;
- }
- // then render voice to buffers
- fluid_mixer_buffers_render_one(buffers, rvoice, bufs, bufcount);
- }
- }
+static fluid_thread_return_t
+fluid_mixer_thread_func(void *data)
+{
+ fluid_mixer_buffers_t *buffers = data;
+ fluid_rvoice_mixer_t *mixer = buffers->mixer;
+ int hasValidData = 0;
+ FLUID_DECLARE_VLA(fluid_real_t *, bufs, buffers->buf_count * 2 + buffers->fx_buf_count * 2);
+ int bufcount = 0;
+ int current_blockcount = 0;
+ fluid_real_t *local_buf = fluid_align_ptr(buffers->local_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ while(!fluid_atomic_int_get(&mixer->threads_should_terminate))
+ {
+ fluid_rvoice_t *rvoice = fluid_mixer_get_mt_rvoice(mixer);
+
+ if(rvoice == NULL)
+ {
+ // if no voices: signal rendered buffers, sleep
+ fluid_atomic_int_set(&buffers->ready, hasValidData ? THREAD_BUF_VALID : THREAD_BUF_NODATA);
+ fluid_cond_mutex_lock(mixer->thread_ready_m);
+ fluid_cond_signal(mixer->thread_ready);
+ fluid_cond_mutex_unlock(mixer->thread_ready_m);
+
+ fluid_cond_mutex_lock(mixer->wakeup_threads_m);
+
+ while(1)
+ {
+ int j = fluid_atomic_int_get(&buffers->ready);
+
+ if(j == THREAD_BUF_PROCESSING || j == THREAD_BUF_TERMINATE)
+ {
+ break;
+ }
+
+ fluid_cond_wait(mixer->wakeup_threads, mixer->wakeup_threads_m);
+ }
+
+ fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
+
+ hasValidData = 0;
+ }
+ else
+ {
+ // else: if buffer is not zeroed, zero buffers
+ if(!hasValidData)
+ {
+ // blockcount may have changed, since thread was put to sleep
+ current_blockcount = mixer->current_blockcount;
+ fluid_mixer_buffers_zero(buffers, current_blockcount);
+ bufcount = fluid_mixer_buffers_prepare(buffers, bufs);
+ hasValidData = 1;
+ }
+
+ // then render voice to buffers
+ fluid_mixer_buffers_render_one(buffers, rvoice, bufs, bufcount, local_buf, current_blockcount);
+ }
+ }
+ return FLUID_THREAD_RETURN_VALUE;
}
static void
-fluid_mixer_buffers_mix(fluid_mixer_buffers_t* dest, fluid_mixer_buffers_t* src)
+fluid_mixer_buffers_mix(fluid_mixer_buffers_t *dst, fluid_mixer_buffers_t *src, int current_blockcount)
{
- int i,j;
- int scount = dest->mixer->current_blockcount * FLUID_BUFSIZE;
- int minbuf;
-
- minbuf = dest->buf_count;
- if (minbuf > src->buf_count)
- minbuf = src->buf_count;
- for (i=0; i < minbuf; i++) {
- for (j=0; j < scount; j++) {
- dest->left_buf[i][j] += src->left_buf[i][j];
- dest->right_buf[i][j] += src->right_buf[i][j];
+ int i, j;
+ int scount = current_blockcount * FLUID_BUFSIZE;
+ int minbuf;
+ fluid_real_t *FLUID_RESTRICT base_src;
+ fluid_real_t *FLUID_RESTRICT base_dst;
+
+ minbuf = dst->buf_count;
+
+ if(minbuf > src->buf_count)
+ {
+ minbuf = src->buf_count;
+ }
+
+ base_src = fluid_align_ptr(src->left_buf, FLUID_DEFAULT_ALIGNMENT);
+ base_dst = fluid_align_ptr(dst->left_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < minbuf; i++)
+ {
+ #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
+
+ for(j = 0; j < scount; j++)
+ {
+ int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
+ base_dst[dsp_i] += base_src[dsp_i];
+ }
+ }
+
+ base_src = fluid_align_ptr(src->right_buf, FLUID_DEFAULT_ALIGNMENT);
+ base_dst = fluid_align_ptr(dst->right_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < minbuf; i++)
+ {
+ #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
+
+ for(j = 0; j < scount; j++)
+ {
+ int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
+ base_dst[dsp_i] += base_src[dsp_i];
+ }
}
- }
- minbuf = dest->fx_buf_count;
- if (minbuf > src->fx_buf_count)
- minbuf = src->fx_buf_count;
- for (i=0; i < minbuf; i++) {
- for (j=0; j < scount; j++) {
- dest->fx_left_buf[i][j] += src->fx_left_buf[i][j];
- dest->fx_right_buf[i][j] += src->fx_right_buf[i][j];
+ minbuf = dst->fx_buf_count;
+
+ if(minbuf > src->fx_buf_count)
+ {
+ minbuf = src->fx_buf_count;
+ }
+
+ base_src = fluid_align_ptr(src->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+ base_dst = fluid_align_ptr(dst->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < minbuf; i++)
+ {
+ #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
+
+ for(j = 0; j < scount; j++)
+ {
+ int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
+ base_dst[dsp_i] += base_src[dsp_i];
+ }
+ }
+
+ base_src = fluid_align_ptr(src->fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
+ base_dst = fluid_align_ptr(dst->fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
+
+ for(i = 0; i < minbuf; i++)
+ {
+ #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
+
+ for(j = 0; j < scount; j++)
+ {
+ int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
+ base_dst[dsp_i] += base_src[dsp_i];
+ }
}
- }
}
/**
- * Go through all threads and see if someone is finished for mixing
+ * Go through all threads and see if someone is finished for mixing
*/
-static FLUID_INLINE int
-fluid_mixer_mix_in(fluid_rvoice_mixer_t* mixer, int extra_threads)
-{
- int i, result, hasmixed;
- do {
- hasmixed = 0;
- result = 0;
- for (i=0; i < extra_threads; i++) {
- int j = fluid_atomic_int_get(&mixer->threads[i].ready);
- switch (j) {
- case THREAD_BUF_PROCESSING:
- result = 1;
- break;
- case THREAD_BUF_VALID:
- fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_NODATA);
- fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i]);
- hasmixed = 1;
- break;
- }
- }
- } while (hasmixed);
- return result;
-}
-
-static void
-fluid_render_loop_multithread(fluid_rvoice_mixer_t* mixer)
-{
- int i, bufcount;
- //int scount = mixer->current_blockcount * FLUID_BUFSIZE;
- FLUID_DECLARE_VLA(fluid_real_t*, bufs,
- mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
- // How many threads should we start this time?
- int extra_threads = mixer->active_voices / VOICES_PER_THREAD;
- if (extra_threads > mixer->thread_count)
- extra_threads = mixer->thread_count;
- if (extra_threads == 0) {
- // No extra threads? No thread overhead!
- fluid_render_loop_singlethread(mixer);
- return;
- }
-
- bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
-
- // Prepare voice list
- fluid_cond_mutex_lock(mixer->wakeup_threads_m);
- fluid_atomic_int_set(&mixer->current_rvoice, 0);
- for (i=0; i < extra_threads; i++)
- fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_PROCESSING);
- // Signal threads to wake up
- fluid_cond_broadcast(mixer->wakeup_threads);
- fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
-
- // If thread is finished, mix it in
- while (fluid_mixer_mix_in(mixer, extra_threads)) {
- // Otherwise get a voice and render it
- fluid_rvoice_t* rvoice = fluid_mixer_get_mt_rvoice(mixer);
- if (rvoice != NULL) {
- fluid_profile_ref_var(prof_ref);
- fluid_mixer_buffers_render_one(&mixer->buffers, rvoice, bufs, bufcount);
- fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref);
- //test++;
- }
- else {
- // If no voices, wait for mixes. Make sure one is still processing to avoid deadlock
- int is_processing = 0;
- //waits++;
- fluid_cond_mutex_lock(mixer->thread_ready_m);
- for (i=0; i < extra_threads; i++)
- if (fluid_atomic_int_get(&mixer->threads[i].ready) ==
- THREAD_BUF_PROCESSING)
- is_processing = 1;
- if (is_processing)
- fluid_cond_wait(mixer->thread_ready, mixer->thread_ready_m);
- fluid_cond_mutex_unlock(mixer->thread_ready_m);
- }
- }
- //FLUID_LOG(FLUID_DBG, "Blockcount: %d, mixed %d of %d voices myself, waits = %d",
- // mixer->current_blockcount, test, mixer->active_voices, waits);
+static int
+fluid_mixer_mix_in(fluid_rvoice_mixer_t *mixer, int extra_threads, int current_blockcount)
+{
+ int i, result, hasmixed;
+
+ do
+ {
+ hasmixed = 0;
+ result = 0;
+
+ for(i = 0; i < extra_threads; i++)
+ {
+ int j = fluid_atomic_int_get(&mixer->threads[i].ready);
+
+ switch(j)
+ {
+ case THREAD_BUF_PROCESSING:
+ result = 1;
+ break;
+
+ case THREAD_BUF_VALID:
+ fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_NODATA);
+ fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i], current_blockcount);
+ hasmixed = 1;
+ break;
+ }
+ }
+ }
+ while(hasmixed);
+
+ return result;
}
-#endif
+static void
+fluid_render_loop_multithread(fluid_rvoice_mixer_t *mixer, int current_blockcount)
+{
+ int i, bufcount;
+ fluid_real_t *local_buf = fluid_align_ptr(mixer->buffers.local_buf, FLUID_DEFAULT_ALIGNMENT);
-/**
- * Update amount of extra mixer threads.
- * @param thread_count Number of extra mixer threads for multi-core rendering
- * @param prio_level real-time prio level for the extra mixer threads
- */
-void
-fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count,
- int prio_level)
-{
-#ifdef ENABLE_MIXER_THREADS
- char name[16];
- int i;
-
- // Kill all existing threads first
- if (mixer->thread_count) {
+ FLUID_DECLARE_VLA(fluid_real_t *, bufs,
+ mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
+ // How many threads should we start this time?
+ int extra_threads = mixer->active_voices / VOICES_PER_THREAD;
+
+ if(extra_threads > mixer->thread_count)
+ {
+ extra_threads = mixer->thread_count;
+ }
+
+ if(extra_threads == 0)
+ {
+ // No extra threads? No thread overhead!
+ fluid_render_loop_singlethread(mixer, current_blockcount);
+ return;
+ }
+
+ bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
+
+ // Prepare voice list
+ fluid_cond_mutex_lock(mixer->wakeup_threads_m);
+ fluid_atomic_int_set(&mixer->current_rvoice, 0);
+
+ for(i = 0; i < extra_threads; i++)
+ {
+ fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_PROCESSING);
+ }
+
+ // Signal threads to wake up
+ fluid_cond_broadcast(mixer->wakeup_threads);
+ fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
+
+ // If thread is finished, mix it in
+ while(fluid_mixer_mix_in(mixer, extra_threads, current_blockcount))
+ {
+ // Otherwise get a voice and render it
+ fluid_rvoice_t *rvoice = fluid_mixer_get_mt_rvoice(mixer);
+
+ if(rvoice != NULL)
+ {
+ fluid_profile_ref_var(prof_ref);
+ fluid_mixer_buffers_render_one(&mixer->buffers, rvoice, bufs, bufcount, local_buf, current_blockcount);
+ fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref, 1,
+ current_blockcount * FLUID_BUFSIZE);
+ //test++;
+ }
+ else
+ {
+ // If no voices, wait for mixes. Make sure one is still processing to avoid deadlock
+ int is_processing = 0;
+ //waits++;
+ fluid_cond_mutex_lock(mixer->thread_ready_m);
+
+ for(i = 0; i < extra_threads; i++)
+ {
+ if(fluid_atomic_int_get(&mixer->threads[i].ready) ==
+ THREAD_BUF_PROCESSING)
+ {
+ is_processing = 1;
+ }
+ }
+
+ if(is_processing)
+ {
+ fluid_cond_wait(mixer->thread_ready, mixer->thread_ready_m);
+ }
+
+ fluid_cond_mutex_unlock(mixer->thread_ready_m);
+ }
+ }
+
+ //FLUID_LOG(FLUID_DBG, "Blockcount: %d, mixed %d of %d voices myself, waits = %d",
+ // current_blockcount, test, mixer->active_voices, waits);
+}
+
+static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t *mixer)
+{
+ int i;
fluid_atomic_int_set(&mixer->threads_should_terminate, 1);
// Signal threads to wake up
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
- for (i=0; i < mixer->thread_count; i++)
- fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE);
+
+ for(i = 0; i < mixer->thread_count; i++)
+ {
+ fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE);
+ }
+
fluid_cond_broadcast(mixer->wakeup_threads);
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
-
- for (i=0; i < mixer->thread_count; i++) {
- if (mixer->threads[i].thread) {
- fluid_thread_join(mixer->threads[i].thread);
- delete_fluid_thread(mixer->threads[i].thread);
- }
- fluid_mixer_buffers_free(&mixer->threads[i]);
+
+ for(i = 0; i < mixer->thread_count; i++)
+ {
+ if(mixer->threads[i].thread)
+ {
+ fluid_thread_join(mixer->threads[i].thread);
+ delete_fluid_thread(mixer->threads[i].thread);
+ }
+
+ fluid_mixer_buffers_free(&mixer->threads[i]);
}
+
FLUID_FREE(mixer->threads);
mixer->thread_count = 0;
mixer->threads = NULL;
- }
-
- if (thread_count == 0)
- return;
-
- // Now prepare the new threads
- fluid_atomic_int_set(&mixer->threads_should_terminate, 0);
- mixer->threads = FLUID_ARRAY(fluid_mixer_buffers_t, thread_count);
- if (mixer->threads == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return;
- }
- FLUID_MEMSET(mixer->threads, 0, thread_count*sizeof(fluid_mixer_buffers_t));
- mixer->thread_count = thread_count;
- for (i=0; i < thread_count; i++) {
- fluid_mixer_buffers_t* b = &mixer->threads[i];
- if (!fluid_mixer_buffers_init(b, mixer))
- return;
- fluid_atomic_int_set(&b->ready, THREAD_BUF_NODATA);
- g_snprintf (name, sizeof (name), "mixer%d", i);
- b->thread = new_fluid_thread(name, fluid_mixer_thread_func, b, prio_level, 0);
- if (!b->thread)
- return;
- }
+}
-#endif
+/**
+ * Update amount of extra mixer threads.
+ * @param thread_count Number of extra mixer threads for multi-core rendering
+ * @param prio_level real-time prio level for the extra mixer threads
+ */
+static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t *mixer, int thread_count, int prio_level)
+{
+ char name[16];
+ int i;
+
+ // Kill all existing threads first
+ if(mixer->thread_count)
+ {
+ delete_rvoice_mixer_threads(mixer);
+ }
+
+ if(thread_count == 0)
+ {
+ return FLUID_OK;
+ }
+
+ // Now prepare the new threads
+ fluid_atomic_int_set(&mixer->threads_should_terminate, 0);
+ mixer->threads = FLUID_ARRAY(fluid_mixer_buffers_t, thread_count);
+
+ if(mixer->threads == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FLUID_FAILED;
+ }
+
+ FLUID_MEMSET(mixer->threads, 0, thread_count * sizeof(fluid_mixer_buffers_t));
+ mixer->thread_count = thread_count;
+
+ for(i = 0; i < thread_count; i++)
+ {
+ fluid_mixer_buffers_t *b = &mixer->threads[i];
+
+ if(!fluid_mixer_buffers_init(b, mixer))
+ {
+ return FLUID_FAILED;
+ }
+
+ fluid_atomic_int_set(&b->ready, THREAD_BUF_NODATA);
+ FLUID_SNPRINTF(name, sizeof(name), "mixer%d", i);
+ b->thread = new_fluid_thread(name, fluid_mixer_thread_func, b, prio_level, 0);
+
+ if(!b->thread)
+ {
+ return FLUID_FAILED;
+ }
+ }
+
+ return FLUID_OK;
}
+#endif
/**
* Synthesize audio into buffers
- * @param blockcount number of blocks to render, each having FLUID_BUFSIZE samples
+ * @param blockcount number of blocks to render, each having FLUID_BUFSIZE samples
* @return number of blocks rendered
*/
-int
-fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
-{
- fluid_profile_ref_var(prof_ref);
-
- mixer->current_blockcount = blockcount > mixer->buffers.buf_blocks ?
- mixer->buffers.buf_blocks : blockcount;
-
- // Zero buffers
- fluid_mixer_buffers_zero(&mixer->buffers);
- fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref);
-
-#ifdef ENABLE_MIXER_THREADS
- if (mixer->thread_count > 0)
- fluid_render_loop_multithread(mixer);
- else
+int
+fluid_rvoice_mixer_render(fluid_rvoice_mixer_t *mixer, int blockcount)
+{
+ fluid_profile_ref_var(prof_ref);
+
+ mixer->current_blockcount = blockcount;
+
+ // Zero buffers
+ fluid_mixer_buffers_zero(&mixer->buffers, blockcount);
+ fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref, mixer->active_voices,
+ blockcount * FLUID_BUFSIZE);
+
+#if ENABLE_MIXER_THREADS
+
+ if(mixer->thread_count > 0)
+ {
+ fluid_render_loop_multithread(mixer, blockcount);
+ }
+ else
#endif
- fluid_render_loop_singlethread(mixer);
- fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref);
-
+ {
+ fluid_render_loop_singlethread(mixer, blockcount);
+ }
+
+ fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref, mixer->active_voices,
+ blockcount * FLUID_BUFSIZE);
+
- // Process reverb & chorus
- fluid_rvoice_mixer_process_fx(mixer);
+ // Process reverb & chorus
+ fluid_rvoice_mixer_process_fx(mixer, blockcount);
- // Call the callback and pack active voice array
- fluid_rvoice_mixer_process_finished_voices(mixer);
+ // Call the callback and pack active voice array
+ fluid_rvoice_mixer_process_finished_voices(mixer);
- return mixer->current_blockcount;
+ return blockcount;
}
diff --git a/libs/fluidsynth/src/fluid_rvoice_mixer.h b/libs/fluidsynth/src/fluid_rvoice_mixer.h
index d4e41ca0a8..1b3fceb342 100644
--- a/libs/fluidsynth/src/fluid_rvoice_mixer.h
+++ b/libs/fluidsynth/src/fluid_rvoice_mixer.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -24,50 +24,41 @@
#include "fluidsynth_priv.h"
#include "fluid_rvoice.h"
-//#include "fluid_ladspa.h"
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
-#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE)
-
+int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t *mixer, int blockcount);
+int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t *mixer,
+ fluid_real_t **left, fluid_real_t **right);
+int fluid_rvoice_mixer_get_fx_bufs(fluid_rvoice_mixer_t *mixer,
+ fluid_real_t **fx_left, fluid_real_t **fx_right);
+int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer);
+#if WITH_PROFILING
+int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer);
+#endif
+fluid_rvoice_mixer_t *new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units,
+ fluid_real_t sample_rate, fluid_rvoice_eventhandler_t *, int, int);
-void fluid_rvoice_mixer_set_finished_voices_callback(
- fluid_rvoice_mixer_t* mixer,
- void (*func)(void*, fluid_rvoice_t*),
- void* userdata);
+void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *);
-int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount);
-int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
- fluid_real_t*** left, fluid_real_t*** right);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params);
-fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count,
- fluid_real_t sample_rate);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb);
+DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus);
-void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
-void fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate);
-void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on);
-void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on);
-void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on);
-int fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value);
-int fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice);
-void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
- int nr, double level, double speed,
- double depth_ms, int type);
-void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
- double roomsize, double damping,
- double width, double level);
-void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer);
-void fluid_rvoice_mixer_reset_reverb(fluid_rvoice_mixer_t* mixer);
-void fluid_rvoice_mixer_reset_chorus(fluid_rvoice_mixer_t* mixer);
-void fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count,
- int prio_level);
-
-#ifdef LADSPA
-void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
- fluid_LADSPA_FxUnit_t* ladspa);
+void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on);
+#ifdef LADSPA
+void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer,
+ fluid_ladspa_fx_t *ladspa_fx, int audio_groups);
#endif
#endif
diff --git a/libs/fluidsynth/src/fluid_samplecache.c b/libs/fluidsynth/src/fluid_samplecache.c
new file mode 100644
index 0000000000..773e19feea
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_samplecache.c
@@ -0,0 +1,295 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * SoundFont file loading code borrowed from Smurf SoundFont Editor
+ * Copyright (C) 1999-2001 Josh Green
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/* CACHED SAMPLE DATA LOADER
+ *
+ * This is a wrapper around fluid_sffile_read_sample_data that attempts to cache the read
+ * data across all FluidSynth instances in a global (process-wide) list.
+ */
+
+#include "fluid_samplecache.h"
+#include "fluid_sys.h"
+#include "fluidsynth.h"
+#include "fluid_list.h"
+
+
+typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t;
+
+struct _fluid_samplecache_entry_t
+{
+ /* The follwing members all form the cache key */
+ char *filename;
+ time_t modification_time;
+ unsigned int sf_samplepos;
+ unsigned int sf_samplesize;
+ unsigned int sf_sample24pos;
+ unsigned int sf_sample24size;
+ unsigned int sample_start;
+ unsigned int sample_end;
+ int sample_type;
+ /* End of cache key members */
+
+ short *sample_data;
+ char *sample_data24;
+ int sample_count;
+
+ int num_references;
+ int mlocked;
+};
+
+static fluid_list_t *samplecache_list = NULL;
+static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT;
+
+static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
+static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
+static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
+
+static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
+
+
+/* PUBLIC INTERFACE */
+
+int fluid_samplecache_load(SFData *sf,
+ unsigned int sample_start, unsigned int sample_end, int sample_type,
+ int try_mlock, short **sample_data, char **sample_data24)
+{
+ fluid_samplecache_entry_t *entry;
+ int ret;
+
+ fluid_mutex_lock(samplecache_mutex);
+
+ entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type);
+
+ if(entry == NULL)
+ {
+ entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type);
+
+ if(entry == NULL)
+ {
+ ret = -1;
+ goto unlock_exit;
+ }
+
+ samplecache_list = fluid_list_prepend(samplecache_list, entry);
+ }
+
+ if(try_mlock && !entry->mlocked)
+ {
+ /* Lock the memory to disable paging. It's okay if this fails. It
+ * probably means that the user doesn't have the required permission. */
+ if(fluid_mlock(entry->sample_data, entry->sample_count * sizeof(short)) == 0)
+ {
+ if(entry->sample_data24 != NULL)
+ {
+ entry->mlocked = (fluid_mlock(entry->sample_data24, entry->sample_count) == 0);
+ }
+ else
+ {
+ entry->mlocked = TRUE;
+ }
+
+ if(!entry->mlocked)
+ {
+ fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
+ FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
+ }
+ }
+ }
+
+ entry->num_references++;
+ *sample_data = entry->sample_data;
+ *sample_data24 = entry->sample_data24;
+ ret = entry->sample_count;
+
+unlock_exit:
+ fluid_mutex_unlock(samplecache_mutex);
+ return ret;
+}
+
+int fluid_samplecache_unload(const short *sample_data)
+{
+ fluid_list_t *entry_list;
+ fluid_samplecache_entry_t *entry;
+ int ret;
+
+ fluid_mutex_lock(samplecache_mutex);
+
+ entry_list = samplecache_list;
+
+ while(entry_list)
+ {
+ entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
+
+ if(sample_data == entry->sample_data)
+ {
+ entry->num_references--;
+
+ if(entry->num_references == 0)
+ {
+ if(entry->mlocked)
+ {
+ fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
+
+ if(entry->sample_data24 != NULL)
+ {
+ fluid_munlock(entry->sample_data24, entry->sample_count);
+ }
+ }
+
+ samplecache_list = fluid_list_remove(samplecache_list, entry);
+ delete_samplecache_entry(entry);
+ }
+
+ ret = FLUID_OK;
+ goto unlock_exit;
+ }
+
+ entry_list = fluid_list_next(entry_list);
+ }
+
+ FLUID_LOG(FLUID_ERR, "Trying to free sample data not found in cache.");
+ ret = FLUID_FAILED;
+
+unlock_exit:
+ fluid_mutex_unlock(samplecache_mutex);
+ return ret;
+}
+
+
+/* Private functions */
+static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
+ unsigned int sample_start,
+ unsigned int sample_end,
+ int sample_type)
+{
+ fluid_samplecache_entry_t *entry;
+
+ entry = FLUID_NEW(fluid_samplecache_entry_t);
+
+ if(entry == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(entry, 0, sizeof(*entry));
+
+ entry->filename = FLUID_STRDUP(sf->fname);
+
+ if(entry->filename == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_exit;
+ }
+
+ if(fluid_get_file_modification_time(entry->filename, &entry->modification_time) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
+ entry->modification_time = 0;
+ }
+
+ entry->sf_samplepos = sf->samplepos;
+ entry->sf_samplesize = sf->samplesize;
+ entry->sf_sample24pos = sf->sample24pos;
+ entry->sf_sample24size = sf->sample24size;
+ entry->sample_start = sample_start;
+ entry->sample_end = sample_end;
+ entry->sample_type = sample_type;
+
+ entry->sample_count = fluid_sffile_read_sample_data(sf, sample_start, sample_end, sample_type,
+ &entry->sample_data, &entry->sample_data24);
+
+ if(entry->sample_count < 0)
+ {
+ goto error_exit;
+ }
+
+ return entry;
+
+error_exit:
+ delete_samplecache_entry(entry);
+ return NULL;
+}
+
+static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
+{
+ fluid_return_if_fail(entry != NULL);
+
+ FLUID_FREE(entry->filename);
+ FLUID_FREE(entry->sample_data);
+ FLUID_FREE(entry->sample_data24);
+ FLUID_FREE(entry);
+}
+
+static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
+ unsigned int sample_start,
+ unsigned int sample_end,
+ int sample_type)
+{
+ time_t mtime;
+ fluid_list_t *entry_list;
+ fluid_samplecache_entry_t *entry;
+
+ if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
+ mtime = 0;
+ }
+
+ entry_list = samplecache_list;
+
+ while(entry_list)
+ {
+ entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
+
+ if((FLUID_STRCMP(sf->fname, entry->filename) == 0) &&
+ (mtime == entry->modification_time) &&
+ (sf->samplepos == entry->sf_samplepos) &&
+ (sf->samplesize == entry->sf_samplesize) &&
+ (sf->sample24pos == entry->sf_sample24pos) &&
+ (sf->sample24size == entry->sf_sample24size) &&
+ (sample_start == entry->sample_start) &&
+ (sample_end == entry->sample_end) &&
+ (sample_type == entry->sample_type))
+ {
+ return entry;
+ }
+
+ entry_list = fluid_list_next(entry_list);
+ }
+
+ return NULL;
+}
+
+static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
+{
+ fluid_stat_buf_t buf;
+
+ if(fluid_stat(filename, &buf))
+ {
+ return FLUID_FAILED;
+ }
+
+ *modification_time = buf.st_mtime;
+ return FLUID_OK;
+}
diff --git a/libs/fluidsynth/src/fluid_samplecache.h b/libs/fluidsynth/src/fluid_samplecache.h
new file mode 100644
index 0000000000..49b802ba61
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_samplecache.h
@@ -0,0 +1,34 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+#ifndef _FLUID_SAMPLECACHE_H
+#define _FLUID_SAMPLECACHE_H
+
+#include "fluid_sfont.h"
+#include "fluid_sffile.h"
+
+int fluid_samplecache_load(SFData *sf,
+ unsigned int sample_start, unsigned int sample_end, int sample_type,
+ int try_mlock, short **data, char **data24);
+
+int fluid_samplecache_unload(const short *sample_data);
+
+#endif /* _FLUID_SAMPLECACHE_H */
diff --git a/libs/fluidsynth/src/fluid_settings.c b/libs/fluidsynth/src/fluid_settings.c
index 181484ecc3..05423384ee 100644
--- a/libs/fluidsynth/src/fluid_settings.c
+++ b/libs/fluidsynth/src/fluid_settings.c
@@ -3,228 +3,251 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
-#include "fluidsynth_priv.h"
#include "fluid_sys.h"
#include "fluid_hash.h"
#include "fluid_synth.h"
-//#include "fluid_cmd.h"
-//#include "fluid_adriver.h"
-//#include "fluid_mdriver.h"
#include "fluid_settings.h"
#include "fluid_midi.h"
-/* Defined in fluid_filerenderer.c */
-extern void fluid_file_renderer_settings (fluid_settings_t* settings);
-
/* maximum allowed components of a settings variable (separated by '.') */
#define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */
#define MAX_SETTINGS_LABEL 256 /* max length of a settings variable label */
-static void fluid_settings_init(fluid_settings_t* settings);
-static void fluid_settings_key_destroy_func(void* value);
-static void fluid_settings_value_destroy_func(void* value);
+static void fluid_settings_init(fluid_settings_t *settings);
+static void fluid_settings_key_destroy_func(void *value);
+static void fluid_settings_value_destroy_func(void *value);
static int fluid_settings_tokenize(const char *s, char *buf, char **ptr);
/* Common structure to all settings nodes */
-typedef struct {
- int type; /**< fluid_types_enum */
-} fluid_setting_node_t;
-
-typedef struct {
- fluid_setting_node_t node;
- char* value;
- char* def;
- int hints;
- fluid_list_t* options;
- fluid_str_update_t update;
- void* data;
+typedef struct
+{
+ char *value;
+ char *def;
+ int hints;
+ fluid_list_t *options;
+ fluid_str_update_t update;
+ void *data;
} fluid_str_setting_t;
-typedef struct {
- fluid_setting_node_t node;
- double value;
- double def;
- double min;
- double max;
- int hints;
- fluid_num_update_t update;
- void* data;
+typedef struct
+{
+ double value;
+ double def;
+ double min;
+ double max;
+ int hints;
+ fluid_num_update_t update;
+ void *data;
} fluid_num_setting_t;
-typedef struct {
- fluid_setting_node_t node;
- int value;
- int def;
- int min;
- int max;
- int hints;
- fluid_int_update_t update;
- void* data;
+typedef struct
+{
+ int value;
+ int def;
+ int min;
+ int max;
+ int hints;
+ fluid_int_update_t update;
+ void *data;
} fluid_int_setting_t;
-typedef struct {
- fluid_setting_node_t node;
- fluid_hashtable_t *hashtable;
+typedef struct
+{
+ fluid_hashtable_t *hashtable;
} fluid_set_setting_t;
+typedef struct
+{
+ int type; /**< fluid_types_enum */
-static fluid_str_setting_t*
-new_fluid_str_setting(const char* value, char* def, int hints, fluid_str_update_t fun, void* data)
+ union
+ {
+ fluid_str_setting_t str;
+ fluid_num_setting_t num;
+ fluid_int_setting_t i;
+ fluid_set_setting_t set;
+ };
+} fluid_setting_node_t;
+
+static fluid_setting_node_t *
+new_fluid_str_setting(const char *value, const char *def, int hints)
{
- fluid_str_setting_t* str;
-
- str = FLUID_NEW(fluid_str_setting_t);
-
- if (!str)
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- str->node.type = FLUID_STR_TYPE;
- str->value = value? FLUID_STRDUP(value) : NULL;
- str->def = def? FLUID_STRDUP(def) : NULL;
- str->hints = hints;
- str->options = NULL;
- str->update = fun;
- str->data = data;
- return str;
+ fluid_setting_node_t *node;
+ fluid_str_setting_t *str;
+
+ node = FLUID_NEW(fluid_setting_node_t);
+
+ if(!node)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ node->type = FLUID_STR_TYPE;
+
+ str = &node->str;
+ str->value = value ? FLUID_STRDUP(value) : NULL;
+ str->def = def ? FLUID_STRDUP(def) : NULL;
+ str->hints = hints;
+ str->options = NULL;
+ str->update = NULL;
+ str->data = NULL;
+ return node;
}
static void
-delete_fluid_str_setting(fluid_str_setting_t* str)
+delete_fluid_str_setting(fluid_setting_node_t *node)
{
- if (!str) return;
+ fluid_return_if_fail(node != NULL);
- if (str->value) FLUID_FREE(str->value);
- if (str->def) FLUID_FREE(str->def);
+ FLUID_ASSERT(node->type == FLUID_STR_TYPE);
- if (str->options) {
- fluid_list_t* list = str->options;
+ FLUID_FREE(node->str.value);
+ FLUID_FREE(node->str.def);
- while (list) {
- FLUID_FREE (list->data);
- list = fluid_list_next(list);
- }
+ if(node->str.options)
+ {
+ fluid_list_t *list = node->str.options;
+
+ while(list)
+ {
+ FLUID_FREE(list->data);
+ list = fluid_list_next(list);
+ }
- delete_fluid_list(str->options);
- }
+ delete_fluid_list(node->str.options);
+ }
- FLUID_FREE(str);
+ FLUID_FREE(node);
}
-static fluid_num_setting_t*
-new_fluid_num_setting(double min, double max, double def,
- int hints, fluid_num_update_t fun, void* data)
+static fluid_setting_node_t *
+new_fluid_num_setting(double min, double max, double def, int hints)
{
- fluid_num_setting_t* setting;
-
- setting = FLUID_NEW(fluid_num_setting_t);
-
- if (!setting)
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- setting->node.type = FLUID_NUM_TYPE;
- setting->value = def;
- setting->def = def;
- setting->min = min;
- setting->max = max;
- setting->hints = hints;
- setting->update = fun;
- setting->data = data;
- return setting;
+ fluid_setting_node_t *node;
+ fluid_num_setting_t *num;
+
+ node = FLUID_NEW(fluid_setting_node_t);
+
+ if(!node)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ node->type = FLUID_NUM_TYPE;
+
+ num = &node->num;
+ num->value = def;
+ num->def = def;
+ num->min = min;
+ num->max = max;
+ num->hints = hints;
+ num->update = NULL;
+ num->data = NULL;
+
+ return node;
}
static void
-delete_fluid_num_setting(fluid_num_setting_t* setting)
+delete_fluid_num_setting(fluid_setting_node_t *node)
{
- if (setting) FLUID_FREE(setting);
+ fluid_return_if_fail(node != NULL);
+
+ FLUID_ASSERT(node->type == FLUID_NUM_TYPE);
+ FLUID_FREE(node);
}
-static fluid_int_setting_t*
-new_fluid_int_setting(int min, int max, int def,
- int hints, fluid_int_update_t fun, void* data)
+static fluid_setting_node_t *
+new_fluid_int_setting(int min, int max, int def, int hints)
{
- fluid_int_setting_t* setting;
-
- setting = FLUID_NEW(fluid_int_setting_t);
-
- if (!setting)
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- setting->node.type = FLUID_INT_TYPE;
- setting->value = def;
- setting->def = def;
- setting->min = min;
- setting->max = max;
- setting->hints = hints;
- setting->update = fun;
- setting->data = data;
- return setting;
+ fluid_setting_node_t *node;
+ fluid_int_setting_t *i;
+
+ node = FLUID_NEW(fluid_setting_node_t);
+
+ if(!node)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ node->type = FLUID_INT_TYPE;
+
+ i = &node->i;
+ i->value = def;
+ i->def = def;
+ i->min = min;
+ i->max = max;
+ i->hints = hints;
+ i->update = NULL;
+ i->data = NULL;
+ return node;
}
static void
-delete_fluid_int_setting(fluid_int_setting_t* setting)
+delete_fluid_int_setting(fluid_setting_node_t *node)
{
- if (setting) FLUID_FREE(setting);
+ fluid_return_if_fail(node != NULL);
+
+ FLUID_ASSERT(node->type == FLUID_INT_TYPE);
+ FLUID_FREE(node);
}
-static fluid_set_setting_t*
+static fluid_setting_node_t *
new_fluid_set_setting(void)
{
- fluid_set_setting_t* setting;
-
- setting = FLUID_NEW(fluid_set_setting_t);
-
- if (!setting)
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- setting->node.type = FLUID_SET_TYPE;
- setting->hashtable = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
- fluid_settings_key_destroy_func,
- fluid_settings_value_destroy_func);
- if (!setting->hashtable)
- {
- FLUID_FREE (setting);
- return NULL;
- }
-
- return setting;
+ fluid_setting_node_t *node;
+ fluid_set_setting_t *set;
+
+ node = FLUID_NEW(fluid_setting_node_t);
+
+ if(!node)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ node->type = FLUID_SET_TYPE;
+ set = &node->set;
+
+ set->hashtable = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
+ fluid_settings_key_destroy_func,
+ fluid_settings_value_destroy_func);
+
+ if(!set->hashtable)
+ {
+ FLUID_FREE(node);
+ return NULL;
+ }
+
+ return node;
}
static void
-delete_fluid_set_setting(fluid_set_setting_t* setting)
+delete_fluid_set_setting(fluid_setting_node_t *node)
{
- if (setting)
- {
- delete_fluid_hashtable(setting->hashtable);
- FLUID_FREE(setting);
- }
+ fluid_return_if_fail(node != NULL);
+
+ FLUID_ASSERT(node->type == FLUID_SET_TYPE);
+ delete_fluid_hashtable(node->set.hashtable);
+ FLUID_FREE(node);
}
/**
@@ -234,16 +257,20 @@ delete_fluid_set_setting(fluid_set_setting_t* setting)
fluid_settings_t *
new_fluid_settings(void)
{
- fluid_settings_t* settings;
+ fluid_settings_t *settings;
+
+ settings = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
+ fluid_settings_key_destroy_func,
+ fluid_settings_value_destroy_func);
- settings = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
- fluid_settings_key_destroy_func,
- fluid_settings_value_destroy_func);
- if (settings == NULL) return NULL;
+ if(settings == NULL)
+ {
+ return NULL;
+ }
- fluid_rec_mutex_init (settings->mutex);
- fluid_settings_init(settings);
- return settings;
+ fluid_rec_mutex_init(settings->mutex);
+ fluid_settings_init(settings);
+ return settings;
}
/**
@@ -251,86 +278,93 @@ new_fluid_settings(void)
* @param settings a settings object
*/
void
-delete_fluid_settings(fluid_settings_t* settings)
+delete_fluid_settings(fluid_settings_t *settings)
{
- fluid_return_if_fail (settings != NULL);
+ fluid_return_if_fail(settings != NULL);
- fluid_rec_mutex_destroy (settings->mutex);
- delete_fluid_hashtable(settings);
+ fluid_rec_mutex_destroy(settings->mutex);
+ delete_fluid_hashtable(settings);
}
/* Settings hash key destroy function */
static void
-fluid_settings_key_destroy_func(void* value)
+fluid_settings_key_destroy_func(void *value)
{
- FLUID_FREE (value); /* Free the string key value */
+ FLUID_FREE(value); /* Free the string key value */
}
/* Settings hash value destroy function */
static void
-fluid_settings_value_destroy_func(void* value)
+fluid_settings_value_destroy_func(void *value)
{
- fluid_setting_node_t *node = value;
-
- switch (node->type) {
- case FLUID_NUM_TYPE:
- delete_fluid_num_setting((fluid_num_setting_t*) value);
- break;
- case FLUID_INT_TYPE:
- delete_fluid_int_setting((fluid_int_setting_t*) value);
- break;
- case FLUID_STR_TYPE:
- delete_fluid_str_setting((fluid_str_setting_t*) value);
- break;
- case FLUID_SET_TYPE:
- delete_fluid_set_setting((fluid_set_setting_t*) value);
- break;
- }
+ fluid_setting_node_t *node = value;
+
+ switch(node->type)
+ {
+ case FLUID_NUM_TYPE:
+ delete_fluid_num_setting(node);
+ break;
+
+ case FLUID_INT_TYPE:
+ delete_fluid_int_setting(node);
+ break;
+
+ case FLUID_STR_TYPE:
+ delete_fluid_str_setting(node);
+ break;
+
+ case FLUID_SET_TYPE:
+ delete_fluid_set_setting(node);
+ break;
+ }
}
void
-fluid_settings_init(fluid_settings_t* settings)
+fluid_settings_init(fluid_settings_t *settings)
{
- fluid_return_if_fail (settings != NULL);
+ fluid_return_if_fail(settings != NULL);
- fluid_synth_settings(settings);
+ fluid_synth_settings(settings);
#if 0
- fluid_shell_settings(settings);
- fluid_player_settings(settings);
- fluid_file_renderer_settings(settings);
- fluid_audio_driver_settings(settings);
- fluid_midi_driver_settings(settings);
+ fluid_shell_settings(settings);
+ fluid_player_settings(settings);
+ fluid_file_renderer_settings(settings);
+ fluid_audio_driver_settings(settings);
+ fluid_midi_driver_settings(settings);
#endif
}
static int
fluid_settings_tokenize(const char *s, char *buf, char **ptr)
{
- char *tokstr, *tok;
- int n = 0;
+ char *tokstr, *tok;
+ int n = 0;
- if (strlen (s) > MAX_SETTINGS_LABEL)
- {
- FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
- MAX_SETTINGS_LABEL);
- return 0;
- }
+ if(FLUID_STRLEN(s) > MAX_SETTINGS_LABEL)
+ {
+ FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
+ MAX_SETTINGS_LABEL);
+ return 0;
+ }
- FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
- tokstr = buf;
+ FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
+ tokstr = buf;
- while ((tok = fluid_strtok (&tokstr, ".")))
- {
- if (n >= MAX_SETTINGS_TOKENS)
+ while((tok = fluid_strtok(&tokstr, ".")))
{
- FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d",
- MAX_SETTINGS_TOKENS);
- return 0;
- } else
- ptr[n++] = tok;
- }
+ if(n >= MAX_SETTINGS_TOKENS)
+ {
+ FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d",
+ MAX_SETTINGS_TOKENS);
+ return 0;
+ }
+ else
+ {
+ ptr[n++] = tok;
+ }
+ }
- return n;
+ return n;
}
/**
@@ -339,34 +373,45 @@ fluid_settings_tokenize(const char *s, char *buf, char **ptr)
* @param settings a settings object
* @param name Settings name
* @param value Location to store setting node if found
- * @return 1 if the node exists, 0 otherwise
+ * @return #FLUID_OK if the node exists, #FLUID_FAILED otherwise
*/
static int
-fluid_settings_get(fluid_settings_t* settings, const char *name,
+fluid_settings_get(fluid_settings_t *settings, const char *name,
fluid_setting_node_t **value)
{
- fluid_hashtable_t* table = settings;
- fluid_setting_node_t *node = NULL;
- char* tokens[MAX_SETTINGS_TOKENS];
- char buf[MAX_SETTINGS_LABEL+1];
- int ntokens;
- int n;
+ fluid_hashtable_t *table = settings;
+ fluid_setting_node_t *node = NULL;
+ char *tokens[MAX_SETTINGS_TOKENS];
+ char buf[MAX_SETTINGS_LABEL + 1];
+ int ntokens;
+ int n;
+
+ ntokens = fluid_settings_tokenize(name, buf, tokens);
- ntokens = fluid_settings_tokenize (name, buf, tokens);
+ if(table == NULL || ntokens <= 0)
+ {
+ return FLUID_FAILED;
+ }
- if (table == NULL || ntokens <= 0) return 0;
+ for(n = 0; n < ntokens; n++)
+ {
- for (n = 0; n < ntokens; n++) {
+ node = fluid_hashtable_lookup(table, tokens[n]);
- node = fluid_hashtable_lookup(table, tokens[n]);
- if (!node) return 0;
+ if(!node)
+ {
+ return FLUID_FAILED;
+ }
- table = (node->type == FLUID_SET_TYPE) ? ((fluid_set_setting_t *)node)->hashtable : NULL;
- }
+ table = (node->type == FLUID_SET_TYPE) ? node->set.hashtable : NULL;
+ }
- if (value) *value = node;
+ if(value)
+ {
+ *value = node;
+ }
- return 1;
+ return FLUID_OK;
}
/**
@@ -375,583 +420,741 @@ fluid_settings_get(fluid_settings_t* settings, const char *name,
* @param settings a settings object
* @param name Settings name
* @param value Node instance to assign (used directly)
- * @return 1 if the value has been set, zero otherwise
+ * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
static int
-fluid_settings_set(fluid_settings_t* settings, const char *name, void* value)
+fluid_settings_set(fluid_settings_t *settings, const char *name, fluid_setting_node_t *value)
{
- fluid_hashtable_t* table = settings;
- fluid_setting_node_t *node;
- char* tokens[MAX_SETTINGS_TOKENS];
- char buf[MAX_SETTINGS_LABEL+1];
- int n, num;
- char *dupname;
-
- num = fluid_settings_tokenize (name, buf, tokens) - 1;
- if (num == 0)
- return 0;
+ fluid_hashtable_t *table = settings;
+ fluid_setting_node_t *node;
+ char *tokens[MAX_SETTINGS_TOKENS];
+ char buf[MAX_SETTINGS_LABEL + 1];
+ int n, num;
+ char *dupname;
- for (n = 0; n < num; n++) {
+ num = fluid_settings_tokenize(name, buf, tokens);
- node = fluid_hashtable_lookup(table, tokens[n]);
+ if(num == 0)
+ {
+ return FLUID_FAILED;
+ }
- if (node) {
+ num--;
- if (node->type == FLUID_SET_TYPE) {
- table = ((fluid_set_setting_t *)node)->hashtable;
- } else {
- /* path ends prematurely */
- FLUID_LOG(FLUID_WARN, "'%s' is not a node", name[n]);
- return 0;
- }
+ for(n = 0; n < num; n++)
+ {
- } else {
- /* create a new node */
- fluid_set_setting_t* setnode;
+ node = fluid_hashtable_lookup(table, tokens[n]);
- dupname = FLUID_STRDUP (tokens[n]);
- setnode = new_fluid_set_setting ();
+ if(node)
+ {
- if (!dupname || !setnode)
- {
- if (dupname) FLUID_FREE (dupname);
- else FLUID_LOG(FLUID_ERR, "Out of memory");
+ if(node->type == FLUID_SET_TYPE)
+ {
+ table = node->set.hashtable;
+ }
+ else
+ {
+ /* path ends prematurely */
+ FLUID_LOG(FLUID_WARN, "'%s' is not a node. Name of the setting was '%s'", tokens[n], name);
+ return FLUID_FAILED;
+ }
- if (setnode) delete_fluid_set_setting (setnode);
+ }
+ else
+ {
+ /* create a new node */
+ fluid_setting_node_t *setnode;
+
+ dupname = FLUID_STRDUP(tokens[n]);
+ setnode = new_fluid_set_setting();
+
+ if(!dupname || !setnode)
+ {
+ if(dupname)
+ {
+ FLUID_FREE(dupname);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ }
+
+ if(setnode)
+ {
+ delete_fluid_set_setting(setnode);
+ }
+
+ return FLUID_FAILED;
+ }
+
+ fluid_hashtable_insert(table, dupname, setnode);
+ table = setnode->set.hashtable;
+ }
+ }
- return 0;
- }
+ dupname = FLUID_STRDUP(tokens[num]);
- fluid_hashtable_insert(table, dupname, setnode);
- table = setnode->hashtable;
+ if(!dupname)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FLUID_FAILED;
}
- }
- dupname = FLUID_STRDUP (tokens[num]);
+ fluid_hashtable_insert(table, dupname, value);
- if (!dupname)
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return 0;
- }
+ return FLUID_OK;
+}
+
+/**
+ * Registers a new string value for the specified setting.
+ *
+ * @param settings a settings object
+ * @param name the setting's name
+ * @param def the default value for the setting
+ * @param hints the hints for the setting
+ * @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
+ */
+int
+fluid_settings_register_str(fluid_settings_t *settings, const char *name, const char *def, int hints)
+{
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_hashtable_insert(table, dupname, value);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
- return 1;
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if(fluid_settings_get(settings, name, &node) != FLUID_OK)
+ {
+ node = new_fluid_str_setting(def, def, hints);
+ retval = fluid_settings_set(settings, name, node);
+
+ if(retval != FLUID_OK)
+ {
+ delete_fluid_str_setting(node);
+ }
+ }
+ else
+ {
+ /* if variable already exists, don't change its value. */
+ if(node->type == FLUID_STR_TYPE)
+ {
+ fluid_str_setting_t *setting = &node->str;
+ setting->def = def ? FLUID_STRDUP(def) : NULL;
+ setting->hints = hints;
+ retval = FLUID_OK;
+ }
+ else
+ {
+ FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
+ }
+ }
+
+ fluid_rec_mutex_unlock(settings->mutex);
+
+ return retval;
}
-/** returns 1 if the value has been registered correctly, 0
- otherwise */
+/**
+ * Registers a new float value for the specified setting.
+ *
+ * @param settings a settings object
+ * @param name the setting's name
+ * @param def the default value for the setting
+ * @param min the smallest allowed value for the setting
+ * @param max the largest allowed value for the setting
+ * @param hints the hints for the setting
+ * @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
+ */
int
-fluid_settings_register_str(fluid_settings_t* settings, const char* name, const char* def, int hints,
- fluid_str_update_t fun, void* data)
+fluid_settings_register_num(fluid_settings_t *settings, const char *name, double def,
+ double min, double max, int hints)
{
- fluid_setting_node_t *node;
- fluid_str_setting_t* setting;
- int retval;
-
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
-
- fluid_rec_mutex_lock (settings->mutex);
-
- if (!fluid_settings_get(settings, name, &node)) {
- setting = new_fluid_str_setting(def, def, hints, fun, data);
- retval = fluid_settings_set(settings, name, setting);
- if (retval != 1) delete_fluid_str_setting (setting);
- } else {
- /* if variable already exists, don't change its value. */
- if (node->type == FLUID_STR_TYPE) {
- setting = (fluid_str_setting_t*) node;
- setting->update = fun;
- setting->data = data;
- setting->def = def? FLUID_STRDUP(def) : NULL;
- setting->hints = hints;
- retval = 1;
- } else {
- FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
- retval = 0;
- }
- }
-
- fluid_rec_mutex_unlock (settings->mutex);
-
- return retval;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
+
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+
+ /* For now, all floating point settings are bounded below and above */
+ hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
+
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if(fluid_settings_get(settings, name, &node) != FLUID_OK)
+ {
+ /* insert a new setting */
+ node = new_fluid_num_setting(min, max, def, hints);
+ retval = fluid_settings_set(settings, name, node);
+
+ if(retval != FLUID_OK)
+ {
+ delete_fluid_num_setting(node);
+ }
+ }
+ else
+ {
+ if(node->type == FLUID_NUM_TYPE)
+ {
+ /* update the existing setting but don't change its value */
+ fluid_num_setting_t *setting = &node->num;
+ setting->min = min;
+ setting->max = max;
+ setting->def = def;
+ setting->hints = hints;
+ retval = FLUID_OK;
+ }
+ else
+ {
+ /* type mismatch */
+ FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
+ }
+ }
+
+ fluid_rec_mutex_unlock(settings->mutex);
+
+ return retval;
}
-/** returns 1 if the value has been register correctly, zero
- otherwise */
+/**
+ * Registers a new integer value for the specified setting.
+ *
+ * @param settings a settings object
+ * @param name the setting's name
+ * @param def the default value for the setting
+ * @param min the smallest allowed value for the setting
+ * @param max the largest allowed value for the setting
+ * @param hints the hints for the setting
+ * @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
+ */
int
-fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
- double min, double max, int hints,
- fluid_num_update_t fun, void* data)
+fluid_settings_register_int(fluid_settings_t *settings, const char *name, int def,
+ int min, int max, int hints)
{
- fluid_setting_node_t *node;
- int retval;
-
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
-
- /* For now, all floating point settings are bounded below and above */
- hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
-
- fluid_rec_mutex_lock (settings->mutex);
-
- if (!fluid_settings_get(settings, name, &node)) {
- /* insert a new setting */
- fluid_num_setting_t* setting;
- setting = new_fluid_num_setting(min, max, def, hints, fun, data);
- retval = fluid_settings_set(settings, name, setting);
- if (retval != 1) delete_fluid_num_setting (setting);
- } else {
- if (node->type == FLUID_NUM_TYPE) {
- /* update the existing setting but don't change its value */
- fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
- setting->update = fun;
- setting->data = data;
- setting->min = min;
- setting->max = max;
- setting->def = def;
- setting->hints = hints;
- retval = 1;
- } else {
- /* type mismatch */
- FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
- retval = 0;
- }
- }
-
- fluid_rec_mutex_unlock (settings->mutex);
-
- return retval;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
+
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+
+ /* For now, all integer settings are bounded below and above */
+ hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
+
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if(fluid_settings_get(settings, name, &node) != FLUID_OK)
+ {
+ /* insert a new setting */
+ node = new_fluid_int_setting(min, max, def, hints);
+ retval = fluid_settings_set(settings, name, node);
+
+ if(retval != FLUID_OK)
+ {
+ delete_fluid_int_setting(node);
+ }
+ }
+ else
+ {
+ if(node->type == FLUID_INT_TYPE)
+ {
+ /* update the existing setting but don't change its value */
+ fluid_int_setting_t *setting = &node->i;
+ setting->min = min;
+ setting->max = max;
+ setting->def = def;
+ setting->hints = hints;
+ retval = FLUID_OK;
+ }
+ else
+ {
+ /* type mismatch */
+ FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
+ }
+ }
+
+ fluid_rec_mutex_unlock(settings->mutex);
+
+ return retval;
}
-/** returns 1 if the value has been register correctly, zero
- otherwise. */
-int
-fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
- int min, int max, int hints,
- fluid_int_update_t fun, void* data)
+/**
+ * Registers a callback for the specified string setting.
+ *
+ * @param settings a settings object
+ * @param name the setting's name
+ * @param callback an update function for the setting
+ * @param data user supplied data passed to the update function
+ * @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
+ */
+int fluid_settings_callback_str(fluid_settings_t *settings, const char *name,
+ fluid_str_update_t callback, void *data)
{
- fluid_setting_node_t *node;
- int retval;
-
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
-
- /* For now, all integer settings are bounded below and above */
- hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
-
- fluid_rec_mutex_lock (settings->mutex);
-
- if (!fluid_settings_get(settings, name, &node)) {
- /* insert a new setting */
- fluid_int_setting_t* setting;
- setting = new_fluid_int_setting(min, max, def, hints, fun, data);
- retval = fluid_settings_set(settings, name, setting);
- if (retval != 1) delete_fluid_int_setting (setting);
- } else {
- if (node->type == FLUID_INT_TYPE) {
- /* update the existing setting but don't change its value */
- fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
- setting->update = fun;
- setting->data = data;
- setting->min = min;
- setting->max = max;
- setting->def = def;
- setting->hints = hints;
- retval = 1;
- } else {
- /* type mismatch */
- FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
- retval = 0;
- }
- }
-
- fluid_rec_mutex_unlock (settings->mutex);
-
- return retval;
+ fluid_setting_node_t *node;
+ fluid_str_setting_t *setting;
+
+ fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
+
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if((fluid_settings_get(settings, name, &node) != FLUID_OK)
+ || node->type != FLUID_STR_TYPE)
+ {
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_FAILED;
+ }
+
+ setting = &node->str;
+ setting->update = callback;
+ setting->data = data;
+
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_OK;
}
/**
- * Get the type of the setting with the given name
+ * Registers a callback for the specified numeric setting.
*
* @param settings a settings object
- * @param name a setting's name
- * @return the type for the named setting, or #FLUID_NO_TYPE when it does not exist
+ * @param name the setting's name
+ * @param callback an update function for the setting
+ * @param data user supplied data passed to the update function
+ * @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
*/
-int
-fluid_settings_get_type(fluid_settings_t* settings, const char *name)
+int fluid_settings_callback_num(fluid_settings_t *settings, const char *name,
+ fluid_num_update_t callback, void *data)
{
- fluid_setting_node_t *node;
- int type;
+ fluid_setting_node_t *node;
+ fluid_num_setting_t *setting;
+
+ fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
- fluid_return_val_if_fail (settings != NULL, FLUID_NO_TYPE);
- fluid_return_val_if_fail (name != NULL, FLUID_NO_TYPE);
- fluid_return_val_if_fail (name[0] != '\0', FLUID_NO_TYPE);
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if((fluid_settings_get(settings, name, &node) != FLUID_OK)
+ || node->type != FLUID_NUM_TYPE)
+ {
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_FAILED;
+ }
- fluid_rec_mutex_lock (settings->mutex);
- type = fluid_settings_get (settings, name, &node) ? node->type : FLUID_NO_TYPE;
- fluid_rec_mutex_unlock (settings->mutex);
+ setting = &node->num;
+ setting->update = callback;
+ setting->data = data;
- return (type);
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_OK;
}
/**
- * Get the hints for the named setting as an integer bitmap
+ * Registers a callback for the specified int setting.
*
* @param settings a settings object
- * @param name a setting's name
- * @return the hints associated to the named setting if it exists, zero otherwise
+ * @param name the setting's name
+ * @param callback an update function for the setting
+ * @param data user supplied data passed to the update function
+ * @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
*/
-int
-fluid_settings_get_hints(fluid_settings_t* settings, const char *name)
+int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
+ fluid_int_update_t callback, void *data)
{
- fluid_setting_node_t *node;
- int hints = 0;
+ fluid_setting_node_t *node;
+ fluid_int_setting_t *setting;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
+ fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)) {
- if (node->type == FLUID_NUM_TYPE) {
- fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
- hints = setting->hints;
- } else if (node->type == FLUID_STR_TYPE) {
- fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
- hints = setting->hints;
- } else if (node->type == FLUID_INT_TYPE) {
- fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
- hints = setting->hints;
+ if((fluid_settings_get(settings, name, &node) != FLUID_OK)
+ || node->type != FLUID_INT_TYPE)
+ {
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_FAILED;
}
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ setting = &node->i;
+ setting->update = callback;
+ setting->data = data;
- return hints;
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_OK;
}
/**
- * Ask whether the setting is changeable in real-time.
+ * Get the type of the setting with the given name
*
* @param settings a settings object
* @param name a setting's name
- * @return non zero if the setting is changeable in real-time
+ * @return the type for the named setting (see #fluid_types_enum), or #FLUID_NO_TYPE when it does not exist
*/
int
-fluid_settings_is_realtime(fluid_settings_t* settings, const char *name)
+fluid_settings_get_type(fluid_settings_t *settings, const char *name)
{
- fluid_setting_node_t *node;
- int isrealtime = FALSE;
+ fluid_setting_node_t *node;
+ int type = FLUID_NO_TYPE;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
+ fluid_return_val_if_fail(settings != NULL, type);
+ fluid_return_val_if_fail(name != NULL, type);
+ fluid_return_val_if_fail(name[0] != '\0', type);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)) {
- if (node->type == FLUID_NUM_TYPE) {
- fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
- isrealtime = setting->update != NULL;
- } else if (node->type == FLUID_STR_TYPE) {
- fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
- isrealtime = setting->update != NULL;
- } else if (node->type == FLUID_INT_TYPE) {
- fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
- isrealtime = setting->update != NULL;
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK)
+ {
+ type = node->type;
}
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return isrealtime;
+ return type;
}
/**
- * Set a string value for a named setting
+ * Get the hints for the named setting as an integer bitmap
*
* @param settings a settings object
* @param name a setting's name
- * @param str new string value
- * @return 1 if the value has been set, 0 otherwise
+ * @param hints set to the hints associated to the setting if it exists
+ * @return #FLUID_OK if hints associated to the named setting exist, #FLUID_FAILED otherwise
*/
int
-fluid_settings_setstr(fluid_settings_t* settings, const char *name, const char *str)
+fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *hints)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
+
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
+ fluid_rec_mutex_lock(settings->mutex);
- fluid_rec_mutex_lock (settings->mutex);
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK)
+ {
+ if(node->type == FLUID_NUM_TYPE)
+ {
+ fluid_num_setting_t *setting = &node->num;
+ *hints = setting->hints;
+ retval = FLUID_OK;
+ }
+ else if(node->type == FLUID_STR_TYPE)
+ {
+ fluid_str_setting_t *setting = &node->str;
+ *hints = setting->hints;
+ retval = FLUID_OK;
+ }
+ else if(node->type == FLUID_INT_TYPE)
+ {
+ fluid_int_setting_t *setting = &node->i;
+ *hints = setting->hints;
+ retval = FLUID_OK;
+ }
+ }
- if (fluid_settings_get (settings, name, &node)) {
- if (node->type == FLUID_STR_TYPE) {
- fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
+ fluid_rec_mutex_unlock(settings->mutex);
- if (setting->value) FLUID_FREE (setting->value);
- setting->value = str ? FLUID_STRDUP (str) : NULL;
+ return retval;
+}
- /* Call under lock to keep update() synchronized with the current value */
- if (setting->update) (*setting->update)(setting->data, name, str);
- retval = 1;
- }
- else if (node->type == FLUID_INT_TYPE) /* Handle yes/no for boolean values for backwards compatibility */
- {
- fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
+/**
+ * Ask whether the setting is changeable in real-time.
+ *
+ * @param settings a settings object
+ * @param name a setting's name
+ * @return TRUE if the setting is changeable in real-time, FALSE otherwise
+ */
+int
+fluid_settings_is_realtime(fluid_settings_t *settings, const char *name)
+{
+ fluid_setting_node_t *node;
+ int isrealtime = FALSE;
+
+ fluid_return_val_if_fail(settings != NULL, 0);
+ fluid_return_val_if_fail(name != NULL, 0);
+ fluid_return_val_if_fail(name[0] != '\0', 0);
- if (setting->hints & FLUID_HINT_TOGGLED)
- {
- if (FLUID_STRCMP (str, "yes") == 0)
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK)
+ {
+ if(node->type == FLUID_NUM_TYPE)
+ {
+ fluid_num_setting_t *setting = &node->num;
+ isrealtime = setting->update != NULL;
+ }
+ else if(node->type == FLUID_STR_TYPE)
{
- setting->value = TRUE;
- if (setting->update) (*setting->update)(setting->data, name, TRUE);
+ fluid_str_setting_t *setting = &node->str;
+ isrealtime = setting->update != NULL;
}
- else if (FLUID_STRCMP (str, "no") == 0)
+ else if(node->type == FLUID_INT_TYPE)
{
- setting->value = FALSE;
- if (setting->update) (*setting->update)(setting->data, name, FALSE);
+ fluid_int_setting_t *setting = &node->i;
+ isrealtime = setting->update != NULL;
}
- }
}
- } else {
- /* insert a new setting */
- fluid_str_setting_t* setting;
- setting = new_fluid_str_setting(str, NULL, 0, NULL, NULL);
- retval = fluid_settings_set(settings, name, setting);
- if (retval != 1) delete_fluid_str_setting (setting);
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return isrealtime;
}
/**
- * Copy the value of a string setting
+ * Set a string value for a named setting
+ *
* @param settings a settings object
* @param name a setting's name
- * @param str Caller supplied buffer to copy string value to
- * @param len Size of 'str' buffer (no more than len bytes will be written, which
- * will always include a zero terminator)
- * @return 1 if the value exists, 0 otherwise
- * @since 1.1.0
- *
- * Like fluid_settings_getstr() but is thread safe. A size of 256 should be
- * more than sufficient for the string buffer.
+ * @param str new string value
+ * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
int
-fluid_settings_copystr(fluid_settings_t* settings, const char *name,
- char *str, int len)
+fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str)
{
- fluid_setting_node_t *node;
- int retval = 0;
-
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (str != NULL, 0);
- fluid_return_val_if_fail (len > 0, 0);
+ fluid_setting_node_t *node;
+ fluid_str_setting_t *setting;
+ char *new_value = NULL;
+ fluid_str_update_t callback = NULL;
+ void *data = NULL;
- str[0] = 0;
+ fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get (settings, name, &node))
- {
- if (node->type == FLUID_STR_TYPE)
+ if((fluid_settings_get(settings, name, &node) != FLUID_OK)
+ || (node->type != FLUID_STR_TYPE))
{
- fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
+ goto error_recovery;
+ }
- if (setting->value)
- {
- FLUID_STRNCPY (str, setting->value, len);
- str[len - 1] = 0; /* Force terminate, in case of truncation */
- }
+ setting = &node->str;
- retval = 1;
+ if(setting->value)
+ {
+ FLUID_FREE(setting->value);
}
- else if (node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
+
+ if(str)
{
- fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
+ new_value = FLUID_STRDUP(str);
+
+ if(new_value == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+ }
+
+ setting->value = new_value;
- if (setting->hints & FLUID_HINT_TOGGLED)
- {
- FLUID_STRNCPY (str, setting->value ? "yes" : "no", len);
- str[len - 1] = 0; /* Force terminate, in case of truncation */
+ callback = setting->update;
+ data = setting->data;
- retval = 1;
- }
+ /* Release the mutex before calling the update callback, to avoid
+ * possible deadlocks with FluidSynths API lock */
+ fluid_rec_mutex_unlock(settings->mutex);
+
+ if(callback)
+ {
+ (*callback)(data, name, new_value);
}
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ return FLUID_OK;
- return retval;
+error_recovery:
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_FAILED;
}
/**
- * Duplicate the value of a string setting
+ * Copy the value of a string setting into the provided buffer (thread safe)
* @param settings a settings object
* @param name a setting's name
- * @param str Location to store pointer to allocated duplicate string
- * @return 1 if the value exists and was successfully duplicated, 0 otherwise
+ * @param str Caller supplied buffer to copy string value to
+ * @param len Size of 'str' buffer (no more than len bytes will be written, which
+ * will always include a zero terminator)
+ * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
* @since 1.1.0
*
- * Like fluid_settings_copystr() but allocates a new copy of the string. Caller
- * owns the string and should free it with free() when done using it.
+ * @note A size of 256 should be more than sufficient for the string buffer.
*/
int
-fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str)
+fluid_settings_copystr(fluid_settings_t *settings, const char *name,
+ char *str, int len)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
+
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(str != NULL, retval);
+ fluid_return_val_if_fail(len > 0, retval);
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (str != NULL, 0);
+ str[0] = 0;
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node))
- {
- if (node->type == FLUID_STR_TYPE)
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
- fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
+ if(node->type == FLUID_STR_TYPE)
+ {
+ fluid_str_setting_t *setting = &node->str;
- if (setting->value)
- {
- *str = FLUID_STRDUP (setting->value);
- if (!*str) FLUID_LOG (FLUID_ERR, "Out of memory");
- }
+ if(setting->value)
+ {
+ FLUID_STRNCPY(str, setting->value, len);
+ }
- if (!setting->value || *str) retval = 1; /* Don't set to 1 if out of memory */
- }
- else if (node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
- {
- fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
+ retval = FLUID_OK;
+ }
+ else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
+ {
+ fluid_int_setting_t *setting = &node->i;
- if (setting->hints & FLUID_HINT_TOGGLED)
- {
- *str = FLUID_STRDUP (setting->value ? "yes" : "no");
- if (!*str) FLUID_LOG (FLUID_ERR, "Out of memory");
+ if(setting->hints & FLUID_HINT_TOGGLED)
+ {
+ FLUID_STRNCPY(str, setting->value ? "yes" : "no", len);
- if (!setting->value || *str) retval = 1; /* Don't set to 1 if out of memory */
- }
+ retval = FLUID_OK;
+ }
+ }
}
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
/**
- * Get the value of a string setting
+ * Duplicate the value of a string setting
* @param settings a settings object
* @param name a setting's name
- * @param str Location to store pointer to the settings string value
- * @return 1 if the value exists, 0 otherwise
- * @deprecated
- *
- * If the value does not exists, 'str' is set to NULL. Otherwise, 'str' will
- * point to the value. The application does not own the returned value and it
- * is valid only until a new value is assigned to the setting of the given name.
+ * @param str Location to store pointer to allocated duplicate string
+ * @return #FLUID_OK if the value exists and was successfully duplicated, #FLUID_FAILED otherwise
+ * @since 1.1.0
*
- * NOTE: In a multi-threaded environment, caller must ensure that the setting
- * being read by fluid_settings_getstr() is not assigned during the
- * duration of callers use of the setting's value. Use fluid_settings_copystr()
- * or fluid_settings_dupstr() which does not have this restriction.
+ * Like fluid_settings_copystr() but allocates a new copy of the string. Caller
+ * owns the string and should free it with free() when done using it.
*/
int
-fluid_settings_getstr(fluid_settings_t* settings, const char *name, char** str)
+fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (str != NULL, 0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(str != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node))
- {
- if (node->type == FLUID_STR_TYPE)
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
- fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
- *str = setting->value;
- retval = 1;
- }
- else if (node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
- {
- fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
-
- if (setting->hints & FLUID_HINT_TOGGLED)
- {
- *str = setting->value ? "yes" : "no";
- retval = 1;
- }
+ if(node->type == FLUID_STR_TYPE)
+ {
+ fluid_str_setting_t *setting = &node->str;
+
+ if(setting->value)
+ {
+ *str = FLUID_STRDUP(setting->value);
+
+ if(!*str)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ }
+ }
+
+ if(!setting->value || *str)
+ {
+ retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */
+ }
+ }
+ else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
+ {
+ fluid_int_setting_t *setting = &node->i;
+
+ if(setting->hints & FLUID_HINT_TOGGLED)
+ {
+ *str = FLUID_STRDUP(setting->value ? "yes" : "no");
+
+ if(!*str)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ }
+
+ if(!setting->value || *str)
+ {
+ retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */
+ }
+ }
+ }
}
- }
- else *str = NULL;
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
+
/**
* Test a string setting for some value.
*
* @param settings a settings object
* @param name a setting's name
* @param s a string to be tested
- * @return 1 if the value exists and is equal to 's', 0 otherwise
+ * @return TRUE if the value exists and is equal to 's', FALSE otherwise
*/
int
-fluid_settings_str_equal (fluid_settings_t* settings, const char *name, const char *s)
+fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *s)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FALSE;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (s != NULL, 0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(s != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get (settings, name, &node))
- {
- if (node->type == FLUID_STR_TYPE)
- {
- fluid_str_setting_t *setting = (fluid_str_setting_t *)node;
- if (setting->value) retval = FLUID_STRCMP (setting->value, s) == 0;
- }
- else if (node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
- fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
+ if(node->type == FLUID_STR_TYPE)
+ {
+ fluid_str_setting_t *setting = &node->str;
+
+ if(setting->value)
+ {
+ retval = FLUID_STRCMP(setting->value, s) == 0;
+ }
+ }
+ else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
+ {
+ fluid_int_setting_t *setting = &node->i;
- if (setting->hints & FLUID_HINT_TOGGLED)
- retval = FLUID_STRCMP (setting->value ? "yes" : "no", s) == 0;
+ if(setting->hints & FLUID_HINT_TOGGLED)
+ {
+ retval = FLUID_STRCMP(setting->value ? "yes" : "no", s) == 0;
+ }
+ }
}
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
/**
@@ -960,39 +1163,43 @@ fluid_settings_str_equal (fluid_settings_t* settings, const char *name, const ch
*
* @param settings a settings object
* @param name a setting's name
- * @return the default string value of the setting if it exists, NULL otherwise
+ * @param def the default string value of the setting if it exists
+ * @return FLUID_OK on success, FLUID_FAILED otherwise
*/
-char*
-fluid_settings_getstr_default(fluid_settings_t* settings, const char *name)
+int
+fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def)
{
- fluid_setting_node_t *node;
- char *retval = NULL;
+ fluid_setting_node_t *node;
+ char *retval = NULL;
- fluid_return_val_if_fail (settings != NULL, NULL);
- fluid_return_val_if_fail (name != NULL, NULL);
- fluid_return_val_if_fail (name[0] != '\0', NULL);
+ fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get (settings, name, &node))
- {
- if (node->type == FLUID_STR_TYPE)
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
- fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
- retval = setting->def;
- }
- else if (node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
- {
- fluid_int_setting_t *setting = (fluid_int_setting_t *)node;
+ if(node->type == FLUID_STR_TYPE)
+ {
+ fluid_str_setting_t *setting = &node->str;
+ retval = setting->def;
+ }
+ else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
+ {
+ fluid_int_setting_t *setting = &node->i;
- if (setting->hints & FLUID_HINT_TOGGLED)
- retval = setting->def ? "yes" : "no";
+ if(setting->hints & FLUID_HINT_TOGGLED)
+ {
+ retval = setting->def ? "yes" : "no";
+ }
+ }
}
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ *def = retval;
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval != NULL ? FLUID_OK : FLUID_FAILED;
}
/**
@@ -1000,35 +1207,36 @@ fluid_settings_getstr_default(fluid_settings_t* settings, const char *name)
* @param settings a settings object
* @param name a setting's name
* @param s option string to add
- * @return 1 if the setting exists and option was added, 0 otherwise
+ * @return #FLUID_OK if the setting exists and option was added, #FLUID_FAILED otherwise
*
* Causes the setting's #FLUID_HINT_OPTIONLIST hint to be set.
*/
int
-fluid_settings_add_option(fluid_settings_t* settings, const char *name, const char *s)
+fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (s != NULL, 0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(s != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_STR_TYPE)) {
- fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
- char* copy = FLUID_STRDUP(s);
- setting->options = fluid_list_append(setting->options, copy);
- setting->hints |= FLUID_HINT_OPTIONLIST;
- retval = 1;
- }
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_STR_TYPE))
+ {
+ fluid_str_setting_t *setting = &node->str;
+ char *copy = FLUID_STRDUP(s);
+ setting->options = fluid_list_append(setting->options, copy);
+ setting->hints |= FLUID_HINT_OPTIONLIST;
+ retval = FLUID_OK;
+ }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
/**
@@ -1036,42 +1244,47 @@ fluid_settings_add_option(fluid_settings_t* settings, const char *name, const ch
* @param settings a settings object
* @param name a setting's name
* @param s option string to remove
- * @return 1 if the setting exists and option was removed, 0 otherwise
+ * @return #FLUID_OK if the setting exists and option was removed, #FLUID_FAILED otherwise
*/
int
-fluid_settings_remove_option(fluid_settings_t* settings, const char *name, const char* s)
+fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (s != NULL, 0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(s != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_STR_TYPE)) {
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_STR_TYPE))
+ {
- fluid_str_setting_t* setting = (fluid_str_setting_t*) node;
- fluid_list_t* list = setting->options;
+ fluid_str_setting_t *setting = &node->str;
+ fluid_list_t *list = setting->options;
- while (list) {
- char* option = (char*) fluid_list_get(list);
- if (FLUID_STRCMP(s, option) == 0) {
- FLUID_FREE (option);
- setting->options = fluid_list_remove_link(setting->options, list);
- retval = 1;
- break;
- }
- list = fluid_list_next(list);
+ while(list)
+ {
+ char *option = (char *) fluid_list_get(list);
+
+ if(FLUID_STRCMP(s, option) == 0)
+ {
+ FLUID_FREE(option);
+ setting->options = fluid_list_remove_link(setting->options, list);
+ retval = FLUID_OK;
+ break;
+ }
+
+ list = fluid_list_next(list);
+ }
}
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
/**
@@ -1080,46 +1293,55 @@ fluid_settings_remove_option(fluid_settings_t* settings, const char *name, const
* @param settings a settings object
* @param name a setting's name
* @param val new setting's value
- * @return 1 if the value has been set, 0 otherwise
+ * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
int
-fluid_settings_setnum(fluid_settings_t* settings, const char *name, double val)
+fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val)
{
- fluid_setting_node_t *node;
- fluid_num_setting_t* setting;
- int retval = 0;
-
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
+ fluid_setting_node_t *node;
+ fluid_num_setting_t *setting;
+ fluid_num_update_t callback = NULL;
+ void *data = NULL;
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
- if (fluid_settings_get(settings, name, &node)) {
- if (node->type == FLUID_NUM_TYPE) {
- setting = (fluid_num_setting_t*) node;
+ fluid_rec_mutex_lock(settings->mutex);
- if (val < setting->min) val = setting->min;
- else if (val > setting->max) val = setting->max;
+ if((fluid_settings_get(settings, name, &node) != FLUID_OK)
+ || (node->type != FLUID_NUM_TYPE))
+ {
+ goto error_recovery;
+ }
- setting->value = val;
+ setting = &node->num;
- /* Call under lock to keep update() synchronized with the current value */
- if (setting->update) (*setting->update)(setting->data, name, val);
- retval = 1;
+ if(val < setting->min || val > setting->max)
+ {
+ FLUID_LOG(FLUID_DBG, "requested set value for %s out of range", name);
+ goto error_recovery;
}
- } else {
- /* insert a new setting */
- fluid_num_setting_t* setting;
- setting = new_fluid_num_setting(-1e10, 1e10, 0.0f, 0, NULL, NULL);
+
setting->value = val;
- retval = fluid_settings_set(settings, name, setting);
- if (retval != 1) delete_fluid_num_setting (setting);
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ callback = setting->update;
+ data = setting->data;
- return retval;
+ /* Release the mutex before calling the update callback, to avoid
+ * possible deadlocks with FluidSynths API lock */
+ fluid_rec_mutex_unlock(settings->mutex);
+
+ if(callback)
+ {
+ (*callback)(data, name, val);
+ }
+
+ return FLUID_OK;
+
+error_recovery:
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_FAILED;
}
/**
@@ -1128,31 +1350,53 @@ fluid_settings_setnum(fluid_settings_t* settings, const char *name, double val)
* @param settings a settings object
* @param name a setting's name
* @param val variable pointer to receive the setting's numeric value
- * @return 1 if the value exists, 0 otherwise
+ * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
*/
int
-fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val)
+fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (val != NULL, 0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(val != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_NUM_TYPE)) {
- fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
- *val = setting->value;
- retval = 1;
- }
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_NUM_TYPE))
+ {
+ fluid_num_setting_t *setting = &node->num;
+ *val = setting->value;
+ retval = FLUID_OK;
+ }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
+}
+
+/**
+ * float-typed wrapper for fluid_settings_getnum
+ *
+ * @param settings a settings object
+ * @param name a setting's name
+ * @param val variable pointer to receive the setting's float value
+ * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
+ */
+int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val)
+{
+ double tmp;
+
+ if(fluid_settings_getnum(settings, name, &tmp) == FLUID_OK)
+ {
+ *val = tmp;
+ return FLUID_OK;
+ }
+
+ return FLUID_FAILED;
}
/**
@@ -1162,29 +1406,35 @@ fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val)
* @param name a setting's name
* @param min setting's range lower limit
* @param max setting's range upper limit
+ * @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise
*/
-void
-fluid_settings_getnum_range(fluid_settings_t* settings, const char *name,
- double* min, double* max)
+int
+fluid_settings_getnum_range(fluid_settings_t *settings, const char *name,
+ double *min, double *max)
{
- fluid_setting_node_t *node;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
+
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(min != NULL, retval);
+ fluid_return_val_if_fail(max != NULL, retval);
- fluid_return_if_fail (settings != NULL);
- fluid_return_if_fail (name != NULL);
- fluid_return_if_fail (name[0] != '\0');
- fluid_return_if_fail (min != NULL);
- fluid_return_if_fail (max != NULL);
+ fluid_rec_mutex_lock(settings->mutex);
- fluid_rec_mutex_lock (settings->mutex);
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_NUM_TYPE))
+ {
+ fluid_num_setting_t *setting = &node->num;
+ *min = setting->min;
+ *max = setting->max;
+ retval = FLUID_OK;
+ }
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_NUM_TYPE)) {
- fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
- *min = setting->min;
- *max = setting->max;
- }
+ fluid_rec_mutex_unlock(settings->mutex);
- fluid_rec_mutex_unlock (settings->mutex);
+ return retval;
}
/**
@@ -1192,29 +1442,33 @@ fluid_settings_getnum_range(fluid_settings_t* settings, const char *name,
*
* @param settings a settings object
* @param name a setting's name
- * @return the default value if the named setting exists, 0.0f otherwise
+ * @param val set to the default value if the named setting exists
+ * @return #FLUID_OK if the default value of the named setting exists, #FLUID_FAILED otherwise
*/
-double
-fluid_settings_getnum_default(fluid_settings_t* settings, const char *name)
+int
+fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val)
{
- fluid_setting_node_t *node;
- double retval = 0.0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_val_if_fail (settings != NULL, 0.0);
- fluid_return_val_if_fail (name != NULL, 0.0);
- fluid_return_val_if_fail (name[0] != '\0', 0.0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(val != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_NUM_TYPE)) {
- fluid_num_setting_t* setting = (fluid_num_setting_t*) node;
- retval = setting->def;
- }
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_NUM_TYPE))
+ {
+ fluid_num_setting_t *setting = &node->num;
+ *val = setting->def;
+ retval = FLUID_OK;
+ }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
/**
@@ -1223,46 +1477,55 @@ fluid_settings_getnum_default(fluid_settings_t* settings, const char *name)
* @param settings a settings object
* @param name a setting's name
* @param val new setting's integer value
- * @return 1 if the value has been set, 0 otherwise
+ * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
int
-fluid_settings_setint(fluid_settings_t* settings, const char *name, int val)
+fluid_settings_setint(fluid_settings_t *settings, const char *name, int val)
{
- fluid_setting_node_t *node;
- fluid_int_setting_t* setting;
- int retval = 0;
-
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
+ fluid_setting_node_t *node;
+ fluid_int_setting_t *setting;
+ fluid_int_update_t callback = NULL;
+ void *data = NULL;
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
- if (fluid_settings_get(settings, name, &node)) {
- if (node->type == FLUID_INT_TYPE) {
- setting = (fluid_int_setting_t*) node;
+ fluid_rec_mutex_lock(settings->mutex);
- if (val < setting->min) val = setting->min;
- else if (val > setting->max) val = setting->max;
+ if((fluid_settings_get(settings, name, &node) != FLUID_OK)
+ || (node->type != FLUID_INT_TYPE))
+ {
+ goto error_recovery;
+ }
- setting->value = val;
+ setting = &node->i;
- /* Call under lock to keep update() synchronized with the current value */
- if (setting->update) (*setting->update)(setting->data, name, val);
- retval = 1;
+ if(val < setting->min || val > setting->max)
+ {
+ FLUID_LOG(FLUID_DBG, "requested set value for %s out of range", name);
+ goto error_recovery;
}
- } else {
- /* insert a new setting */
- fluid_int_setting_t* setting;
- setting = new_fluid_int_setting(INT_MIN, INT_MAX, 0, 0, NULL, NULL);
+
setting->value = val;
- retval = fluid_settings_set(settings, name, setting);
- if (retval != 1) delete_fluid_int_setting (setting);
- }
- fluid_rec_mutex_unlock (settings->mutex);
+ callback = setting->update;
+ data = setting->data;
+
+ /* Release the mutex before calling the update callback, to avoid
+ * possible deadlocks with FluidSynths API lock */
+ fluid_rec_mutex_unlock(settings->mutex);
+
+ if(callback)
+ {
+ (*callback)(data, name, val);
+ }
+
+ return FLUID_OK;
- return retval;
+error_recovery:
+ fluid_rec_mutex_unlock(settings->mutex);
+ return FLUID_FAILED;
}
/**
@@ -1271,31 +1534,32 @@ fluid_settings_setint(fluid_settings_t* settings, const char *name, int val)
* @param settings a settings object
* @param name a setting's name
* @param val pointer to a variable to receive the setting's integer value
- * @return 1 if the value exists, 0 otherwise
+ * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
*/
int
-fluid_settings_getint(fluid_settings_t* settings, const char *name, int* val)
+fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
- fluid_return_val_if_fail (val != NULL, 0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(val != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_INT_TYPE)) {
- fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
- *val = setting->value;
- retval = 1;
- }
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_INT_TYPE))
+ {
+ fluid_int_setting_t *setting = &node->i;
+ *val = setting->value;
+ retval = FLUID_OK;
+ }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
/**
@@ -1304,29 +1568,35 @@ fluid_settings_getint(fluid_settings_t* settings, const char *name, int* val)
* @param name a setting's name
* @param min setting's range lower limit
* @param max setting's range upper limit
+ * @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise
*/
-void
-fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
- int* min, int* max)
+int
+fluid_settings_getint_range(fluid_settings_t *settings, const char *name,
+ int *min, int *max)
{
- fluid_setting_node_t *node;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_if_fail (settings != NULL);
- fluid_return_if_fail (name != NULL);
- fluid_return_if_fail (name[0] != '\0');
- fluid_return_if_fail (min != NULL);
- fluid_return_if_fail (max != NULL);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(min != NULL, retval);
+ fluid_return_val_if_fail(max != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_INT_TYPE))
+ {
+ fluid_int_setting_t *setting = &node->i;
+ *min = setting->min;
+ *max = setting->max;
+ retval = FLUID_OK;
+ }
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_INT_TYPE)) {
- fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
- *min = setting->min;
- *max = setting->max;
- }
+ fluid_rec_mutex_unlock(settings->mutex);
- fluid_rec_mutex_unlock (settings->mutex);
+ return retval;
}
/**
@@ -1334,29 +1604,32 @@ fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
*
* @param settings a settings object
* @param name a setting's name
- * @return the setting's default integer value it it exists, zero otherwise
+ * @param val set to the setting's default integer value if it exists
+ * @return #FLUID_OK if the setting's default integer value exists, #FLUID_FAILED otherwise
*/
-int
-fluid_settings_getint_default(fluid_settings_t* settings, const char *name)
+int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val)
{
- fluid_setting_node_t *node;
- int retval = 0;
+ fluid_setting_node_t *node;
+ int retval = FLUID_FAILED;
- fluid_return_val_if_fail (settings != NULL, 0);
- fluid_return_val_if_fail (name != NULL, 0);
- fluid_return_val_if_fail (name[0] != '\0', 0);
+ fluid_return_val_if_fail(settings != NULL, retval);
+ fluid_return_val_if_fail(name != NULL, retval);
+ fluid_return_val_if_fail(name[0] != '\0', retval);
+ fluid_return_val_if_fail(val != NULL, retval);
- fluid_rec_mutex_lock (settings->mutex);
+ fluid_rec_mutex_lock(settings->mutex);
- if (fluid_settings_get(settings, name, &node)
- && (node->type == FLUID_INT_TYPE)) {
- fluid_int_setting_t* setting = (fluid_int_setting_t*) node;
- retval = setting->def;
- }
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && (node->type == FLUID_INT_TYPE))
+ {
+ fluid_int_setting_t *setting = &node->i;
+ *val = setting->def;
+ retval = FLUID_OK;
+ }
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return retval;
+ return retval;
}
/**
@@ -1368,45 +1641,50 @@ fluid_settings_getint_default(fluid_settings_t* settings, const char *name)
* @param data any user provided pointer
* @param func callback function to be called on each iteration
*
- * NOTE: Starting with FluidSynth 1.1.0 the \a func callback is called for each
+ * @note Starting with FluidSynth 1.1.0 the \a func callback is called for each
* option in alphabetical order. Sort order was undefined in previous versions.
*/
void
-fluid_settings_foreach_option (fluid_settings_t* settings, const char *name,
- void* data, fluid_settings_foreach_option_t func)
+fluid_settings_foreach_option(fluid_settings_t *settings, const char *name,
+ void *data, fluid_settings_foreach_option_t func)
{
- fluid_setting_node_t *node;
- fluid_str_setting_t *setting;
- fluid_list_t *p, *newlist = NULL;
+ fluid_setting_node_t *node;
+ fluid_str_setting_t *setting;
+ fluid_list_t *p, *newlist = NULL;
- fluid_return_if_fail (settings != NULL);
- fluid_return_if_fail (name != NULL);
- fluid_return_if_fail (name[0] != '\0');
- fluid_return_if_fail (func != NULL);
+ fluid_return_if_fail(settings != NULL);
+ fluid_return_if_fail(name != NULL);
+ fluid_return_if_fail(name[0] != '\0');
+ fluid_return_if_fail(func != NULL);
- fluid_rec_mutex_lock (settings->mutex); /* ++ lock */
+ fluid_rec_mutex_lock(settings->mutex); /* ++ lock */
- if (!fluid_settings_get (settings, name, &node) || node->type != FLUID_STR_TYPE)
- {
- fluid_rec_mutex_unlock (settings->mutex); /* -- unlock */
- return;
- }
+ if(fluid_settings_get(settings, name, &node) != FLUID_OK
+ || node->type != FLUID_STR_TYPE)
+ {
+ fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
+ return;
+ }
- setting = (fluid_str_setting_t*)node;
+ setting = &node->str;
- /* Duplicate option list */
- for (p = setting->options; p; p = p->next)
- newlist = fluid_list_append (newlist, fluid_list_get (p));
+ /* Duplicate option list */
+ for(p = setting->options; p; p = p->next)
+ {
+ newlist = fluid_list_append(newlist, fluid_list_get(p));
+ }
- /* Sort by name */
- newlist = fluid_list_sort (newlist, fluid_list_str_compare_func);
+ /* Sort by name */
+ newlist = fluid_list_sort(newlist, fluid_list_str_compare_func);
- for (p = newlist; p; p = p->next)
- (*func)(data, (char *)name, (char *)fluid_list_get (p));
+ for(p = newlist; p; p = p->next)
+ {
+ (*func)(data, name, (const char *)fluid_list_get(p));
+ }
- fluid_rec_mutex_unlock (settings->mutex); /* -- unlock */
+ fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
- delete_fluid_list (newlist);
+ delete_fluid_list(newlist);
}
/**
@@ -1418,21 +1696,26 @@ fluid_settings_foreach_option (fluid_settings_t* settings, const char *name,
* @since 1.1.0
*/
int
-fluid_settings_option_count (fluid_settings_t *settings, const char *name)
+fluid_settings_option_count(fluid_settings_t *settings, const char *name)
{
- fluid_setting_node_t *node;
- int count = -1;
+ fluid_setting_node_t *node;
+ int count = -1;
- fluid_return_val_if_fail (settings != NULL, -1);
- fluid_return_val_if_fail (name != NULL, -1);
- fluid_return_val_if_fail (name[0] != '\0', -1);
+ fluid_return_val_if_fail(settings != NULL, -1);
+ fluid_return_val_if_fail(name != NULL, -1);
+ fluid_return_val_if_fail(name[0] != '\0', -1);
+
+ fluid_rec_mutex_lock(settings->mutex);
+
+ if(fluid_settings_get(settings, name, &node) == FLUID_OK
+ && node->type == FLUID_STR_TYPE)
+ {
+ count = fluid_list_size(node->str.options);
+ }
- fluid_rec_mutex_lock (settings->mutex);
- if (fluid_settings_get(settings, name, &node) && node->type == FLUID_STR_TYPE)
- count = fluid_list_size (((fluid_str_setting_t *)node)->options);
- fluid_rec_mutex_unlock (settings->mutex);
+ fluid_rec_mutex_unlock(settings->mutex);
- return (count);
+ return (count);
}
/**
@@ -1445,113 +1728,136 @@ fluid_settings_option_count (fluid_settings_t *settings, const char *name)
* @since 1.1.0
*/
char *
-fluid_settings_option_concat (fluid_settings_t *settings, const char *name,
- const char *separator)
+fluid_settings_option_concat(fluid_settings_t *settings, const char *name,
+ const char *separator)
{
- fluid_setting_node_t *node;
- fluid_str_setting_t *setting;
- fluid_list_t *p, *newlist = NULL;
- int count, len;
- char *str, *option;
+ fluid_setting_node_t *node;
+ fluid_str_setting_t *setting;
+ fluid_list_t *p, *newlist = NULL;
+ size_t count, len;
+ char *str, *option;
- fluid_return_val_if_fail (settings != NULL, NULL);
- fluid_return_val_if_fail (name != NULL, NULL);
- fluid_return_val_if_fail (name[0] != '\0', NULL);
+ fluid_return_val_if_fail(settings != NULL, NULL);
+ fluid_return_val_if_fail(name != NULL, NULL);
+ fluid_return_val_if_fail(name[0] != '\0', NULL);
- if (!separator) separator = ", ";
+ if(!separator)
+ {
+ separator = ", ";
+ }
- fluid_rec_mutex_lock (settings->mutex); /* ++ lock */
+ fluid_rec_mutex_lock(settings->mutex); /* ++ lock */
- if (!fluid_settings_get (settings, name, &node) || node->type != FLUID_STR_TYPE)
- {
- fluid_rec_mutex_unlock (settings->mutex); /* -- unlock */
- return (NULL);
- }
+ if(fluid_settings_get(settings, name, &node) != FLUID_OK
+ || node->type != FLUID_STR_TYPE)
+ {
+ fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
+ return (NULL);
+ }
- setting = (fluid_str_setting_t*)node;
+ setting = &node->str;
- /* Duplicate option list, count options and get total string length */
- for (p = setting->options, count = 0, len = 0; p; p = p->next, count++)
- {
- option = fluid_list_get (p);
+ /* Duplicate option list, count options and get total string length */
+ for(p = setting->options, count = 0, len = 0; p; p = p->next, count++)
+ {
+ option = fluid_list_get(p);
- if (option)
+ if(option)
+ {
+ newlist = fluid_list_append(newlist, option);
+ len += FLUID_STRLEN(option);
+ }
+ }
+
+ if(count > 1)
{
- newlist = fluid_list_append (newlist, option);
- len += strlen (option);
+ len += (count - 1) * FLUID_STRLEN(separator);
}
- }
- if (count > 1) len += (count - 1) * strlen (separator);
- len++; /* For terminator */
+ len++; /* For terminator */
- /* Sort by name */
- newlist = fluid_list_sort (newlist, fluid_list_str_compare_func);
+ /* Sort by name */
+ newlist = fluid_list_sort(newlist, fluid_list_str_compare_func);
- str = FLUID_MALLOC (len);
+ str = FLUID_MALLOC(len);
- if (str)
- {
- str[0] = 0;
- for (p = newlist; p; p = p->next)
+ if(str)
{
- option = fluid_list_get (p);
- strcat (str, option);
- if (p->next) strcat (str, separator);
+ str[0] = 0;
+
+ for(p = newlist; p; p = p->next)
+ {
+ option = fluid_list_get(p);
+ strcat(str, option);
+
+ if(p->next)
+ {
+ strcat(str, separator);
+ }
+ }
}
- }
- fluid_rec_mutex_unlock (settings->mutex); /* -- unlock */
+ fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
- delete_fluid_list (newlist);
+ delete_fluid_list(newlist);
- if (!str) FLUID_LOG (FLUID_ERR, "Out of memory");
+ if(!str)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ }
- return (str);
+ return (str);
}
/* Structure passed to fluid_settings_foreach_iter recursive function */
typedef struct
{
- char path[MAX_SETTINGS_LABEL+1]; /* Maximum settings label length */
- fluid_list_t *names; /* For fluid_settings_foreach() */
+ char path[MAX_SETTINGS_LABEL + 1]; /* Maximum settings label length */
+ fluid_list_t *names; /* For fluid_settings_foreach() */
} fluid_settings_foreach_bag_t;
static int
-fluid_settings_foreach_iter (void* key, void* value, void* data)
+fluid_settings_foreach_iter(void *key, void *value, void *data)
{
- fluid_settings_foreach_bag_t *bag = data;
- char *keystr = key;
- fluid_setting_node_t *node = value;
- int pathlen;
- char *s;
-
- pathlen = strlen (bag->path);
-
- if (pathlen > 0)
- {
- bag->path[pathlen] = '.';
- bag->path[pathlen + 1] = 0;
- }
-
- strcat (bag->path, keystr);
-
- switch (node->type) {
- case FLUID_NUM_TYPE:
- case FLUID_INT_TYPE:
- case FLUID_STR_TYPE:
- s = FLUID_STRDUP (bag->path);
- if (s) bag->names = fluid_list_append (bag->names, s);
- break;
- case FLUID_SET_TYPE:
- fluid_hashtable_foreach(((fluid_set_setting_t *)value)->hashtable,
- fluid_settings_foreach_iter, bag);
- break;
- }
-
- bag->path[pathlen] = 0;
-
- return 0;
+ fluid_settings_foreach_bag_t *bag = data;
+ char *keystr = key;
+ fluid_setting_node_t *node = value;
+ size_t pathlen;
+ char *s;
+
+ pathlen = FLUID_STRLEN(bag->path);
+
+ if(pathlen > 0)
+ {
+ bag->path[pathlen] = '.';
+ bag->path[pathlen + 1] = 0;
+ }
+
+ strcat(bag->path, keystr);
+
+ switch(node->type)
+ {
+ case FLUID_NUM_TYPE:
+ case FLUID_INT_TYPE:
+ case FLUID_STR_TYPE:
+ s = FLUID_STRDUP(bag->path);
+
+ if(s)
+ {
+ bag->names = fluid_list_append(bag->names, s);
+ }
+
+ break;
+
+ case FLUID_SET_TYPE:
+ fluid_hashtable_foreach(node->set.hashtable,
+ fluid_settings_foreach_iter, bag);
+ break;
+ }
+
+ bag->path[pathlen] = 0;
+
+ return 0;
}
/**
@@ -1562,41 +1868,78 @@ fluid_settings_foreach_iter (void* key, void* value, void* data)
* @param data any user provided pointer
* @param func callback function to be called on each iteration
*
- * NOTE: Starting with FluidSynth 1.1.0 the \a func callback is called for each
+ * @note Starting with FluidSynth 1.1.0 the \a func callback is called for each
* setting in alphabetical order. Sort order was undefined in previous versions.
*/
void
-fluid_settings_foreach (fluid_settings_t* settings, void* data,
- fluid_settings_foreach_t func)
+fluid_settings_foreach(fluid_settings_t *settings, void *data,
+ fluid_settings_foreach_t func)
{
- fluid_settings_foreach_bag_t bag;
- fluid_setting_node_t *node;
- fluid_list_t *p;
- int r;
+ fluid_settings_foreach_bag_t bag;
+ fluid_setting_node_t *node;
+ fluid_list_t *p;
+
+ fluid_return_if_fail(settings != NULL);
+ fluid_return_if_fail(func != NULL);
+
+ bag.path[0] = 0;
+ bag.names = NULL;
+
+ fluid_rec_mutex_lock(settings->mutex);
+
+ /* Add all node names to the bag.names list */
+ fluid_hashtable_foreach(settings, fluid_settings_foreach_iter, &bag);
+
+ /* Sort names */
+ bag.names = fluid_list_sort(bag.names, fluid_list_str_compare_func);
+
+ /* Loop over names and call the callback */
+ for(p = bag.names; p; p = p->next)
+ {
+ if(fluid_settings_get(settings, (const char *)(p->data), &node) == FLUID_OK
+ && node)
+ {
+ (*func)(data, (const char *)(p->data), node->type);
+ }
+
+ FLUID_FREE(p->data); /* -- Free name */
+ }
- fluid_return_if_fail (settings != NULL);
- fluid_return_if_fail (func != NULL);
+ fluid_rec_mutex_unlock(settings->mutex);
- bag.path[0] = 0;
- bag.names = NULL;
+ delete_fluid_list(bag.names); /* -- Free names list */
+}
- fluid_rec_mutex_lock (settings->mutex);
+/**
+ * Split a comma-separated list of integers and fill the passed
+ * in buffer with the parsed values.
+ *
+ * @param str the comma-separated string to split
+ * @param buf user-supplied buffer to hold the parsed numbers
+ * @param buf_len length of user-supplied buffer
+ * @return number of parsed values or -1 on failure
+ */
+int fluid_settings_split_csv(const char *str, int *buf, int buf_len)
+{
+ char *s;
+ char *tok;
+ char *tokstr;
+ int n = 0;
- /* Add all node names to the bag.names list */
- fluid_hashtable_foreach (settings, fluid_settings_foreach_iter, &bag);
+ s = tokstr = FLUID_STRDUP(str);
- /* Sort names */
- bag.names = fluid_list_sort (bag.names, fluid_list_str_compare_func);
+ if(s == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return -1;
+ }
- /* Loop over names and call the callback */
- for (p = bag.names; p; p = p->next)
- {
- r = fluid_settings_get (settings, (char *)(p->data), &node);
- if (r && node) (*func) (data, (char *)(p->data), node->type);
- FLUID_FREE (p->data); /* -- Free name */
- }
+ while((tok = fluid_strtok(&tokstr, ",")) && n < buf_len)
+ {
+ buf[n++] = atoi(tok);
+ }
- fluid_rec_mutex_unlock (settings->mutex);
+ FLUID_FREE(s);
- delete_fluid_list (bag.names); /* -- Free names list */
+ return n;
}
diff --git a/libs/fluidsynth/src/fluid_settings.h b/libs/fluidsynth/src/fluid_settings.h
index 244f0b457b..4a952f1bad 100644
--- a/libs/fluidsynth/src/fluid_settings.h
+++ b/libs/fluidsynth/src/fluid_settings.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -22,35 +22,34 @@
#ifndef _FLUID_SETTINGS_H
#define _FLUID_SETTINGS_H
+int fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s);
+int fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s);
-/** returns 1 if the option was added, 0 otherwise */
-int fluid_settings_add_option(fluid_settings_t* settings, const char* name, const char* s);
+typedef void (*fluid_str_update_t)(void *data, const char *name, const char *value);
-/** returns 1 if the option was added, 0 otherwise */
-int fluid_settings_remove_option(fluid_settings_t* settings, const char* name, const char* s);
+int fluid_settings_register_str(fluid_settings_t *settings, const char *name, const char *def, int hints);
+int fluid_settings_callback_str(fluid_settings_t *settings, const char *name,
+ fluid_str_update_t fun, void *data);
-typedef int (*fluid_num_update_t)(void* data, const char* name, double value);
-typedef int (*fluid_str_update_t)(void* data, const char* name, const char* value);
-typedef int (*fluid_int_update_t)(void* data, const char* name, int value);
+typedef void (*fluid_num_update_t)(void *data, const char *name, double value);
-/** returns 0 if the value has been registered correctly, non-zero
- otherwise */
-int fluid_settings_register_str(fluid_settings_t* settings, const char* name, const char* def, int hints,
- fluid_str_update_t fun, void* data);
+int fluid_settings_register_num(fluid_settings_t *settings, const char *name, double def,
+ double min, double max, int hints);
+int fluid_settings_callback_num(fluid_settings_t *settings, const char *name,
+ fluid_num_update_t fun, void *data);
-/** returns 0 if the value has been registered correctly, non-zero
- otherwise */
-int fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
- double min, double max, int hints,
- fluid_num_update_t fun, void* data);
+/* Type specific wrapper for fluid_settings_getnum */
+int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val);
-/** returns 0 if the value has been registered correctly, non-zero
- otherwise */
-int fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
- int min, int max, int hints,
- fluid_int_update_t fun, void* data);
+typedef void (*fluid_int_update_t)(void *data, const char *name, int value);
+int fluid_settings_register_int(fluid_settings_t *settings, const char *name, int def,
+ int min, int max, int hints);
+int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
+ fluid_int_update_t fun, void *data);
+
+int fluid_settings_split_csv(const char *str, int *buf, int buf_len);
#endif /* _FLUID_SETTINGS_H */
diff --git a/libs/fluidsynth/src/fluid_sffile.c b/libs/fluidsynth/src/fluid_sffile.c
new file mode 100644
index 0000000000..b3e64cc3f4
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_sffile.c
@@ -0,0 +1,2566 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * SoundFont file loading code borrowed from Smurf SoundFont Editor
+ * Copyright (C) 1999-2001 Josh Green
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+#include "fluid_sffile.h"
+#include "fluid_sfont.h"
+#include "fluid_sys.h"
+
+#if LIBSNDFILE_SUPPORT
+#include <sndfile.h>
+#endif
+
+/*=================================sfload.c========================
+ Borrowed from Smurf SoundFont Editor by Josh Green
+ =================================================================*/
+
+/*
+ functions for loading data from sfont files, with appropriate byte swapping
+ on big endian machines. Sfont IDs are not swapped because the ID read is
+ equivalent to the matching ID list in memory regardless of LE/BE machine
+*/
+
+/* sf file chunk IDs */
+enum
+{
+ UNKN_ID,
+ RIFF_ID,
+ LIST_ID,
+ SFBK_ID,
+ INFO_ID,
+ SDTA_ID,
+ PDTA_ID, /* info/sample/preset */
+
+ IFIL_ID,
+ ISNG_ID,
+ INAM_ID,
+ IROM_ID, /* info ids (1st byte of info strings) */
+ IVER_ID,
+ ICRD_ID,
+ IENG_ID,
+ IPRD_ID, /* more info ids */
+ ICOP_ID,
+ ICMT_ID,
+ ISFT_ID, /* and yet more info ids */
+
+ SNAM_ID,
+ SMPL_ID, /* sample ids */
+ PHDR_ID,
+ PBAG_ID,
+ PMOD_ID,
+ PGEN_ID, /* preset ids */
+ IHDR_ID,
+ IBAG_ID,
+ IMOD_ID,
+ IGEN_ID, /* instrument ids */
+ SHDR_ID, /* sample info */
+ SM24_ID
+};
+
+static const char idlist[] = {"RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD"
+ "ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdrsm24"
+ };
+
+
+/* generator types */
+typedef enum
+{
+ Gen_StartAddrOfs,
+ Gen_EndAddrOfs,
+ Gen_StartLoopAddrOfs,
+ Gen_EndLoopAddrOfs,
+ Gen_StartAddrCoarseOfs,
+ Gen_ModLFO2Pitch,
+ Gen_VibLFO2Pitch,
+ Gen_ModEnv2Pitch,
+ Gen_FilterFc,
+ Gen_FilterQ,
+ Gen_ModLFO2FilterFc,
+ Gen_ModEnv2FilterFc,
+ Gen_EndAddrCoarseOfs,
+ Gen_ModLFO2Vol,
+ Gen_Unused1,
+ Gen_ChorusSend,
+ Gen_ReverbSend,
+ Gen_Pan,
+ Gen_Unused2,
+ Gen_Unused3,
+ Gen_Unused4,
+ Gen_ModLFODelay,
+ Gen_ModLFOFreq,
+ Gen_VibLFODelay,
+ Gen_VibLFOFreq,
+ Gen_ModEnvDelay,
+ Gen_ModEnvAttack,
+ Gen_ModEnvHold,
+ Gen_ModEnvDecay,
+ Gen_ModEnvSustain,
+ Gen_ModEnvRelease,
+ Gen_Key2ModEnvHold,
+ Gen_Key2ModEnvDecay,
+ Gen_VolEnvDelay,
+ Gen_VolEnvAttack,
+ Gen_VolEnvHold,
+ Gen_VolEnvDecay,
+ Gen_VolEnvSustain,
+ Gen_VolEnvRelease,
+ Gen_Key2VolEnvHold,
+ Gen_Key2VolEnvDecay,
+ Gen_Instrument,
+ Gen_Reserved1,
+ Gen_KeyRange,
+ Gen_VelRange,
+ Gen_StartLoopAddrCoarseOfs,
+ Gen_Keynum,
+ Gen_Velocity,
+ Gen_Attenuation,
+ Gen_Reserved2,
+ Gen_EndLoopAddrCoarseOfs,
+ Gen_CoarseTune,
+ Gen_FineTune,
+ Gen_SampleId,
+ Gen_SampleModes,
+ Gen_Reserved3,
+ Gen_ScaleTune,
+ Gen_ExclusiveClass,
+ Gen_OverrideRootKey,
+ Gen_Dummy
+} Gen_Type;
+
+#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
+#define Gen_Count Gen_Dummy /* count of generators */
+#define GenArrSize sizeof(SFGenAmount) * Gen_Count /* gen array size */
+
+
+static const unsigned short invalid_inst_gen[] =
+{
+ Gen_Unused1,
+ Gen_Unused2,
+ Gen_Unused3,
+ Gen_Unused4,
+ Gen_Reserved1,
+ Gen_Reserved2,
+ Gen_Reserved3,
+ 0
+};
+
+static const unsigned short invalid_preset_gen[] =
+{
+ Gen_StartAddrOfs,
+ Gen_EndAddrOfs,
+ Gen_StartLoopAddrOfs,
+ Gen_EndLoopAddrOfs,
+ Gen_StartAddrCoarseOfs,
+ Gen_EndAddrCoarseOfs,
+ Gen_StartLoopAddrCoarseOfs,
+ Gen_Keynum,
+ Gen_Velocity,
+ Gen_EndLoopAddrCoarseOfs,
+ Gen_SampleModes,
+ Gen_ExclusiveClass,
+ Gen_OverrideRootKey,
+ 0
+};
+
+
+#define CHNKIDSTR(id) &idlist[(id - 1) * 4]
+
+/* sfont file chunk sizes */
+#define SF_PHDR_SIZE (38)
+#define SF_BAG_SIZE (4)
+#define SF_MOD_SIZE (10)
+#define SF_GEN_SIZE (4)
+#define SF_IHDR_SIZE (22)
+#define SF_SHDR_SIZE (46)
+
+
+#define READCHUNK(sf, var) \
+ do \
+ { \
+ if (sf->fcbs->fread(var, 8, sf->sffd) == FLUID_FAILED) \
+ return FALSE; \
+ ((SFChunk *)(var))->size = FLUID_LE32TOH(((SFChunk *)(var))->size); \
+ } while (0)
+
+#define READD(sf, var) \
+ do \
+ { \
+ uint32_t _temp; \
+ if (sf->fcbs->fread(&_temp, 4, sf->sffd) == FLUID_FAILED) \
+ return FALSE; \
+ var = FLUID_LE32TOH(_temp); \
+ } while (0)
+
+#define READW(sf, var) \
+ do \
+ { \
+ uint16_t _temp; \
+ if (sf->fcbs->fread(&_temp, 2, sf->sffd) == FLUID_FAILED) \
+ return FALSE; \
+ var = FLUID_LE16TOH(_temp); \
+ } while (0)
+
+#define READID(sf, var) \
+ do \
+ { \
+ if (sf->fcbs->fread(var, 4, sf->sffd) == FLUID_FAILED) \
+ return FALSE; \
+ } while (0)
+
+#define READSTR(sf, var) \
+ do \
+ { \
+ if (sf->fcbs->fread(var, 20, sf->sffd) == FLUID_FAILED) \
+ return FALSE; \
+ (*var)[20] = '\0'; \
+ } while (0)
+
+#define READB(sf, var) \
+ do \
+ { \
+ if (sf->fcbs->fread(&var, 1, sf->sffd) == FLUID_FAILED) \
+ return FALSE; \
+ } while (0)
+
+#define FSKIP(sf, size) \
+ do \
+ { \
+ if (sf->fcbs->fseek(sf->sffd, size, SEEK_CUR) == FLUID_FAILED) \
+ return FALSE; \
+ } while (0)
+
+#define FSKIPW(sf) \
+ do \
+ { \
+ if (sf->fcbs->fseek(sf->sffd, 2, SEEK_CUR) == FLUID_FAILED) \
+ return FALSE; \
+ } while (0)
+
+/* removes and advances a fluid_list_t pointer */
+#define SLADVREM(list, item) \
+ do \
+ { \
+ fluid_list_t *_temp = item; \
+ item = fluid_list_next(item); \
+ list = fluid_list_remove_link(list, _temp); \
+ delete1_fluid_list(_temp); \
+ } while (0)
+
+
+static int load_header(SFData *sf);
+static int load_body(SFData *sf);
+static int process_info(SFData *sf, int size);
+static int process_sdta(SFData *sf, unsigned int size);
+static int process_pdta(SFData *sf, int size);
+static int load_phdr(SFData *sf, int size);
+static int load_pbag(SFData *sf, int size);
+static int load_pmod(SFData *sf, int size);
+static int load_pgen(SFData *sf, int size);
+static int load_ihdr(SFData *sf, int size);
+static int load_ibag(SFData *sf, int size);
+static int load_imod(SFData *sf, int size);
+static int load_igen(SFData *sf, int size);
+static int load_shdr(SFData *sf, unsigned int size);
+static int fixup_pgen(SFData *sf);
+static int fixup_igen(SFData *sf);
+
+static int chunkid(unsigned int id);
+static int read_listchunk(SFData *sf, SFChunk *chunk);
+static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size);
+static int preset_compare_func(void *a, void *b);
+static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist);
+static int valid_inst_genid(unsigned short genid);
+static int valid_preset_genid(unsigned short genid);
+
+
+static void delete_preset(SFPreset *preset);
+static void delete_inst(SFInst *inst);
+static void delete_zone(SFZone *zone);
+
+static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);
+static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);
+
+/*
+ * Open a SoundFont file and parse it's contents into a SFData structure.
+ *
+ * @param fname filename
+ * @param fcbs file callback structure
+ * @return the partially parsed SoundFont as SFData structure or NULL on error
+ */
+SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs)
+{
+ SFData *sf;
+ int fsize = 0;
+
+ if(!(sf = FLUID_NEW(SFData)))
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(sf, 0, sizeof(SFData));
+
+ sf->fcbs = fcbs;
+
+ if((sf->sffd = fcbs->fopen(fname)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Unable to open file '%s'", fname);
+ goto error_exit;
+ }
+
+ sf->fname = FLUID_STRDUP(fname);
+
+ if(sf->fname == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_exit;
+ }
+
+ /* get size of file by seeking to end */
+ if(fcbs->fseek(sf->sffd, 0L, SEEK_END) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Seek to end of file failed");
+ goto error_exit;
+ }
+
+ if((fsize = fcbs->ftell(sf->sffd)) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Get end of file position failed");
+ goto error_exit;
+ }
+
+ sf->filesize = fsize;
+
+ if(fcbs->fseek(sf->sffd, 0, SEEK_SET) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Rewind to start of file failed");
+ goto error_exit;
+ }
+
+ if(!load_header(sf))
+ {
+ goto error_exit;
+ }
+
+ return sf;
+
+error_exit:
+ fluid_sffile_close(sf);
+ return NULL;
+}
+
+/*
+ * Parse all preset information from the soundfont
+ *
+ * @return FLUID_OK on success, otherwise FLUID_FAILED
+ */
+int fluid_sffile_parse_presets(SFData *sf)
+{
+ if(!load_body(sf))
+ {
+ return FLUID_FAILED;
+ }
+
+ return FLUID_OK;
+}
+
+/* Load sample data from the soundfont file
+ *
+ * This function will always return the sample data in WAV format. If the sample_type specifies an
+ * Ogg Vorbis compressed sample, it will be decompressed automatically before returning.
+ *
+ * @param sf SFData instance
+ * @param sample_start index of first sample point in Soundfont sample chunk
+ * @param sample_end index of last sample point in Soundfont sample chunk
+ * @param sample_type type of the sample in Soundfont
+ * @param data pointer to sample data pointer, will point to loaded sample data on success
+ * @param data24 pointer to 24-bit sample data pointer if 24-bit data present, will point to loaded
+ * 24-bit sample data on success or NULL if no 24-bit data is present in file
+ *
+ * @return The number of sample words in returned buffers or -1 on failure
+ */
+int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
+ int sample_type, short **data, char **data24)
+{
+ int num_samples;
+
+ if(sample_type & FLUID_SAMPLETYPE_OGG_VORBIS)
+ {
+ num_samples = fluid_sffile_read_vorbis(sf, sample_start, sample_end, data);
+ }
+ else
+ {
+ num_samples = fluid_sffile_read_wav(sf, sample_start, sample_end, data, data24);
+ }
+
+ return num_samples;
+}
+
+/*
+ * Close a SoundFont file and free the SFData structure.
+ *
+ * @param sf pointer to SFData structure
+ * @param fcbs file callback structure
+ */
+void fluid_sffile_close(SFData *sf)
+{
+ fluid_list_t *entry;
+ SFPreset *preset;
+ SFInst *inst;
+
+ if(sf->sffd)
+ {
+ sf->fcbs->fclose(sf->sffd);
+ }
+
+ FLUID_FREE(sf->fname);
+
+ entry = sf->info;
+
+ while(entry)
+ {
+ FLUID_FREE(fluid_list_get(entry));
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(sf->info);
+
+ entry = sf->preset;
+
+ while(entry)
+ {
+ preset = (SFPreset *)fluid_list_get(entry);
+ delete_preset(preset);
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(sf->preset);
+
+ entry = sf->inst;
+
+ while(entry)
+ {
+ inst = (SFInst *)fluid_list_get(entry);
+ delete_inst(inst);
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(sf->inst);
+
+ entry = sf->sample;
+
+ while(entry)
+ {
+ FLUID_FREE(fluid_list_get(entry));
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(sf->sample);
+
+ FLUID_FREE(sf);
+}
+
+
+/*
+ * Private functions
+ */
+
+/* sound font file load functions */
+static int chunkid(unsigned int id)
+{
+ unsigned int i;
+ const unsigned int *p;
+
+ p = (const unsigned int *)&idlist;
+
+ for(i = 0; i < sizeof(idlist) / sizeof(int); i++, p += 1)
+ {
+ if(*p == id)
+ {
+ return (i + 1);
+ }
+ }
+
+ return UNKN_ID;
+}
+
+static int load_header(SFData *sf)
+{
+ SFChunk chunk;
+
+ READCHUNK(sf, &chunk); /* load RIFF chunk */
+
+ if(chunkid(chunk.id) != RIFF_ID)
+ {
+ /* error if not RIFF */
+ FLUID_LOG(FLUID_ERR, "Not a RIFF file");
+ return FALSE;
+ }
+
+ READID(sf, &chunk.id); /* load file ID */
+
+ if(chunkid(chunk.id) != SFBK_ID)
+ {
+ /* error if not SFBK_ID */
+ FLUID_LOG(FLUID_ERR, "Not a SoundFont file");
+ return FALSE;
+ }
+
+ if(chunk.size != sf->filesize - 8)
+ {
+ FLUID_LOG(FLUID_ERR, "SoundFont file size mismatch");
+ return FALSE;
+ }
+
+ /* Process INFO block */
+ if(!read_listchunk(sf, &chunk))
+ {
+ return FALSE;
+ }
+
+ if(chunkid(chunk.id) != INFO_ID)
+ {
+ FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk");
+ return FALSE;
+ }
+
+ if(!process_info(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ /* Process sample chunk */
+ if(!read_listchunk(sf, &chunk))
+ {
+ return FALSE;
+ }
+
+ if(chunkid(chunk.id) != SDTA_ID)
+ {
+ FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk");
+ return FALSE;
+ }
+
+ if(!process_sdta(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ /* process HYDRA chunk */
+ if(!read_listchunk(sf, &chunk))
+ {
+ return FALSE;
+ }
+
+ if(chunkid(chunk.id) != PDTA_ID)
+ {
+ FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk");
+ return FALSE;
+ }
+
+ sf->hydrapos = sf->fcbs->ftell(sf->sffd);
+ sf->hydrasize = chunk.size;
+
+ return TRUE;
+}
+
+static int load_body(SFData *sf)
+{
+ if(sf->fcbs->fseek(sf->sffd, sf->hydrapos, SEEK_SET) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to seek to HYDRA position");
+ return FALSE;
+ }
+
+ if(!process_pdta(sf, sf->hydrasize))
+ {
+ return FALSE;
+ }
+
+ if(!fixup_pgen(sf))
+ {
+ return FALSE;
+ }
+
+ if(!fixup_igen(sf))
+ {
+ return FALSE;
+ }
+
+ /* sort preset list by bank, preset # */
+ sf->preset = fluid_list_sort(sf->preset, (fluid_compare_func_t)preset_compare_func);
+
+ return TRUE;
+}
+
+static int read_listchunk(SFData *sf, SFChunk *chunk)
+{
+ READCHUNK(sf, chunk); /* read list chunk */
+
+ if(chunkid(chunk->id) != LIST_ID) /* error if ! list chunk */
+ {
+ FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse");
+ return FALSE;
+ }
+
+ READID(sf, &chunk->id); /* read id string */
+ chunk->size -= 4;
+ return TRUE;
+}
+
+static int process_info(SFData *sf, int size)
+{
+ SFChunk chunk;
+ unsigned char id;
+ char *item;
+ unsigned short ver;
+
+ while(size > 0)
+ {
+ READCHUNK(sf, &chunk);
+ size -= 8;
+
+ id = chunkid(chunk.id);
+
+ if(id == IFIL_ID)
+ {
+ /* sound font version chunk? */
+ if(chunk.size != 4)
+ {
+ FLUID_LOG(FLUID_ERR, "Sound font version info chunk has invalid size");
+ return FALSE;
+ }
+
+ READW(sf, ver);
+ sf->version.major = ver;
+ READW(sf, ver);
+ sf->version.minor = ver;
+
+ if(sf->version.major < 2)
+ {
+ FLUID_LOG(FLUID_ERR, "Sound font version is %d.%d which is not"
+ " supported, convert to version 2.0x",
+ sf->version.major, sf->version.minor);
+ return FALSE;
+ }
+
+ if(sf->version.major == 3)
+ {
+#if !LIBSNDFILE_SUPPORT
+ FLUID_LOG(FLUID_WARN,
+ "Sound font version is %d.%d but fluidsynth was compiled without"
+ " support for (v3.x)",
+ sf->version.major, sf->version.minor);
+ return FALSE;
+#endif
+ }
+ else if(sf->version.major > 2)
+ {
+ FLUID_LOG(FLUID_WARN,
+ "Sound font version is %d.%d which is newer than"
+ " what this version of fluidsynth was designed for (v2.0x)",
+ sf->version.major, sf->version.minor);
+ return FALSE;
+ }
+ }
+ else if(id == IVER_ID)
+ {
+ /* ROM version chunk? */
+ if(chunk.size != 4)
+ {
+ FLUID_LOG(FLUID_ERR, "ROM version info chunk has invalid size");
+ return FALSE;
+ }
+
+ READW(sf, ver);
+ sf->romver.major = ver;
+ READW(sf, ver);
+ sf->romver.minor = ver;
+ }
+ else if(id != UNKN_ID)
+ {
+ if((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))
+ {
+ FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",
+ &chunk.id, chunk.size);
+ return FALSE;
+ }
+
+ /* alloc for chunk id and da chunk */
+ if(!(item = FLUID_MALLOC(chunk.size + 1)))
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+
+ /* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */
+ sf->info = fluid_list_append(sf->info, item);
+
+ *(unsigned char *)item = id;
+
+ if(sf->fcbs->fread(&item[1], chunk.size, sf->sffd) == FLUID_FAILED)
+ {
+ return FALSE;
+ }
+
+ /* force terminate info item (don't forget uint8 info ID) */
+ *(item + chunk.size) = '\0';
+ }
+ else
+ {
+ FLUID_LOG(FLUID_ERR, "Invalid chunk id in INFO chunk");
+ return FALSE;
+ }
+
+ size -= chunk.size;
+ }
+
+ if(size < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "INFO chunk size mismatch");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int process_sdta(SFData *sf, unsigned int size)
+{
+ SFChunk chunk;
+
+ if(size == 0)
+ {
+ return TRUE; /* no sample data? */
+ }
+
+ /* read sub chunk */
+ READCHUNK(sf, &chunk);
+ size -= 8;
+
+ if(chunkid(chunk.id) != SMPL_ID)
+ {
+ FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead");
+ return FALSE;
+ }
+
+ /* SDTA chunk may also contain sm24 chunk for 24 bit samples
+ * (not yet supported), only an error if SMPL chunk size is
+ * greater than SDTA. */
+ if(chunk.size > size)
+ {
+ FLUID_LOG(FLUID_ERR, "SDTA chunk size mismatch");
+ return FALSE;
+ }
+
+ /* sample data follows */
+ sf->samplepos = sf->fcbs->ftell(sf->sffd);
+
+ /* used to check validity of sample headers */
+ sf->samplesize = chunk.size;
+
+ FSKIP(sf, chunk.size);
+ size -= chunk.size;
+
+ if(sf->version.major >= 2 && sf->version.minor >= 4)
+ {
+ /* any chance to find another chunk here? */
+ if(size > 8)
+ {
+ /* read sub chunk */
+ READCHUNK(sf, &chunk);
+ size -= 8;
+
+ if(chunkid(chunk.id) == SM24_ID)
+ {
+ int sm24size, sdtahalfsize;
+
+ FLUID_LOG(FLUID_DBG, "Found SM24 chunk");
+
+ if(chunk.size > size)
+ {
+ FLUID_LOG(FLUID_WARN, "SM24 exeeds SDTA chunk, ignoring SM24");
+ goto ret; // no error
+ }
+
+ sdtahalfsize = sf->samplesize / 2;
+ /* + 1 byte in the case that half the size of smpl chunk is an odd value */
+ sdtahalfsize += sdtahalfsize % 2;
+ sm24size = chunk.size;
+
+ if(sdtahalfsize != sm24size)
+ {
+ FLUID_LOG(FLUID_WARN, "SM24 not equal to half the size of SMPL chunk (0x%X != "
+ "0x%X), ignoring SM24",
+ sm24size, sdtahalfsize);
+ goto ret; // no error
+ }
+
+ /* sample data24 follows */
+ sf->sample24pos = sf->fcbs->ftell(sf->sffd);
+ sf->sample24size = sm24size;
+ }
+ }
+ }
+
+ret:
+ FSKIP(sf, size);
+
+ return TRUE;
+}
+
+static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size)
+{
+ unsigned int id;
+ const char *expstr;
+
+ expstr = CHNKIDSTR(expid); /* in case we need it */
+
+ READCHUNK(sf, chunk);
+ *size -= 8;
+
+ if((id = chunkid(chunk->id)) != expid)
+ {
+ FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", expstr);
+ return FALSE;
+ }
+
+ if(chunk->size % reclen) /* valid chunk size? */
+ {
+ FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", expstr, reclen);
+ return FALSE;
+ }
+
+ if((*size -= chunk->size) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", expstr);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int process_pdta(SFData *sf, int size)
+{
+ SFChunk chunk;
+
+ if(!pdtahelper(sf, PHDR_ID, SF_PHDR_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_phdr(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, PBAG_ID, SF_BAG_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_pbag(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, PMOD_ID, SF_MOD_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_pmod(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, PGEN_ID, SF_GEN_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_pgen(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, IHDR_ID, SF_IHDR_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_ihdr(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, IBAG_ID, SF_BAG_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_ibag(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, IMOD_ID, SF_MOD_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_imod(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, IGEN_ID, SF_GEN_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_igen(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ if(!pdtahelper(sf, SHDR_ID, SF_SHDR_SIZE, &chunk, &size))
+ {
+ return FALSE;
+ }
+
+ if(!load_shdr(sf, chunk.size))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* preset header loader */
+static int load_phdr(SFData *sf, int size)
+{
+ int i, i2;
+ SFPreset *preset, *prev_preset = NULL;
+ unsigned short pbag_idx, prev_pbag_idx = 0;
+
+ if(size % SF_PHDR_SIZE || size == 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset header chunk size is invalid");
+ return FALSE;
+ }
+
+ i = size / SF_PHDR_SIZE - 1;
+
+ if(i == 0)
+ {
+ /* at least one preset + term record */
+ FLUID_LOG(FLUID_WARN, "File contains no presets");
+ FSKIP(sf, SF_PHDR_SIZE);
+ return TRUE;
+ }
+
+ for(; i > 0; i--)
+ {
+ /* load all preset headers */
+ if((preset = FLUID_NEW(SFPreset)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ sf->preset = fluid_list_append(sf->preset, preset);
+ preset->zone = NULL; /* In case of failure, fluid_sffile_close can cleanup */
+ READSTR(sf, &preset->name); /* possible read failure ^ */
+ READW(sf, preset->prenum);
+ READW(sf, preset->bank);
+ READW(sf, pbag_idx);
+ READD(sf, preset->libr);
+ READD(sf, preset->genre);
+ READD(sf, preset->morph);
+
+ if(prev_preset)
+ {
+ /* not first preset? */
+ if(pbag_idx < prev_pbag_idx)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");
+ return FALSE;
+ }
+
+ i2 = pbag_idx - prev_pbag_idx;
+
+ while(i2--)
+ {
+ prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);
+ }
+ }
+ else if(pbag_idx > 0) /* 1st preset, warn if ofs >0 */
+ {
+ FLUID_LOG(FLUID_WARN, "%d preset zones not referenced, discarding", pbag_idx);
+ }
+
+ prev_preset = preset; /* update preset ptr */
+ prev_pbag_idx = pbag_idx;
+ }
+
+ FSKIP(sf, 24);
+ READW(sf, pbag_idx); /* Read terminal generator index */
+ FSKIP(sf, 12);
+
+ if(pbag_idx < prev_pbag_idx)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");
+ return FALSE;
+ }
+
+ i2 = pbag_idx - prev_pbag_idx;
+
+ while(i2--)
+ {
+ prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);
+ }
+
+ return TRUE;
+}
+
+/* preset bag loader */
+static int load_pbag(SFData *sf, int size)
+{
+ fluid_list_t *p, *p2;
+ SFZone *z, *pz = NULL;
+ unsigned short genndx, modndx;
+ unsigned short pgenndx = 0, pmodndx = 0;
+ unsigned short i;
+
+ if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */
+ {
+ FLUID_LOG(FLUID_ERR, "Preset bag chunk size is invalid");
+ return FALSE;
+ }
+
+ p = sf->preset;
+
+ while(p)
+ {
+ /* traverse through presets */
+ p2 = ((SFPreset *)(p->data))->zone;
+
+ while(p2)
+ {
+ /* traverse preset's zones */
+ if((size -= SF_BAG_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");
+ return FALSE;
+ }
+
+ if((z = FLUID_NEW(SFZone)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ p2->data = z;
+ z->gen = NULL; /* Init gen and mod before possible failure, */
+ z->mod = NULL; /* to ensure proper cleanup (fluid_sffile_close) */
+ READW(sf, genndx); /* possible read failure ^ */
+ READW(sf, modndx);
+ z->instsamp = NULL;
+
+ if(pz)
+ {
+ /* if not first zone */
+ if(genndx < pgenndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");
+ return FALSE;
+ }
+
+ if(modndx < pmodndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");
+ return FALSE;
+ }
+
+ i = genndx - pgenndx;
+
+ while(i--)
+ {
+ pz->gen = fluid_list_prepend(pz->gen, NULL);
+ }
+
+ i = modndx - pmodndx;
+
+ while(i--)
+ {
+ pz->mod = fluid_list_prepend(pz->mod, NULL);
+ }
+ }
+
+ pz = z; /* update previous zone ptr */
+ pgenndx = genndx; /* update previous zone gen index */
+ pmodndx = modndx; /* update previous zone mod index */
+ p2 = fluid_list_next(p2);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ size -= SF_BAG_SIZE;
+
+ if(size != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");
+ return FALSE;
+ }
+
+ READW(sf, genndx);
+ READW(sf, modndx);
+
+ if(!pz)
+ {
+ if(genndx > 0)
+ {
+ FLUID_LOG(FLUID_WARN, "No preset generators and terminal index not 0");
+ }
+
+ if(modndx > 0)
+ {
+ FLUID_LOG(FLUID_WARN, "No preset modulators and terminal index not 0");
+ }
+
+ return TRUE;
+ }
+
+ if(genndx < pgenndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");
+ return FALSE;
+ }
+
+ if(modndx < pmodndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");
+ return FALSE;
+ }
+
+ i = genndx - pgenndx;
+
+ while(i--)
+ {
+ pz->gen = fluid_list_prepend(pz->gen, NULL);
+ }
+
+ i = modndx - pmodndx;
+
+ while(i--)
+ {
+ pz->mod = fluid_list_prepend(pz->mod, NULL);
+ }
+
+ return TRUE;
+}
+
+/* preset modulator loader */
+static int load_pmod(SFData *sf, int size)
+{
+ fluid_list_t *p, *p2, *p3;
+ SFMod *m;
+
+ p = sf->preset;
+
+ while(p)
+ {
+ /* traverse through all presets */
+ p2 = ((SFPreset *)(p->data))->zone;
+
+ while(p2)
+ {
+ /* traverse this preset's zones */
+ p3 = ((SFZone *)(p2->data))->mod;
+
+ while(p3)
+ {
+ /* load zone's modulators */
+ if((size -= SF_MOD_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");
+ return FALSE;
+ }
+
+ if((m = FLUID_NEW(SFMod)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ p3->data = m;
+ READW(sf, m->src);
+ READW(sf, m->dest);
+ READW(sf, m->amount);
+ READW(sf, m->amtsrc);
+ READW(sf, m->trans);
+ p3 = fluid_list_next(p3);
+ }
+
+ p2 = fluid_list_next(p2);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ /*
+ If there isn't even a terminal record
+ Hmmm, the specs say there should be one, but..
+ */
+ if(size == 0)
+ {
+ return TRUE;
+ }
+
+ size -= SF_MOD_SIZE;
+
+ if(size != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");
+ return FALSE;
+ }
+
+ FSKIP(sf, SF_MOD_SIZE); /* terminal mod */
+
+ return TRUE;
+}
+
+/* -------------------------------------------------------------------
+ * preset generator loader
+ * generator (per preset) loading rules:
+ * Zones with no generators or modulators shall be annihilated
+ * Global zone must be 1st zone, discard additional ones (instrumentless zones)
+ *
+ * generator (per zone) loading rules (in order of decreasing precedence):
+ * KeyRange is 1st in list (if exists), else discard
+ * if a VelRange exists only preceded by a KeyRange, else discard
+ * if a generator follows an instrument discard it
+ * if a duplicate generator exists replace previous one
+ * ------------------------------------------------------------------- */
+static int load_pgen(SFData *sf, int size)
+{
+ fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
+ SFZone *z;
+ SFGen *g;
+ SFGenAmount genval;
+ unsigned short genid;
+ int level, skip, drop, gzone, discarded;
+
+ p = sf->preset;
+
+ while(p)
+ {
+ /* traverse through all presets */
+ gzone = FALSE;
+ discarded = FALSE;
+ p2 = ((SFPreset *)(p->data))->zone;
+
+ if(p2)
+ {
+ hz = &p2;
+ }
+
+ while(p2)
+ {
+ /* traverse preset's zones */
+ level = 0;
+ z = (SFZone *)(p2->data);
+ p3 = z->gen;
+
+ while(p3)
+ {
+ /* load zone's generators */
+ dup = NULL;
+ skip = FALSE;
+ drop = FALSE;
+
+ if((size -= SF_GEN_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
+ return FALSE;
+ }
+
+ READW(sf, genid);
+
+ if(genid == Gen_KeyRange)
+ {
+ /* nothing precedes */
+ if(level == 0)
+ {
+ level = 1;
+ READB(sf, genval.range.lo);
+ READB(sf, genval.range.hi);
+ }
+ else
+ {
+ skip = TRUE;
+ }
+ }
+ else if(genid == Gen_VelRange)
+ {
+ /* only KeyRange precedes */
+ if(level <= 1)
+ {
+ level = 2;
+ READB(sf, genval.range.lo);
+ READB(sf, genval.range.hi);
+ }
+ else
+ {
+ skip = TRUE;
+ }
+ }
+ else if(genid == Gen_Instrument)
+ {
+ /* inst is last gen */
+ level = 3;
+ READW(sf, genval.uword);
+ ((SFZone *)(p2->data))->instsamp = FLUID_INT_TO_POINTER(genval.uword + 1);
+ break; /* break out of generator loop */
+ }
+ else
+ {
+ level = 2;
+
+ if(valid_preset_genid(genid))
+ {
+ /* generator valid? */
+ READW(sf, genval.sword);
+ dup = find_gen_by_id(genid, z->gen);
+ }
+ else
+ {
+ skip = TRUE;
+ }
+ }
+
+ if(!skip)
+ {
+ if(!dup)
+ {
+ /* if gen ! dup alloc new */
+ if((g = FLUID_NEW(SFGen)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ p3->data = g;
+ g->id = genid;
+ }
+ else
+ {
+ g = (SFGen *)(dup->data); /* ptr to orig gen */
+ drop = TRUE;
+ }
+
+ g->amount = genval;
+ }
+ else
+ {
+ /* Skip this generator */
+ discarded = TRUE;
+ drop = TRUE;
+ FSKIPW(sf);
+ }
+
+ if(!drop)
+ {
+ p3 = fluid_list_next(p3); /* next gen */
+ }
+ else
+ {
+ SLADVREM(z->gen, p3); /* drop place holder */
+ }
+
+ } /* generator loop */
+
+ if(level == 3)
+ {
+ SLADVREM(z->gen, p3); /* zone has inst? */
+ }
+ else
+ {
+ /* congratulations its a global zone */
+ if(!gzone)
+ {
+ /* Prior global zones? */
+ gzone = TRUE;
+
+ /* if global zone is not 1st zone, relocate */
+ if(*hz != p2)
+ {
+ void *save = p2->data;
+ FLUID_LOG(FLUID_WARN, "Preset '%s': Global zone is not first zone",
+ ((SFPreset *)(p->data))->name);
+ SLADVREM(*hz, p2);
+ *hz = fluid_list_prepend(*hz, save);
+ continue;
+ }
+ }
+ else
+ {
+ /* previous global zone exists, discard */
+ FLUID_LOG(FLUID_WARN, "Preset '%s': Discarding invalid global zone",
+ ((SFPreset *)(p->data))->name);
+ *hz = fluid_list_remove(*hz, p2->data);
+ delete_zone((SFZone *)fluid_list_get(p2));
+ }
+ }
+
+ while(p3)
+ {
+ /* Kill any zones following an instrument */
+ discarded = TRUE;
+
+ if((size -= SF_GEN_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
+ return FALSE;
+ }
+
+ FSKIP(sf, SF_GEN_SIZE);
+ SLADVREM(z->gen, p3);
+ }
+
+ p2 = fluid_list_next(p2); /* next zone */
+ }
+
+ if(discarded)
+ {
+ FLUID_LOG(FLUID_WARN,
+ "Preset '%s': Some invalid generators were discarded",
+ ((SFPreset *)(p->data))->name);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ /* in case there isn't a terminal record */
+ if(size == 0)
+ {
+ return TRUE;
+ }
+
+ size -= SF_GEN_SIZE;
+
+ if(size != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
+ return FALSE;
+ }
+
+ FSKIP(sf, SF_GEN_SIZE); /* terminal gen */
+
+ return TRUE;
+}
+
+/* instrument header loader */
+static int load_ihdr(SFData *sf, int size)
+{
+ int i, i2;
+ SFInst *p, *pr = NULL; /* ptr to current & previous instrument */
+ unsigned short zndx, pzndx = 0;
+
+ if(size % SF_IHDR_SIZE || size == 0) /* chunk size is valid? */
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument header has invalid size");
+ return FALSE;
+ }
+
+ size = size / SF_IHDR_SIZE - 1;
+
+ if(size == 0)
+ {
+ /* at least one preset + term record */
+ FLUID_LOG(FLUID_WARN, "File contains no instruments");
+ FSKIP(sf, SF_IHDR_SIZE);
+ return TRUE;
+ }
+
+ for(i = 0; i < size; i++)
+ {
+ /* load all instrument headers */
+ if((p = FLUID_NEW(SFInst)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ sf->inst = fluid_list_append(sf->inst, p);
+ p->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */
+ p->idx = i;
+ READSTR(sf, &p->name); /* Possible read failure ^ */
+ READW(sf, zndx);
+
+ if(pr)
+ {
+ /* not first instrument? */
+ if(zndx < pzndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");
+ return FALSE;
+ }
+
+ i2 = zndx - pzndx;
+
+ while(i2--)
+ {
+ pr->zone = fluid_list_prepend(pr->zone, NULL);
+ }
+ }
+ else if(zndx > 0) /* 1st inst, warn if ofs >0 */
+ {
+ FLUID_LOG(FLUID_WARN, "%d instrument zones not referenced, discarding", zndx);
+ }
+
+ pzndx = zndx;
+ pr = p; /* update instrument ptr */
+ }
+
+ FSKIP(sf, 20);
+ READW(sf, zndx);
+
+ if(zndx < pzndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");
+ return FALSE;
+ }
+
+ i2 = zndx - pzndx;
+
+ while(i2--)
+ {
+ pr->zone = fluid_list_prepend(pr->zone, NULL);
+ }
+
+ return TRUE;
+}
+
+/* instrument bag loader */
+static int load_ibag(SFData *sf, int size)
+{
+ fluid_list_t *p, *p2;
+ SFZone *z, *pz = NULL;
+ unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0;
+ int i;
+
+ if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument bag chunk size is invalid");
+ return FALSE;
+ }
+
+ p = sf->inst;
+
+ while(p)
+ {
+ /* traverse through inst */
+ p2 = ((SFInst *)(p->data))->zone;
+
+ while(p2)
+ {
+ /* load this inst's zones */
+ if((size -= SF_BAG_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument bag chunk size mismatch");
+ return FALSE;
+ }
+
+ if((z = FLUID_NEW(SFZone)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ p2->data = z;
+ z->gen = NULL; /* In case of failure, */
+ z->mod = NULL; /* fluid_sffile_close can clean up */
+ READW(sf, genndx); /* READW = possible read failure */
+ READW(sf, modndx);
+ z->instsamp = NULL;
+
+ if(pz)
+ {
+ /* if not first zone */
+ if(genndx < pgenndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");
+ return FALSE;
+ }
+
+ if(modndx < pmodndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");
+ return FALSE;
+ }
+
+ i = genndx - pgenndx;
+
+ while(i--)
+ {
+ pz->gen = fluid_list_prepend(pz->gen, NULL);
+ }
+
+ i = modndx - pmodndx;
+
+ while(i--)
+ {
+ pz->mod = fluid_list_prepend(pz->mod, NULL);
+ }
+ }
+
+ pz = z; /* update previous zone ptr */
+ pgenndx = genndx;
+ pmodndx = modndx;
+ p2 = fluid_list_next(p2);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ size -= SF_BAG_SIZE;
+
+ if(size != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument chunk size mismatch");
+ return FALSE;
+ }
+
+ READW(sf, genndx);
+ READW(sf, modndx);
+
+ if(!pz)
+ {
+ /* in case that all are no zoners */
+ if(genndx > 0)
+ {
+ FLUID_LOG(FLUID_WARN, "No instrument generators and terminal index not 0");
+ }
+
+ if(modndx > 0)
+ {
+ FLUID_LOG(FLUID_WARN, "No instrument modulators and terminal index not 0");
+ }
+
+ return TRUE;
+ }
+
+ if(genndx < pgenndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");
+ return FALSE;
+ }
+
+ if(modndx < pmodndx)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");
+ return FALSE;
+ }
+
+ i = genndx - pgenndx;
+
+ while(i--)
+ {
+ pz->gen = fluid_list_prepend(pz->gen, NULL);
+ }
+
+ i = modndx - pmodndx;
+
+ while(i--)
+ {
+ pz->mod = fluid_list_prepend(pz->mod, NULL);
+ }
+
+ return TRUE;
+}
+
+/* instrument modulator loader */
+static int load_imod(SFData *sf, int size)
+{
+ fluid_list_t *p, *p2, *p3;
+ SFMod *m;
+
+ p = sf->inst;
+
+ while(p)
+ {
+ /* traverse through all inst */
+ p2 = ((SFInst *)(p->data))->zone;
+
+ while(p2)
+ {
+ /* traverse this inst's zones */
+ p3 = ((SFZone *)(p2->data))->mod;
+
+ while(p3)
+ {
+ /* load zone's modulators */
+ if((size -= SF_MOD_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");
+ return FALSE;
+ }
+
+ if((m = FLUID_NEW(SFMod)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ p3->data = m;
+ READW(sf, m->src);
+ READW(sf, m->dest);
+ READW(sf, m->amount);
+ READW(sf, m->amtsrc);
+ READW(sf, m->trans);
+ p3 = fluid_list_next(p3);
+ }
+
+ p2 = fluid_list_next(p2);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ /*
+ If there isn't even a terminal record
+ Hmmm, the specs say there should be one, but..
+ */
+ if(size == 0)
+ {
+ return TRUE;
+ }
+
+ size -= SF_MOD_SIZE;
+
+ if(size != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");
+ return FALSE;
+ }
+
+ FSKIP(sf, SF_MOD_SIZE); /* terminal mod */
+
+ return TRUE;
+}
+
+/* load instrument generators (see load_pgen for loading rules) */
+static int load_igen(SFData *sf, int size)
+{
+ fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
+ SFZone *z;
+ SFGen *g;
+ SFGenAmount genval;
+ unsigned short genid;
+ int level, skip, drop, gzone, discarded;
+
+ p = sf->inst;
+
+ while(p)
+ {
+ /* traverse through all instruments */
+ gzone = FALSE;
+ discarded = FALSE;
+ p2 = ((SFInst *)(p->data))->zone;
+
+ if(p2)
+ {
+ hz = &p2;
+ }
+
+ while(p2)
+ {
+ /* traverse this instrument's zones */
+ level = 0;
+ z = (SFZone *)(p2->data);
+ p3 = z->gen;
+
+ while(p3)
+ {
+ /* load zone's generators */
+ dup = NULL;
+ skip = FALSE;
+ drop = FALSE;
+
+ if((size -= SF_GEN_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");
+ return FALSE;
+ }
+
+ READW(sf, genid);
+
+ if(genid == Gen_KeyRange)
+ {
+ /* nothing precedes */
+ if(level == 0)
+ {
+ level = 1;
+ READB(sf, genval.range.lo);
+ READB(sf, genval.range.hi);
+ }
+ else
+ {
+ skip = TRUE;
+ }
+ }
+ else if(genid == Gen_VelRange)
+ {
+ /* only KeyRange precedes */
+ if(level <= 1)
+ {
+ level = 2;
+ READB(sf, genval.range.lo);
+ READB(sf, genval.range.hi);
+ }
+ else
+ {
+ skip = TRUE;
+ }
+ }
+ else if(genid == Gen_SampleId)
+ {
+ /* sample is last gen */
+ level = 3;
+ READW(sf, genval.uword);
+ ((SFZone *)(p2->data))->instsamp = FLUID_INT_TO_POINTER(genval.uword + 1);
+ break; /* break out of generator loop */
+ }
+ else
+ {
+ level = 2;
+
+ if(valid_inst_genid(genid))
+ {
+ /* gen valid? */
+ READW(sf, genval.sword);
+ dup = find_gen_by_id(genid, z->gen);
+ }
+ else
+ {
+ skip = TRUE;
+ }
+ }
+
+ if(!skip)
+ {
+ if(!dup)
+ {
+ /* if gen ! dup alloc new */
+ if((g = FLUID_NEW(SFGen)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ p3->data = g;
+ g->id = genid;
+ }
+ else
+ {
+ g = (SFGen *)(dup->data);
+ drop = TRUE;
+ }
+
+ g->amount = genval;
+ }
+ else
+ {
+ /* skip this generator */
+ discarded = TRUE;
+ drop = TRUE;
+ FSKIPW(sf);
+ }
+
+ if(!drop)
+ {
+ p3 = fluid_list_next(p3); /* next gen */
+ }
+ else
+ {
+ SLADVREM(z->gen, p3);
+ }
+
+ } /* generator loop */
+
+ if(level == 3)
+ {
+ SLADVREM(z->gen, p3); /* zone has sample? */
+ }
+ else
+ {
+ /* its a global zone */
+ if(!gzone)
+ {
+ gzone = TRUE;
+
+ /* if global zone is not 1st zone, relocate */
+ if(*hz != p2)
+ {
+ void *save = p2->data;
+ FLUID_LOG(FLUID_WARN, "Instrument '%s': Global zone is not first zone",
+ ((SFPreset *)(p->data))->name);
+ SLADVREM(*hz, p2);
+ *hz = fluid_list_prepend(*hz, save);
+ continue;
+ }
+ }
+ else
+ {
+ /* previous global zone exists, discard */
+ FLUID_LOG(FLUID_WARN, "Instrument '%s': Discarding invalid global zone",
+ ((SFInst *)(p->data))->name);
+ *hz = fluid_list_remove(*hz, p2->data);
+ delete_zone((SFZone *)fluid_list_get(p2));
+ }
+ }
+
+ while(p3)
+ {
+ /* Kill any zones following a sample */
+ discarded = TRUE;
+
+ if((size -= SF_GEN_SIZE) < 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument generator chunk size mismatch");
+ return FALSE;
+ }
+
+ FSKIP(sf, SF_GEN_SIZE);
+ SLADVREM(z->gen, p3);
+ }
+
+ p2 = fluid_list_next(p2); /* next zone */
+ }
+
+ if(discarded)
+ {
+ FLUID_LOG(FLUID_WARN,
+ "Instrument '%s': Some invalid generators were discarded",
+ ((SFInst *)(p->data))->name);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ /* for those non-terminal record cases, grr! */
+ if(size == 0)
+ {
+ return TRUE;
+ }
+
+ size -= SF_GEN_SIZE;
+
+ if(size != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");
+ return FALSE;
+ }
+
+ FSKIP(sf, SF_GEN_SIZE); /* terminal gen */
+
+ return TRUE;
+}
+
+/* sample header loader */
+static int load_shdr(SFData *sf, unsigned int size)
+{
+ unsigned int i;
+ SFSample *p;
+
+ if(size % SF_SHDR_SIZE || size == 0) /* size is multiple of SHDR size? */
+ {
+ FLUID_LOG(FLUID_ERR, "Sample header has invalid size");
+ return FALSE;
+ }
+
+ size = size / SF_SHDR_SIZE - 1;
+
+ if(size == 0)
+ {
+ /* at least one sample + term record? */
+ FLUID_LOG(FLUID_WARN, "File contains no samples");
+ FSKIP(sf, SF_SHDR_SIZE);
+ return TRUE;
+ }
+
+ /* load all sample headers */
+ for(i = 0; i < size; i++)
+ {
+ if((p = FLUID_NEW(SFSample)) == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FALSE;
+ }
+ sf->sample = fluid_list_append(sf->sample, p);
+ READSTR(sf, &p->name);
+ READD(sf, p->start);
+ READD(sf, p->end);
+ READD(sf, p->loopstart);
+ READD(sf, p->loopend);
+ READD(sf, p->samplerate);
+ READB(sf, p->origpitch);
+ READB(sf, p->pitchadj);
+ FSKIPW(sf); /* skip sample link */
+ READW(sf, p->sampletype);
+ p->samfile = 0;
+ }
+
+ FSKIP(sf, SF_SHDR_SIZE); /* skip terminal shdr */
+
+ return TRUE;
+}
+
+/* "fixup" (inst # -> inst ptr) instrument references in preset list */
+static int fixup_pgen(SFData *sf)
+{
+ fluid_list_t *p, *p2, *p3;
+ SFZone *z;
+ int i;
+
+ p = sf->preset;
+
+ while(p)
+ {
+ p2 = ((SFPreset *)(p->data))->zone;
+
+ while(p2)
+ {
+ /* traverse this preset's zones */
+ z = (SFZone *)(p2->data);
+
+ if((i = FLUID_POINTER_TO_INT(z->instsamp)))
+ {
+ /* load instrument # */
+ p3 = fluid_list_nth(sf->inst, i - 1);
+
+ if(!p3)
+ {
+ FLUID_LOG(FLUID_ERR, "Preset %03d %03d: Invalid instrument reference",
+ ((SFPreset *)(p->data))->bank, ((SFPreset *)(p->data))->prenum);
+ return FALSE;
+ }
+
+ z->instsamp = p3;
+ }
+ else
+ {
+ z->instsamp = NULL;
+ }
+
+ p2 = fluid_list_next(p2);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ return TRUE;
+}
+
+/* "fixup" (sample # -> sample ptr) sample references in instrument list */
+static int fixup_igen(SFData *sf)
+{
+ fluid_list_t *p, *p2, *p3;
+ SFZone *z;
+ int i;
+
+ p = sf->inst;
+
+ while(p)
+ {
+ p2 = ((SFInst *)(p->data))->zone;
+
+ while(p2)
+ {
+ /* traverse instrument's zones */
+ z = (SFZone *)(p2->data);
+
+ if((i = FLUID_POINTER_TO_INT(z->instsamp)))
+ {
+ /* load sample # */
+ p3 = fluid_list_nth(sf->sample, i - 1);
+
+ if(!p3)
+ {
+ FLUID_LOG(FLUID_ERR, "Instrument '%s': Invalid sample reference",
+ ((SFInst *)(p->data))->name);
+ return FALSE;
+ }
+
+ z->instsamp = p3;
+ }
+
+ p2 = fluid_list_next(p2);
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ return TRUE;
+}
+
+static void delete_preset(SFPreset *preset)
+{
+ fluid_list_t *entry;
+ SFZone *zone;
+
+ if(!preset)
+ {
+ return;
+ }
+
+ entry = preset->zone;
+
+ while(entry)
+ {
+ zone = (SFZone *)fluid_list_get(entry);
+ delete_zone(zone);
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(preset->zone);
+
+ FLUID_FREE(preset);
+}
+
+static void delete_inst(SFInst *inst)
+{
+ fluid_list_t *entry;
+ SFZone *zone;
+
+ if(!inst)
+ {
+ return;
+ }
+
+ entry = inst->zone;
+
+ while(entry)
+ {
+ zone = (SFZone *)fluid_list_get(entry);
+ delete_zone(zone);
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(inst->zone);
+
+ FLUID_FREE(inst);
+}
+
+
+/* Free all elements of a zone (Preset or Instrument) */
+static void delete_zone(SFZone *zone)
+{
+ fluid_list_t *entry;
+
+ if(!zone)
+ {
+ return;
+ }
+
+ entry = zone->gen;
+
+ while(entry)
+ {
+ FLUID_FREE(fluid_list_get(entry));
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(zone->gen);
+
+ entry = zone->mod;
+
+ while(entry)
+ {
+ FLUID_FREE(fluid_list_get(entry));
+ entry = fluid_list_next(entry);
+ }
+
+ delete_fluid_list(zone->mod);
+
+ FLUID_FREE(zone);
+}
+
+/* preset sort function, first by bank, then by preset # */
+static int preset_compare_func(void *a, void *b)
+{
+ int aval, bval;
+
+ aval = (int)(((SFPreset *)a)->bank) << 16 | ((SFPreset *)a)->prenum;
+ bval = (int)(((SFPreset *)b)->bank) << 16 | ((SFPreset *)b)->prenum;
+
+ return (aval - bval);
+}
+
+/* Find a generator by its id in the passed in list.
+ *
+ * @return pointer to SFGen if found, otherwise NULL
+ */
+static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist)
+{
+ /* is generator in gen list? */
+ fluid_list_t *p;
+
+ p = genlist;
+
+ while(p)
+ {
+ if(p->data == NULL)
+ {
+ return NULL;
+ }
+
+ if(gen == ((SFGen *)p->data)->id)
+ {
+ break;
+ }
+
+ p = fluid_list_next(p);
+ }
+
+ return p;
+}
+
+/* check validity of instrument generator */
+static int valid_inst_genid(unsigned short genid)
+{
+ int i = 0;
+
+ if(genid > Gen_MaxValid)
+ {
+ return FALSE;
+ }
+
+ while(invalid_inst_gen[i] && invalid_inst_gen[i] != genid)
+ {
+ i++;
+ }
+
+ return (invalid_inst_gen[i] == 0);
+}
+
+/* check validity of preset generator */
+static int valid_preset_genid(unsigned short genid)
+{
+ int i = 0;
+
+ if(!valid_inst_genid(genid))
+ {
+ return FALSE;
+ }
+
+ while(invalid_preset_gen[i] && invalid_preset_gen[i] != genid)
+ {
+ i++;
+ }
+
+ return (invalid_preset_gen[i] == 0);
+}
+
+
+static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24)
+{
+ short *loaded_data = NULL;
+ char *loaded_data24 = NULL;
+
+ int num_samples = (end + 1) - start;
+ fluid_return_val_if_fail(num_samples > 0, -1);
+
+ if((start * sizeof(short) > sf->samplesize) || (end * sizeof(short) > sf->samplesize))
+ {
+ FLUID_LOG(FLUID_ERR, "Sample offsets exceed sample data chunk");
+ goto error_exit;
+ }
+
+ /* Load 16-bit sample data */
+ if(sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * sizeof(short)), SEEK_SET) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to seek to sample position");
+ goto error_exit;
+ }
+
+ loaded_data = FLUID_ARRAY(short, num_samples);
+
+ if(loaded_data == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_exit;
+ }
+
+ if(sf->fcbs->fread(loaded_data, num_samples * sizeof(short), sf->sffd) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to read sample data");
+ goto error_exit;
+ }
+
+ /* If this machine is big endian, byte swap the 16 bit samples */
+ if(FLUID_IS_BIG_ENDIAN)
+ {
+ int i;
+
+ for(i = 0; i < num_samples; i++)
+ {
+ loaded_data[i] = FLUID_LE16TOH(loaded_data[i]);
+ }
+ }
+
+ *data = loaded_data;
+
+ /* Optionally load additional 8 bit sample data for 24-bit support. Any failures while loading
+ * the 24-bit sample data will be logged as errors but won't prevent the sample reading to
+ * fail, as sound output is still possible with the 16-bit sample data. */
+ if(sf->sample24pos)
+ {
+ if((start > sf->sample24size) || (end > sf->sample24size))
+ {
+ FLUID_LOG(FLUID_ERR, "Sample offsets exceed 24-bit sample data chunk");
+ goto error24_exit;
+ }
+
+ if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file");
+ goto error24_exit;
+ }
+
+ loaded_data24 = FLUID_ARRAY(char, num_samples);
+
+ if(loaded_data24 == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data");
+ goto error24_exit;
+ }
+
+ if(sf->fcbs->fread(loaded_data24, num_samples, sf->sffd) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data");
+ goto error24_exit;
+ }
+ }
+
+ *data24 = loaded_data24;
+
+ return num_samples;
+
+error24_exit:
+ FLUID_LOG(FLUID_WARN, "Ignoring 24-bit sample data, sound quality might suffer");
+ FLUID_FREE(loaded_data24);
+ *data24 = NULL;
+ return num_samples;
+
+error_exit:
+ FLUID_FREE(loaded_data);
+ FLUID_FREE(loaded_data24);
+ return -1;
+}
+
+
+/* Ogg Vorbis loading and decompression */
+#if LIBSNDFILE_SUPPORT
+
+/* Virtual file access rountines to allow loading individually compressed
+ * samples from the Soundfont sample data chunk using the file callbacks
+ * passing in during opening of the file */
+typedef struct _sfvio_data_t
+{
+ SFData *sffile;
+ sf_count_t start; /* start byte offset of compressed data */
+ sf_count_t end; /* end byte offset of compressed data */
+ sf_count_t offset; /* current virtual file offset from start byte offset */
+
+} sfvio_data_t;
+
+static sf_count_t sfvio_get_filelen(void *user_data)
+{
+ sfvio_data_t *data = user_data;
+
+ return (data->end + 1) - data->start;
+}
+
+static sf_count_t sfvio_seek(sf_count_t offset, int whence, void *user_data)
+{
+ sfvio_data_t *data = user_data;
+ SFData *sf = data->sffile;
+ sf_count_t new_offset;
+
+ switch(whence)
+ {
+ case SEEK_SET:
+ new_offset = offset;
+ break;
+
+ case SEEK_CUR:
+ new_offset = data->offset + offset;
+ break;
+
+ case SEEK_END:
+ new_offset = sfvio_get_filelen(user_data) + offset;
+ break;
+
+ default:
+ goto fail; /* proper error handling not possible?? */
+ }
+
+ if(sf->fcbs->fseek(sf->sffd, sf->samplepos + data->start + new_offset, SEEK_SET) != FLUID_FAILED)
+ {
+ data->offset = new_offset;
+ }
+
+fail:
+ return data->offset;
+}
+
+static sf_count_t sfvio_read(void *ptr, sf_count_t count, void *user_data)
+{
+ sfvio_data_t *data = user_data;
+ SFData *sf = data->sffile;
+ sf_count_t remain;
+
+ remain = sfvio_get_filelen(user_data) - data->offset;
+
+ if(count > remain)
+ {
+ count = remain;
+ }
+
+ if(count == 0)
+ {
+ return count;
+ }
+
+ if(sf->fcbs->fread(ptr, count, sf->sffd) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to read compressed sample data");
+ return 0;
+ }
+
+ data->offset += count;
+
+ return count;
+}
+
+static sf_count_t sfvio_tell(void *user_data)
+{
+ sfvio_data_t *data = user_data;
+
+ return data->offset;
+}
+
+/**
+ * Read Ogg Vorbis compressed data from the Soundfont and decompress it, returning the number of samples
+ * in the decompressed WAV. Only 16-bit mono samples are supported.
+ *
+ * Note that this function takes byte indices for start and end source data. The sample headers in SF3
+ * files use byte indices, so those pointers can be passed directly to this function.
+ *
+ * This function uses a virtual file structure in order to read the Ogg Vorbis
+ * data from arbitrary locations in the source file.
+ */
+static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)
+{
+ SNDFILE *sndfile;
+ SF_INFO sfinfo;
+ SF_VIRTUAL_IO sfvio =
+ {
+ sfvio_get_filelen,
+ sfvio_seek,
+ sfvio_read,
+ NULL,
+ sfvio_tell
+ };
+ sfvio_data_t sfdata;
+ short *wav_data = NULL;
+
+ if((start_byte > sf->samplesize) || (end_byte > sf->samplesize))
+ {
+ FLUID_LOG(FLUID_ERR, "Ogg Vorbis data offsets exceed sample data chunk");
+ return -1;
+ }
+
+ // Initialize file position indicator and SF_INFO structure
+ sfdata.sffile = sf;
+ sfdata.start = start_byte;
+ sfdata.end = end_byte;
+ sfdata.offset = 0;
+
+ memset(&sfinfo, 0, sizeof(sfinfo));
+
+ /* Seek to beginning of Ogg Vorbis data in Soundfont */
+ if(sf->fcbs->fseek(sf->sffd, sf->samplepos + start_byte, SEEK_SET) == FLUID_FAILED)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to seek to compressd sample position");
+ return -1;
+ }
+
+ // Open sample as a virtual file
+ sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, &sfdata);
+
+ if(!sndfile)
+ {
+ FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
+ return -1;
+ }
+
+ // Empty sample
+ if(!sfinfo.frames || !sfinfo.channels)
+ {
+ FLUID_LOG(FLUID_DBG, "Empty decompressed sample");
+ *data = NULL;
+ sf_close(sndfile);
+ return 0;
+ }
+
+ /* FIXME: ensure that the decompressed WAV data is 16-bit mono? */
+
+ wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels);
+
+ if(!wav_data)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_exit;
+ }
+
+ /* Automatically decompresses the Ogg Vorbis data to 16-bit WAV */
+ if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames)
+ {
+ FLUID_LOG(FLUID_DBG, "Decompression failed!");
+ FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
+ goto error_exit;
+ }
+
+ sf_close(sndfile);
+
+ *data = wav_data;
+
+ return sfinfo.frames;
+
+error_exit:
+ FLUID_FREE(wav_data);
+ sf_close(sndfile);
+ return -1;
+}
+#else
+static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)
+{
+ return -1;
+}
+#endif
diff --git a/libs/fluidsynth/src/fluid_sffile.h b/libs/fluidsynth/src/fluid_sffile.h
new file mode 100644
index 0000000000..0c315c73b6
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_sffile.h
@@ -0,0 +1,230 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+#ifndef _FLUID_SFFILE_H
+#define _FLUID_SFFILE_H
+
+
+#include "fluid_gen.h"
+#include "fluid_list.h"
+#include "fluid_mod.h"
+#include "fluidsynth.h"
+#include "fluidsynth_priv.h"
+
+
+/* Sound Font structure defines */
+
+/* Forward declarations */
+typedef union _SFGenAmount SFGenAmount;
+typedef struct _SFVersion SFVersion;
+typedef struct _SFMod SFMod;
+typedef struct _SFGen SFGen;
+typedef struct _SFZone SFZone;
+typedef struct _SFSample SFSample;
+typedef struct _SFInst SFInst;
+typedef struct _SFPreset SFPreset;
+typedef struct _SFData SFData;
+typedef struct _SFChunk SFChunk;
+typedef struct _SFPhdr SFPhdr;
+typedef struct _SFBag SFBag;
+typedef struct _SFIhdr SFIhdr;
+typedef struct _SFShdr SFShdr;
+
+
+struct _SFVersion
+{
+ /* version structure */
+ unsigned short major;
+ unsigned short minor;
+};
+
+struct _SFMod
+{
+ /* Modulator structure */
+ unsigned short src; /* source modulator */
+ unsigned short dest; /* destination generator */
+ signed short amount; /* signed, degree of modulation */
+ unsigned short amtsrc; /* second source controls amnt of first */
+ unsigned short trans; /* transform applied to source */
+};
+
+union _SFGenAmount /* Generator amount structure */
+{
+ signed short sword; /* signed 16 bit value */
+ unsigned short uword; /* unsigned 16 bit value */
+ struct
+ {
+ unsigned char lo; /* low value for ranges */
+ unsigned char hi; /* high value for ranges */
+ } range;
+};
+
+struct _SFGen
+{
+ /* Generator structure */
+ unsigned short id; /* generator ID */
+ SFGenAmount amount; /* generator value */
+};
+
+struct _SFZone
+{
+ /* Sample/instrument zone structure */
+ fluid_list_t *instsamp; /* instrument/sample pointer for zone */
+ fluid_list_t *gen; /* list of generators */
+ fluid_list_t *mod; /* list of modulators */
+};
+
+struct _SFSample
+{
+ /* Sample structure */
+ char name[21]; /* Name of sample */
+ unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
+ unsigned int start; /* Offset in sample area to start of sample */
+ unsigned int end; /* Offset from start to end of sample,
+ this is the last point of the
+ sample, the SF spec has this as the
+ 1st point after, corrected on
+ load/save */
+ unsigned int loopstart; /* Offset from start to start of loop */
+ unsigned int loopend; /* Offset from start to end of loop,
+ marks the first point after loop,
+ whose sample value is ideally
+ equivalent to loopstart */
+ unsigned int samplerate; /* Sample rate recorded at */
+ unsigned char origpitch; /* root midi key number */
+ signed char pitchadj; /* pitch correction in cents */
+ unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
+ fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */
+};
+
+struct _SFInst
+{
+ /* Instrument structure */
+ char name[21]; /* Name of instrument */
+ int idx; /* Index of this instrument in the Soundfont */
+ fluid_list_t *zone; /* list of instrument zones */
+};
+
+struct _SFPreset
+{
+ /* Preset structure */
+ char name[21]; /* preset name */
+ unsigned short prenum; /* preset number */
+ unsigned short bank; /* bank number */
+ unsigned int libr; /* Not used (preserved) */
+ unsigned int genre; /* Not used (preserved) */
+ unsigned int morph; /* Not used (preserved) */
+ fluid_list_t *zone; /* list of preset zones */
+};
+
+/* NOTE: sffd is also used to determine if sound font is new (NULL) */
+struct _SFData
+{
+ /* Sound font data structure */
+ SFVersion version; /* sound font version */
+ SFVersion romver; /* ROM version */
+
+ unsigned int filesize;
+
+ unsigned int samplepos; /* position within sffd of the sample chunk */
+ unsigned int samplesize; /* length within sffd of the sample chunk */
+
+ unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit
+ sample support */
+ unsigned int sample24size; /* length within sffd of the sm24 chunk */
+
+ unsigned int hydrapos;
+ unsigned int hydrasize;
+
+ char *fname; /* file name */
+ FILE *sffd; /* loaded sfont file descriptor */
+ const fluid_file_callbacks_t *fcbs; /* file callbacks used to read this file */
+
+ fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
+ fluid_list_t *preset; /* linked list of preset info */
+ fluid_list_t *inst; /* linked list of instrument info */
+ fluid_list_t *sample; /* linked list of sample info */
+};
+
+/* functions */
+
+
+/*-----------------------------------sffile.h----------------------------*/
+/*
+ File structures and routines (used to be in sffile.h)
+*/
+
+/* sfont file data structures */
+struct _SFChunk
+{
+ /* RIFF file chunk structure */
+ unsigned int id; /* chunk id */
+ unsigned int size; /* size of the following chunk */
+};
+
+struct _SFPhdr
+{
+ unsigned char name[20]; /* preset name */
+ unsigned short preset; /* preset number */
+ unsigned short bank; /* bank number */
+ unsigned short pbagndx; /* index into preset bag */
+ unsigned int library; /* just for preserving them */
+ unsigned int genre; /* Not used */
+ unsigned int morphology; /* Not used */
+};
+
+struct _SFBag
+{
+ unsigned short genndx; /* index into generator list */
+ unsigned short modndx; /* index into modulator list */
+};
+
+struct _SFIhdr
+{
+ char name[20]; /* Name of instrument */
+ unsigned short ibagndx; /* Instrument bag index */
+};
+
+struct _SFShdr
+{
+ /* Sample header loading struct */
+ char name[20]; /* Sample name */
+ unsigned int start; /* Offset to start of sample */
+ unsigned int end; /* Offset to end of sample */
+ unsigned int loopstart; /* Offset to start of loop */
+ unsigned int loopend; /* Offset to end of loop */
+ unsigned int samplerate; /* Sample rate recorded at */
+ unsigned char origpitch; /* root midi key number */
+ signed char pitchadj; /* pitch correction in cents */
+ unsigned short samplelink; /* Not used */
+ unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
+};
+
+/* Public functions */
+SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs);
+void fluid_sffile_close(SFData *sf);
+int fluid_sffile_parse_presets(SFData *sf);
+int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
+ int sample_type, short **data, char **data24);
+
+#endif /* _FLUID_SFFILE_H */
diff --git a/libs/fluidsynth/src/fluid_sfont.c b/libs/fluidsynth/src/fluid_sfont.c
new file mode 100644
index 0000000000..405bec6c64
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_sfont.c
@@ -0,0 +1,784 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include "fluid_sfont.h"
+#include "fluid_sys.h"
+
+
+void *default_fopen(const char *path)
+{
+ return FLUID_FOPEN(path, "rb");
+}
+
+int default_fclose(void *handle)
+{
+ return FLUID_FCLOSE((FILE *)handle) == 0 ? FLUID_OK : FLUID_FAILED;
+}
+
+long default_ftell(void *handle)
+{
+ return FLUID_FTELL((FILE *)handle);
+}
+
+int safe_fread(void *buf, int count, void *fd)
+{
+ if(FLUID_FREAD(buf, count, 1, (FILE *)fd) != 1)
+ {
+ if(feof((FILE *)fd))
+ {
+ FLUID_LOG(FLUID_ERR, "EOF while attemping to read %d bytes", count);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_ERR, "File read failed");
+ }
+
+ return FLUID_FAILED;
+ }
+
+ return FLUID_OK;
+}
+
+int safe_fseek(void *fd, long ofs, int whence)
+{
+ if(FLUID_FSEEK((FILE *)fd, ofs, whence) != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "File seek failed with offset = %ld and whence = %d", ofs, whence);
+ return FLUID_FAILED;
+ }
+
+ return FLUID_OK;
+}
+
+/**
+ * Creates a new SoundFont loader.
+ *
+ * @param load Pointer to a function that provides a #fluid_sfont_t (see #fluid_sfloader_load_t).
+ * @param free Pointer to a function that destroys this instance (see #fluid_sfloader_free_t).
+ * Unless any private data needs to be freed it is sufficient to set this to delete_fluid_sfloader().
+ *
+ * @return the SoundFont loader instance on success, NULL otherwise.
+ */
+fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free)
+{
+ fluid_sfloader_t *loader;
+
+ fluid_return_val_if_fail(load != NULL, NULL);
+ fluid_return_val_if_fail(free != NULL, NULL);
+
+ loader = FLUID_NEW(fluid_sfloader_t);
+
+ if(loader == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(loader, 0, sizeof(*loader));
+
+ loader->load = load;
+ loader->free = free;
+ fluid_sfloader_set_callbacks(loader,
+ default_fopen,
+ safe_fread,
+ safe_fseek,
+ default_ftell,
+ default_fclose);
+
+ return loader;
+}
+
+/**
+ * Frees a SoundFont loader created with new_fluid_sfloader().
+ *
+ * @param loader The SoundFont loader instance to free.
+ */
+void delete_fluid_sfloader(fluid_sfloader_t *loader)
+{
+ fluid_return_if_fail(loader != NULL);
+
+ FLUID_FREE(loader);
+}
+
+/**
+ * Specify private data to be used by #fluid_sfloader_load_t.
+ *
+ * @param loader The SoundFont loader instance.
+ * @param data The private data to store.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise.
+ */
+int fluid_sfloader_set_data(fluid_sfloader_t *loader, void *data)
+{
+ fluid_return_val_if_fail(loader != NULL, FLUID_FAILED);
+
+ loader->data = data;
+ return FLUID_OK;
+}
+
+/**
+ * Obtain private data previously set with fluid_sfloader_set_data().
+ *
+ * @param loader The SoundFont loader instance.
+ * @return The private data or NULL if none explicitly set before.
+ */
+void *fluid_sfloader_get_data(fluid_sfloader_t *loader)
+{
+ fluid_return_val_if_fail(loader != NULL, NULL);
+
+ return loader->data;
+}
+
+/**
+ * Set custom callbacks to be used upon soundfont loading.
+ *
+ * Useful for loading a soundfont from memory, see \a doc/fluidsynth_sfload_mem.c as an example.
+ *
+ * @param loader The SoundFont loader instance.
+ * @param open A function implementing #fluid_sfloader_callback_open_t.
+ * @param read A function implementing #fluid_sfloader_callback_read_t.
+ * @param seek A function implementing #fluid_sfloader_callback_seek_t.
+ * @param tell A function implementing #fluid_sfloader_callback_tell_t.
+ * @param close A function implementing #fluid_sfloader_callback_close_t.
+ * @return #FLUID_OK if the callbacks have been successfully set, #FLUID_FAILED otherwise.
+ */
+int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
+ fluid_sfloader_callback_open_t open,
+ fluid_sfloader_callback_read_t read,
+ fluid_sfloader_callback_seek_t seek,
+ fluid_sfloader_callback_tell_t tell,
+ fluid_sfloader_callback_close_t close)
+{
+ fluid_file_callbacks_t *cb;
+
+ fluid_return_val_if_fail(loader != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(open != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(read != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(seek != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(tell != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(close != NULL, FLUID_FAILED);
+
+ cb = &loader->file_callbacks;
+
+ cb->fopen = open;
+ cb->fread = read;
+ cb->fseek = seek;
+ cb->ftell = tell;
+ cb->fclose = close;
+
+ return FLUID_OK;
+}
+
+/**
+ * Creates a new virtual SoundFont instance structure.
+ * @param get_name A function implementing #fluid_sfont_get_name_t.
+ * @param get_preset A function implementing #fluid_sfont_get_preset_t.
+ * @param iter_start A function implementing #fluid_sfont_iteration_start_t, or NULL if preset iteration not needed.
+ * @param iter_next A function implementing #fluid_sfont_iteration_next_t, or NULL if preset iteration not needed.
+ * @param free A function implementing #fluid_sfont_free_t.
+ * @return The soundfont instance on success or NULL otherwise.
+ */
+fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name,
+ fluid_sfont_get_preset_t get_preset,
+ fluid_sfont_iteration_start_t iter_start,
+ fluid_sfont_iteration_next_t iter_next,
+ fluid_sfont_free_t free)
+{
+ fluid_sfont_t *sfont;
+
+ fluid_return_val_if_fail(get_name != NULL, NULL);
+ fluid_return_val_if_fail(get_preset != NULL, NULL);
+ fluid_return_val_if_fail(free != NULL, NULL);
+
+ sfont = FLUID_NEW(fluid_sfont_t);
+
+ if(sfont == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(sfont, 0, sizeof(*sfont));
+
+ sfont->get_name = get_name;
+ sfont->get_preset = get_preset;
+ sfont->iteration_start = iter_start;
+ sfont->iteration_next = iter_next;
+ sfont->free = free;
+
+ return sfont;
+}
+
+/**
+ * Set private data to use with a SoundFont instance.
+ *
+ * @param sfont The SoundFont instance.
+ * @param data The private data to store.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise.
+ */
+int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data)
+{
+ fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED);
+
+ sfont->data = data;
+ return FLUID_OK;
+}
+
+/**
+ * Retrieve the private data of a SoundFont instance.
+ *
+ * @param sfont The SoundFont instance.
+ * @return The private data or NULL if none explicitly set before.
+ */
+void *fluid_sfont_get_data(fluid_sfont_t *sfont)
+{
+ fluid_return_val_if_fail(sfont != NULL, NULL);
+
+ return sfont->data;
+}
+
+/**
+ * Retrieve the unique ID of a SoundFont instance.
+ *
+ * @param sfont The SoundFont instance.
+ * @return The SoundFont ID.
+ */
+int fluid_sfont_get_id(fluid_sfont_t *sfont)
+{
+ return sfont->id;
+}
+
+/**
+ * Retrieve the name of a SoundFont instance.
+ *
+ * @param sfont The SoundFont instance.
+ * @return The name of the SoundFont.
+ */
+const char *fluid_sfont_get_name(fluid_sfont_t *sfont)
+{
+ return sfont->get_name(sfont);
+}
+
+/**
+ * Retrieve the preset assigned the a SoundFont instance
+ * for the given bank and preset number.
+ * @param sfont The SoundFont instance.
+ * @param bank bank number of the preset
+ * @param prenum program number of the preset
+ * @return The preset instance or NULL if none found.
+ */
+fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum)
+{
+ return sfont->get_preset(sfont, bank, prenum);
+}
+
+
+/**
+ * Starts / re-starts virtual preset iteration in a SoundFont.
+ * @param sfont Virtual SoundFont instance
+ */
+void fluid_sfont_iteration_start(fluid_sfont_t *sfont)
+{
+ fluid_return_if_fail(sfont != NULL);
+ fluid_return_if_fail(sfont->iteration_start != NULL);
+
+ sfont->iteration_start(sfont);
+}
+
+/**
+ * Virtual SoundFont preset iteration function.
+ *
+ * Returns preset information to the caller and advances the
+ * internal iteration state to the next preset for subsequent calls.
+ * @param sfont The SoundFont instance.
+ * @return NULL when no more presets are available, otherwise the a pointer to the current preset
+ */
+fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont)
+{
+ fluid_return_val_if_fail(sfont != NULL, NULL);
+ fluid_return_val_if_fail(sfont->iteration_next != NULL, NULL);
+
+ return sfont->iteration_next(sfont);
+}
+
+/**
+ * Destroys a SoundFont instance created with new_fluid_sfont().
+ *
+ * Implements #fluid_sfont_free_t.
+ *
+ * @param sfont The SoundFont instance to destroy.
+ * @return Always returns 0.
+ */
+int delete_fluid_sfont(fluid_sfont_t *sfont)
+{
+ fluid_return_val_if_fail(sfont != NULL, 0);
+
+ FLUID_FREE(sfont);
+ return 0;
+}
+
+/**
+ * Create a virtual SoundFont preset instance.
+ *
+ * @param parent_sfont The SoundFont instance this preset shall belong to
+ * @param get_name A function implementing #fluid_preset_get_name_t
+ * @param get_bank A function implementing #fluid_preset_get_banknum_t
+ * @param get_num A function implementing #fluid_preset_get_num_t
+ * @param noteon A function implementing #fluid_preset_noteon_t
+ * @param free A function implementing #fluid_preset_free_t
+ * @return The preset instance on success, NULL otherwise.
+ */
+fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont,
+ fluid_preset_get_name_t get_name,
+ fluid_preset_get_banknum_t get_bank,
+ fluid_preset_get_num_t get_num,
+ fluid_preset_noteon_t noteon,
+ fluid_preset_free_t free)
+{
+ fluid_preset_t *preset;
+
+ fluid_return_val_if_fail(parent_sfont != NULL, NULL);
+ fluid_return_val_if_fail(get_name != NULL, NULL);
+ fluid_return_val_if_fail(get_bank != NULL, NULL);
+ fluid_return_val_if_fail(get_num != NULL, NULL);
+ fluid_return_val_if_fail(noteon != NULL, NULL);
+ fluid_return_val_if_fail(free != NULL, NULL);
+
+ preset = FLUID_NEW(fluid_preset_t);
+
+ if(preset == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(preset, 0, sizeof(*preset));
+
+ preset->sfont = parent_sfont;
+ preset->get_name = get_name;
+ preset->get_banknum = get_bank;
+ preset->get_num = get_num;
+ preset->noteon = noteon;
+ preset->free = free;
+
+ return preset;
+}
+
+/**
+ * Set private data to use with a SoundFont preset instance.
+ *
+ * @param preset The SoundFont preset instance.
+ * @param data The private data to store.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise.
+ */
+int fluid_preset_set_data(fluid_preset_t *preset, void *data)
+{
+ fluid_return_val_if_fail(preset != NULL, FLUID_FAILED);
+
+ preset->data = data;
+ return FLUID_OK;
+}
+
+/**
+ * Retrieve the private data of a SoundFont preset instance.
+ *
+ * @param preset The SoundFont preset instance.
+ * @return The private data or NULL if none explicitly set before.
+ */
+void *fluid_preset_get_data(fluid_preset_t *preset)
+{
+ fluid_return_val_if_fail(preset != NULL, NULL);
+
+ return preset->data;
+}
+
+/**
+ * Retrieves the presets name by executing the \p get_name function
+ * provided on its creation.
+ *
+ * @param preset The SoundFont preset instance.
+ * @return Pointer to a NULL-terminated string containing the presets name.
+ */
+const char *fluid_preset_get_name(fluid_preset_t *preset)
+{
+ return preset->get_name(preset);
+}
+
+/**
+ * Retrieves the presets bank number by executing the \p get_bank function
+ * provided on its creation.
+ *
+ * @param preset The SoundFont preset instance.
+ * @return The bank number of \p preset.
+ */
+int fluid_preset_get_banknum(fluid_preset_t *preset)
+{
+ return preset->get_banknum(preset);
+}
+
+/**
+ * Retrieves the presets (instrument) number by executing the \p get_num function
+ * provided on its creation.
+ *
+ * @param preset The SoundFont preset instance.
+ * @return The number of \p preset.
+ */
+int fluid_preset_get_num(fluid_preset_t *preset)
+{
+ return preset->get_num(preset);
+}
+
+/**
+ * Retrieves the presets parent SoundFont instance.
+ *
+ * @param preset The SoundFont preset instance.
+ * @return The parent SoundFont of \p preset.
+ */
+fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset)
+{
+ return preset->sfont;
+}
+
+/**
+ * Destroys a SoundFont preset instance created with new_fluid_preset().
+ *
+ * Implements #fluid_preset_free_t.
+ *
+ * @param preset The SoundFont preset instance to destroy.
+ */
+void delete_fluid_preset(fluid_preset_t *preset)
+{
+ fluid_return_if_fail(preset != NULL);
+
+ FLUID_FREE(preset);
+}
+
+/**
+ * Create a new sample instance.
+ * @return The sample on success, NULL otherwise.
+ */
+fluid_sample_t *
+new_fluid_sample()
+{
+ fluid_sample_t *sample = NULL;
+
+ sample = FLUID_NEW(fluid_sample_t);
+
+ if(sample == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(sample, 0, sizeof(*sample));
+
+ return sample;
+}
+
+/**
+ * Destroy a sample instance previously created with new_fluid_sample().
+ * @param sample The sample to destroy.
+ */
+void
+delete_fluid_sample(fluid_sample_t *sample)
+{
+ fluid_return_if_fail(sample != NULL);
+
+ if(sample->auto_free)
+ {
+ FLUID_FREE(sample->data);
+ FLUID_FREE(sample->data24);
+ }
+
+ FLUID_FREE(sample);
+}
+
+/**
+ * Returns the size of the fluid_sample_t structure.
+ *
+ * Useful in low latency scenarios e.g. to allocate a sample on the stack.
+ *
+ * @return Size of fluid_sample_t in bytes
+ */
+size_t fluid_sample_sizeof()
+{
+ return sizeof(fluid_sample_t);
+}
+
+/**
+ * Set the name of a SoundFont sample.
+ * @param sample SoundFont sample
+ * @param name Name to assign to sample (20 chars in length + zero terminator)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_sample_set_name(fluid_sample_t *sample, const char *name)
+{
+ fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+
+ FLUID_STRNCPY(sample->name, name, sizeof(sample->name));
+ return FLUID_OK;
+}
+
+/**
+ * Assign sample data to a SoundFont sample.
+ * @param sample SoundFont sample
+ * @param data Buffer containing 16 bit (mono-)audio sample data
+ * @param data24 If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples
+ * @param nbframes Number of samples in \a data
+ * @param sample_rate Sampling rate of the sample data
+ * @param copy_data TRUE to copy the sample data (and automatically free it upon delete_fluid_sample()), FALSE to use it directly (and not free it)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ *
+ * @note If \a copy_data is FALSE, data should have 8 unused frames at start
+ * and 8 unused frames at the end and \a nbframes should be >=48
+ */
+int
+fluid_sample_set_sound_data(fluid_sample_t *sample,
+ short *data,
+ char *data24,
+ unsigned int nbframes,
+ unsigned int sample_rate,
+ short copy_data
+ )
+{
+ /* the number of samples before the start and after the end */
+#define SAMPLE_LOOP_MARGIN 8U
+
+ fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(data != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(nbframes == 0, FLUID_FAILED);
+
+ /* in case we already have some data */
+ if((sample->data != NULL || sample->data24 != NULL) && sample->auto_free)
+ {
+ FLUID_FREE(sample->data);
+ FLUID_FREE(sample->data24);
+ sample->data = NULL;
+ sample->data24 = NULL;
+ }
+
+ if(copy_data)
+ {
+ unsigned int storedNbFrames;
+
+ /* nbframes should be >= 48 (SoundFont specs) */
+ storedNbFrames = nbframes;
+
+ if(storedNbFrames < 48)
+ {
+ storedNbFrames = 48;
+ }
+
+ storedNbFrames += 2 * SAMPLE_LOOP_MARGIN;
+
+ sample->data = FLUID_ARRAY(short, storedNbFrames);
+
+ if(sample->data == NULL)
+ {
+ goto error_rec;
+ }
+
+ FLUID_MEMSET(sample->data, 0, storedNbFrames);
+ FLUID_MEMCPY(sample->data + SAMPLE_LOOP_MARGIN, data, nbframes * sizeof(short));
+
+ if(data24 != NULL)
+ {
+ sample->data24 = FLUID_ARRAY(char, storedNbFrames);
+
+ if(sample->data24 == NULL)
+ {
+ goto error_rec;
+ }
+
+ FLUID_MEMSET(sample->data24, 0, storedNbFrames);
+ FLUID_MEMCPY(sample->data24 + SAMPLE_LOOP_MARGIN, data24, nbframes * sizeof(char));
+ }
+
+ /* pointers */
+ /* all from the start of data */
+ sample->start = SAMPLE_LOOP_MARGIN;
+ sample->end = SAMPLE_LOOP_MARGIN + storedNbFrames - 1;
+ }
+ else
+ {
+ /* we cannot assure the SAMPLE_LOOP_MARGIN */
+ sample->data = data;
+ sample->data24 = data24;
+ sample->start = 0;
+ sample->end = nbframes - 1;
+ }
+
+ sample->samplerate = sample_rate;
+ sample->sampletype = FLUID_SAMPLETYPE_MONO;
+ sample->auto_free = copy_data;
+
+ return FLUID_OK;
+
+error_rec:
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ FLUID_FREE(sample->data);
+ FLUID_FREE(sample->data24);
+ return FLUID_FAILED;
+
+#undef SAMPLE_LOOP_MARGIN
+}
+
+/**
+ * Set the loop of a sample.
+ *
+ * @param sample SoundFont sample
+ * @param loop_start Start sample index of the loop.
+ * @param loop_end End index of the loop (must be a valid sample as it marks the last sample to be played).
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise.
+ */
+int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end)
+{
+ fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
+
+ sample->loopstart = loop_start;
+ sample->loopend = loop_end;
+
+ return FLUID_OK;
+}
+
+/**
+ * Set the pitch of a sample.
+ *
+ * @param sample SoundFont sample
+ * @param root_key Root MIDI note of sample (0-127)
+ * @param fine_tune Fine tune in cents
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise.
+ */
+int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune)
+{
+ fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(0 <= root_key && root_key <= 127, FLUID_FAILED);
+
+ sample->origpitch = root_key;
+ sample->pitchadj = fine_tune;
+
+ return FLUID_OK;
+}
+
+
+/**
+ * Validate parameters of a sample
+ *
+ */
+int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size)
+{
+ /* ROM samples are unusable for us by definition */
+ if(sample->sampletype & FLUID_SAMPLETYPE_ROM)
+ {
+ FLUID_LOG(FLUID_WARN, "Sample '%s': ROM sample ignored", sample->name);
+ return FLUID_FAILED;
+ }
+
+ /* Ogg vorbis compressed samples in the SF3 format use byte indices for
+ * sample start and end pointers before decompression. Standard SF2 samples
+ * use sample word indices for all pointers, so use half the buffer_size
+ * for validation. */
+ if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))
+ {
+ if(buffer_size % 2)
+ {
+ FLUID_LOG(FLUID_WARN, "Sample '%s': invalid buffer size", sample->name);
+ return FLUID_FAILED;
+ }
+
+ buffer_size /= 2;
+ }
+
+ if((sample->end > buffer_size) || (sample->start >= sample->end))
+ {
+ FLUID_LOG(FLUID_WARN, "Sample '%s': invalid start/end file positions", sample->name);
+ return FLUID_FAILED;
+ }
+
+ return FLUID_OK;
+}
+
+/* Check the sample loop pointers and optionally convert them to something
+ * usable in case they are broken. Return a boolean indicating if the pointers
+ * have been modified, so the user can be notified of possible audio glitches.
+ */
+int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int buffer_size)
+{
+ int modified = FALSE;
+ unsigned int max_end = buffer_size / 2;
+ /* In fluid_sample_t the sample end pointer points to the last sample, not
+ * to the data word after the last sample. FIXME: why? */
+ unsigned int sample_end = sample->end + 1;
+
+ if(sample->loopstart == sample->loopend)
+ {
+ /* Some SoundFonts disable loops by setting loopstart = loopend. While
+ * technically invalid, we decided to accept those samples anyway. Just
+ * ensure that those two pointers are within the sampledata by setting
+ * them to 0. Don't report the modification, as this change has no audible
+ * effect. */
+ sample->loopstart = sample->loopend = 0;
+ return FALSE;
+ }
+ else if(sample->loopstart > sample->loopend)
+ {
+ unsigned int tmp;
+
+ /* If loop start and end are reversed, try to swap them around and
+ * continue validation */
+ FLUID_LOG(FLUID_DBG, "Sample '%s': reversed loop pointers '%d' - '%d', trying to fix",
+ sample->name, sample->loopstart, sample->loopend);
+ tmp = sample->loopstart;
+ sample->loopstart = sample->loopend;
+ sample->loopend = tmp;
+ modified = TRUE;
+ }
+
+ /* The SoundFont 2.4 spec defines the loopstart index as the first sample
+ * point of the loop while loopend is the first point AFTER the last sample
+ * of the loop. However we cannot be sure whether any of loopend or end is
+ * correct. Hours of thinking through this have concluded that it would be
+ * best practice to mangle with loops as little as necessary by only making
+ * sure the pointers are within sample->start to max_end. Incorrect
+ * soundfont shall preferably fail loudly. */
+ if((sample->loopstart < sample->start) || (sample->loopstart > max_end))
+ {
+ FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop start '%d', setting to sample start '%d'",
+ sample->name, sample->loopstart, sample->start);
+ sample->loopstart = sample->start;
+ modified = TRUE;
+ }
+
+ if((sample->loopend < sample->start) || (sample->loopend > max_end))
+ {
+ FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop end '%d', setting to sample end '%d'",
+ sample->name, sample->loopend, sample_end);
+ sample->loopend = sample_end;
+ modified = TRUE;
+ }
+
+ if((sample->loopstart > sample_end) || (sample->loopend > sample_end))
+ {
+ FLUID_LOG(FLUID_DBG, "Sample '%s': loop range '%d - %d' after sample end '%d', using it anyway",
+ sample->name, sample->loopstart, sample->loopend, sample_end);
+ }
+
+ return modified;
+}
diff --git a/libs/fluidsynth/src/fluid_sfont.h b/libs/fluidsynth/src/fluid_sfont.h
index 51e941e440..24773353df 100644
--- a/libs/fluidsynth/src/fluid_sfont.h
+++ b/libs/fluidsynth/src/fluid_sfont.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -22,6 +22,10 @@
#ifndef _PRIV_FLUID_SFONT_H
#define _PRIV_FLUID_SFONT_H
+#include "fluidsynth.h"
+
+int fluid_sample_validate(fluid_sample_t *sample, unsigned int max_end);
+int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int max_end);
/*
* Utility macros to access soundfonts, presets, and samples
@@ -31,24 +35,12 @@
#define fluid_sfloader_load(_loader, _filename) (*(_loader)->load)(_loader, _filename)
-#define delete_fluid_sfont(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
-#define fluid_sfont_get_name(_sf) (*(_sf)->get_name)(_sf)
-#define fluid_sfont_get_preset(_sf,_bank,_prenum) (*(_sf)->get_preset)(_sf,_bank,_prenum)
-#define fluid_sfont_iteration_start(_sf) (*(_sf)->iteration_start)(_sf)
-#define fluid_sfont_iteration_next(_sf,_pr) (*(_sf)->iteration_next)(_sf,_pr)
-#define fluid_sfont_get_data(_sf) (_sf)->data
-#define fluid_sfont_set_data(_sf,_p) { (_sf)->data = (void*) (_p); }
+#define fluid_sfont_delete_internal(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
-#define delete_fluid_preset(_preset) \
+#define fluid_preset_delete_internal(_preset) \
{ if ((_preset) && (_preset)->free) { (*(_preset)->free)(_preset); }}
-#define fluid_preset_get_data(_preset) (_preset)->data
-#define fluid_preset_set_data(_preset,_p) { (_preset)->data = (void*) (_p); }
-#define fluid_preset_get_name(_preset) (*(_preset)->get_name)(_preset)
-#define fluid_preset_get_banknum(_preset) (*(_preset)->get_banknum)(_preset)
-#define fluid_preset_get_num(_preset) (*(_preset)->get_num)(_preset)
-
#define fluid_preset_noteon(_preset,_synth,_ch,_key,_vel) \
(*(_preset)->noteon)(_preset,_synth,_ch,_key,_vel)
@@ -65,4 +57,135 @@
+/**
+ * File callback structure to enable custom soundfont loading (e.g. from memory).
+ */
+struct _fluid_file_callbacks_t
+{
+ fluid_sfloader_callback_open_t fopen;
+ fluid_sfloader_callback_read_t fread;
+ fluid_sfloader_callback_seek_t fseek;
+ fluid_sfloader_callback_close_t fclose;
+ fluid_sfloader_callback_tell_t ftell;
+};
+
+/**
+ * SoundFont loader structure.
+ */
+struct _fluid_sfloader_t
+{
+ void *data; /**< User defined data pointer used by _fluid_sfloader_t::load() */
+
+ /** Callback structure specifying file operations used during soundfont loading to allow custom loading, such as from memory */
+ fluid_file_callbacks_t file_callbacks;
+
+ fluid_sfloader_free_t free;
+
+ fluid_sfloader_load_t load;
+};
+
+/**
+ * Virtual SoundFont instance structure.
+ */
+struct _fluid_sfont_t
+{
+ void *data; /**< User defined data */
+ int id; /**< SoundFont ID */
+ int refcount; /**< SoundFont reference count (1 if no presets referencing it) */
+ int bankofs; /**< Bank offset */
+
+ fluid_sfont_free_t free;
+
+ fluid_sfont_get_name_t get_name;
+
+ fluid_sfont_get_preset_t get_preset;
+
+ fluid_sfont_iteration_start_t iteration_start;
+
+ fluid_sfont_iteration_next_t iteration_next;
+};
+
+/**
+ * Virtual SoundFont preset.
+ */
+struct _fluid_preset_t
+{
+ void *data; /**< User supplied data */
+ fluid_sfont_t *sfont; /**< Parent virtual SoundFont */
+
+ fluid_preset_free_t free;
+
+ fluid_preset_get_name_t get_name;
+
+ fluid_preset_get_banknum_t get_banknum;
+
+ fluid_preset_get_num_t get_num;
+
+ fluid_preset_noteon_t noteon;
+
+ /**
+ * Virtual SoundFont preset notify method.
+ * @param preset Virtual SoundFont preset
+ * @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED
+ * @param chan MIDI channel number
+ * @return Should return #FLUID_OK
+ *
+ * Implement this optional method if the preset needs to be notified about
+ * preset select and unselect events.
+ *
+ * This method may be called from within synthesis context and therefore
+ * should be as efficient as possible and not perform any operations considered
+ * bad for realtime audio output (memory allocations and other OS calls).
+ */
+ int (*notify)(fluid_preset_t *preset, int reason, int chan);
+};
+
+/**
+ * Virtual SoundFont sample.
+ */
+struct _fluid_sample_t
+{
+ char name[21]; /**< Sample name */
+
+ /* The following for sample pointers store the original pointers from the Soundfont
+ * file. They are never changed after loading and are used to re-create the
+ * actual sample pointers after a sample has been unloaded and loaded again. The
+ * actual sample pointers get modified during loading for SF3 (compressed) samples
+ * and individually loaded SF2 samples. */
+ unsigned int source_start;
+ unsigned int source_end;
+ unsigned int source_loopstart;
+ unsigned int source_loopend;
+
+ unsigned int start; /**< Start index */
+ unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */
+ unsigned int loopstart; /**< Loop start index */
+ unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */
+
+ unsigned int samplerate; /**< Sample rate */
+ int origpitch; /**< Original pitch (MIDI note number, 0-127) */
+ int pitchadj; /**< Fine pitch adjustment (+/- 99 cents) */
+ int sampletype; /**< Specifies the type of this sample as indicated by the #fluid_sample_type enum */
+ int auto_free; /**< TRUE if _fluid_sample_t::data and _fluid_sample_t::data24 should be freed upon sample destruction */
+ short *data; /**< Pointer to the sample's 16 bit PCM data */
+ char *data24; /**< If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples */
+
+ int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */
+ double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */
+
+ unsigned int refcount; /**< Count of voices using this sample */
+ int preset_count; /**< Count of selected presets using this sample (used for dynamic sample loading) */
+
+ /**
+ * Implement this function to receive notification when sample is no longer used.
+ * @param sample Virtual SoundFont sample
+ * @param reason #FLUID_SAMPLE_DONE only currently
+ * @return Should return #FLUID_OK
+ */
+ int (*notify)(fluid_sample_t *sample, int reason);
+
+ void *userdata; /**< User defined data */
+};
+
+
#endif /* _PRIV_FLUID_SFONT_H */
diff --git a/libs/fluidsynth/src/fluid_synth.c b/libs/fluidsynth/src/fluid_synth.c
index 8a30e250ba..e8845632f1 100644
--- a/libs/fluidsynth/src/fluid_synth.c
+++ b/libs/fluidsynth/src/fluid_synth.c
@@ -3,30 +3,27 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
-#include <math.h>
-
#include "fluid_synth.h"
#include "fluid_sys.h"
#include "fluid_chan.h"
#include "fluid_tuning.h"
#include "fluid_settings.h"
#include "fluid_sfont.h"
-#include "fluid_hash.h"
#include "fluid_defsfont.h"
#ifdef TRAP_ON_FPE
@@ -34,82 +31,113 @@
#include <fenv.h>
/* seems to not be declared in fenv.h */
-extern int feenableexcept (int excepts);
+extern int feenableexcept(int excepts);
#endif
-static void fluid_synth_init(void);
+#define FLUID_API_RETURN(return_value) \
+ do { fluid_synth_api_exit(synth); \
+ return return_value; } while (0)
-static int fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key,
- int vel);
-static int fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key);
-static int fluid_synth_cc_LOCAL(fluid_synth_t* synth, int channum, int num);
-static int fluid_synth_update_device_id (fluid_synth_t *synth, char *name,
- int value);
-static int fluid_synth_update_overflow (fluid_synth_t *synth, char *name,
- fluid_real_t value);
-static int fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, const char *data,
- int len, char *response,
- int *response_len, int avail_response,
- int *handled, int dryrun);
-static int fluid_synth_all_notes_off_LOCAL(fluid_synth_t* synth, int chan);
-static int fluid_synth_all_sounds_off_LOCAL(fluid_synth_t* synth, int chan);
-static int fluid_synth_system_reset_LOCAL(fluid_synth_t* synth);
-static int fluid_synth_modulate_voices_LOCAL(fluid_synth_t* synth, int chan,
- int is_cc, int ctrl);
-static int fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan);
-static int fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int channum);
-static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan);
-static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan);
-static int fluid_synth_set_preset (fluid_synth_t *synth, int chan,
- fluid_preset_t *preset);
-static fluid_preset_t*
-fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
- unsigned int banknum, unsigned int prognum);
-static fluid_preset_t*
-fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname,
- unsigned int banknum, unsigned int prognum);
-
-static void fluid_synth_update_presets(fluid_synth_t* synth);
-static int fluid_synth_update_sample_rate(fluid_synth_t* synth,
- char* name, double value);
-static int fluid_synth_update_gain(fluid_synth_t* synth,
- char* name, double value);
-static void fluid_synth_update_gain_LOCAL(fluid_synth_t* synth);
-static int fluid_synth_update_polyphony(fluid_synth_t* synth,
- char* name, int value);
-static int fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth, int new_polyphony);
-static void init_dither(void);
-static inline int roundi (float x);
-static int fluid_synth_render_blocks(fluid_synth_t* synth, int blockcount);
-//static void fluid_synth_core_thread_func (void* data);
-//static FLUID_INLINE void fluid_synth_process_event_queue_LOCAL
-// (fluid_synth_t *synth, fluid_event_queue_t *queue);
-static fluid_voice_t* fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth);
-static void fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t* synth,
- fluid_voice_t* new_voice);
-static fluid_sfont_info_t *new_fluid_sfont_info (fluid_synth_t *synth,
- fluid_sfont_t *sfont);
-static int fluid_synth_sfunload_callback(void* data, unsigned int msec);
-static void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth,
- int chan, int key);
-static fluid_tuning_t* fluid_synth_get_tuning(fluid_synth_t* synth,
- int bank, int prog);
-static int fluid_synth_replace_tuning_LOCK (fluid_synth_t* synth,
- fluid_tuning_t *tuning,
- int bank, int prog, int apply);
-static void fluid_synth_replace_tuning_LOCAL (fluid_synth_t *synth,
- fluid_tuning_t *old_tuning,
- fluid_tuning_t *new_tuning,
- int apply, int unref_new);
-static void fluid_synth_update_voice_tuning_LOCAL (fluid_synth_t *synth,
- fluid_channel_t *channel);
-static int fluid_synth_set_tuning_LOCAL (fluid_synth_t *synth, int chan,
- fluid_tuning_t *tuning, int apply);
-static void fluid_synth_set_gen_LOCAL (fluid_synth_t* synth, int chan,
- int param, float value, int absolute);
-static void fluid_synth_stop_LOCAL (fluid_synth_t *synth, unsigned int id);
+#define FLUID_API_RETURN_IF_CHAN_DISABLED(return_value) \
+ do { if (FLUID_LIKELY(synth->channel[chan]->mode & FLUID_CHANNEL_ENABLED)) \
+ {} \
+ else \
+ { FLUID_API_RETURN(return_value); } \
+ } while (0)
+#define FLUID_API_ENTRY_CHAN(fail_value) \
+ fluid_return_val_if_fail (synth != NULL, fail_value); \
+ fluid_return_val_if_fail (chan >= 0, fail_value); \
+ fluid_synth_api_enter(synth); \
+ if (chan >= synth->midi_channels) { \
+ FLUID_API_RETURN(fail_value); \
+ } \
+static void fluid_synth_init(void);
+static void fluid_synth_api_enter(fluid_synth_t *synth);
+static void fluid_synth_api_exit(fluid_synth_t *synth);
+
+static int fluid_synth_noteon_LOCAL(fluid_synth_t *synth, int chan, int key,
+ int vel);
+static int fluid_synth_noteoff_LOCAL(fluid_synth_t *synth, int chan, int key);
+static int fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num);
+static int fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data,
+ int len, char *response,
+ int *response_len, int avail_response,
+ int *handled, int dryrun);
+int fluid_synth_all_notes_off_LOCAL(fluid_synth_t *synth, int chan);
+static int fluid_synth_all_sounds_off_LOCAL(fluid_synth_t *synth, int chan);
+static int fluid_synth_system_reset_LOCAL(fluid_synth_t *synth);
+static int fluid_synth_modulate_voices_LOCAL(fluid_synth_t *synth, int chan,
+ int is_cc, int ctrl);
+static int fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t *synth, int chan);
+static int fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t *synth, int channum);
+static int fluid_synth_update_key_pressure_LOCAL(fluid_synth_t *synth, int chan, int key);
+static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t *synth, int chan);
+static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t *synth, int chan);
+static int fluid_synth_set_preset(fluid_synth_t *synth, int chan,
+ fluid_preset_t *preset);
+static fluid_preset_t *
+fluid_synth_get_preset(fluid_synth_t *synth, int sfontnum,
+ int banknum, int prognum);
+static fluid_preset_t *
+fluid_synth_get_preset_by_sfont_name(fluid_synth_t *synth, const char *sfontname,
+ int banknum, int prognum);
+
+static void fluid_synth_update_presets(fluid_synth_t *synth);
+static void fluid_synth_update_gain_LOCAL(fluid_synth_t *synth);
+static int fluid_synth_update_polyphony_LOCAL(fluid_synth_t *synth, int new_polyphony);
+static void init_dither(void);
+static FLUID_INLINE int roundi(float x);
+static int fluid_synth_render_blocks(fluid_synth_t *synth, int blockcount);
+
+static fluid_voice_t *fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t *synth);
+static void fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t *synth,
+ fluid_voice_t *new_voice);
+static int fluid_synth_sfunload_callback(void *data, unsigned int msec);
+void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth,
+ int chan, int key);
+static fluid_tuning_t *fluid_synth_get_tuning(fluid_synth_t *synth,
+ int bank, int prog);
+static int fluid_synth_replace_tuning_LOCK(fluid_synth_t *synth,
+ fluid_tuning_t *tuning,
+ int bank, int prog, int apply);
+static void fluid_synth_replace_tuning_LOCAL(fluid_synth_t *synth,
+ fluid_tuning_t *old_tuning,
+ fluid_tuning_t *new_tuning,
+ int apply, int unref_new);
+static void fluid_synth_update_voice_tuning_LOCAL(fluid_synth_t *synth,
+ fluid_channel_t *channel);
+static int fluid_synth_set_tuning_LOCAL(fluid_synth_t *synth, int chan,
+ fluid_tuning_t *tuning, int apply);
+static void fluid_synth_set_gen_LOCAL(fluid_synth_t *synth, int chan,
+ int param, float value, int absolute);
+static void fluid_synth_stop_LOCAL(fluid_synth_t *synth, unsigned int id);
+
+
+static int fluid_synth_set_important_channels(fluid_synth_t *synth, const char *channels);
+
+
+/* Callback handlers for real-time settings */
+static void fluid_synth_handle_sample_rate(void *data, const char *name, double value);
+static void fluid_synth_handle_gain(void *data, const char *name, double value);
+static void fluid_synth_handle_polyphony(void *data, const char *name, int value);
+static void fluid_synth_handle_device_id(void *data, const char *name, int value);
+static void fluid_synth_handle_overflow(void *data, const char *name, double value);
+static void fluid_synth_handle_important_channels(void *data, const char *name,
+ const char *value);
+static void fluid_synth_handle_reverb_chorus_num(void *data, const char *name, double value);
+static void fluid_synth_handle_reverb_chorus_int(void *data, const char *name, int value);
+
+
+static void fluid_synth_reset_basic_channel_LOCAL(fluid_synth_t *synth, int chan, int nbr_chan);
+static int fluid_synth_check_next_basic_channel(fluid_synth_t *synth, int basicchan, int mode, int val);
+static void fluid_synth_set_basic_channel_LOCAL(fluid_synth_t *synth, int basicchan, int mode, int val);
+static int fluid_synth_set_reverb_full_LOCAL(fluid_synth_t *synth, int set, double roomsize,
+ double damping, double width, double level);
+
+static int fluid_synth_set_chorus_full_LOCAL(fluid_synth_t *synth, int set, int nr, double level,
+ double speed, double depth_ms, int type);
/***************************************************************
*
@@ -117,7 +145,8 @@ static void fluid_synth_stop_LOCAL (fluid_synth_t *synth, unsigned int id);
*/
/* has the synth module been initialized? */
-static int fluid_synth_initialized = 0;
+/* fluid_atomic_int_t may be anything, so init with {0} to catch most cases */
+static fluid_atomic_int_t fluid_synth_initialized = {0};
static void fluid_synth_init(void);
static void init_dither(void);
@@ -128,26 +157,34 @@ static void init_dither(void);
* explicitly overridden by the sound font in order to turn them off.
*/
-fluid_mod_t default_vel2att_mod; /* SF2.01 section 8.4.1 */
-fluid_mod_t default_vel2filter_mod; /* SF2.01 section 8.4.2 */
-fluid_mod_t default_at2viblfo_mod; /* SF2.01 section 8.4.3 */
-fluid_mod_t default_mod2viblfo_mod; /* SF2.01 section 8.4.4 */
-fluid_mod_t default_att_mod; /* SF2.01 section 8.4.5 */
-fluid_mod_t default_pan_mod; /* SF2.01 section 8.4.6 */
-fluid_mod_t default_expr_mod; /* SF2.01 section 8.4.7 */
-fluid_mod_t default_reverb_mod; /* SF2.01 section 8.4.8 */
-fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */
-fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */
+static fluid_mod_t default_vel2att_mod; /* SF2.01 section 8.4.1 */
+/*not static */ fluid_mod_t default_vel2filter_mod; /* SF2.01 section 8.4.2 */
+static fluid_mod_t default_at2viblfo_mod; /* SF2.01 section 8.4.3 */
+static fluid_mod_t default_mod2viblfo_mod; /* SF2.01 section 8.4.4 */
+static fluid_mod_t default_att_mod; /* SF2.01 section 8.4.5 */
+static fluid_mod_t default_pan_mod; /* SF2.01 section 8.4.6 */
+static fluid_mod_t default_expr_mod; /* SF2.01 section 8.4.7 */
+static fluid_mod_t default_reverb_mod; /* SF2.01 section 8.4.8 */
+static fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */
+static fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */
+static fluid_mod_t custom_balance_mod; /* Non-standard modulator */
+
+
+/* custom_breath2att_modulator is not a default modulator specified in SF
+it is intended to replace default_vel2att_mod on demand using
+API fluid_set_breath_mode() or command shell setbreathmode.
+*/
+static fluid_mod_t custom_breath2att_mod;
/* reverb presets */
-static fluid_revmodel_presets_t revmodel_preset[] = {
- /* name */ /* roomsize */ /* damp */ /* width */ /* level */
- { "Test 1", 0.2f, 0.0f, 0.5f, 0.9f },
- { "Test 2", 0.4f, 0.2f, 0.5f, 0.8f },
- { "Test 3", 0.6f, 0.4f, 0.5f, 0.7f },
- { "Test 4", 0.8f, 0.7f, 0.5f, 0.6f },
- { "Test 5", 0.8f, 1.0f, 0.5f, 0.5f },
- { NULL, 0.0f, 0.0f, 0.0f, 0.0f }
+static const fluid_revmodel_presets_t revmodel_preset[] =
+{
+ /* name */ /* roomsize */ /* damp */ /* width */ /* level */
+ { "Test 1", 0.2f, 0.0f, 0.5f, 0.9f },
+ { "Test 2", 0.4f, 0.2f, 0.5f, 0.8f },
+ { "Test 3", 0.6f, 0.4f, 0.5f, 0.7f },
+ { "Test 4", 0.8f, 0.7f, 0.5f, 0.6f },
+ { "Test 5", 0.8f, 1.0f, 0.5f, 0.5f },
};
@@ -156,76 +193,60 @@ static fluid_revmodel_presets_t revmodel_preset[] = {
* INITIALIZATION & UTILITIES
*/
-static void fluid_synth_register_overflow(fluid_settings_t* settings,
- fluid_num_update_t update_func,
- void* update_data)
-{
- fluid_settings_register_num(settings, "synth.overflow.percussion",
- 4000, -10000, 10000, 0, update_func, update_data);
- fluid_settings_register_num(settings, "synth.overflow.sustained",
- -1000, -10000, 10000, 0, update_func, update_data);
- fluid_settings_register_num(settings, "synth.overflow.released",
- -2000, -10000, 10000, 0, update_func, update_data);
- fluid_settings_register_num(settings, "synth.overflow.age",
- 1000, -10000, 10000, 0, update_func, update_data);
- fluid_settings_register_num(settings, "synth.overflow.volume",
- 500, -10000, 10000, 0, update_func, update_data);
-}
-
-void fluid_synth_settings(fluid_settings_t* settings)
-{
- fluid_settings_register_int(settings, "synth.verbose", 0, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.dump", 0, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.reverb.active", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.chorus.active", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.ladspa.active", 0, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.lock-memory", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_str(settings, "midi.portname", "", 0, NULL, NULL);
-
- fluid_settings_register_str(settings, "synth.default-soundfont",
- DEFAULT_SOUNDFONT, 0, NULL, NULL);
-
- fluid_settings_register_int(settings, "synth.polyphony",
- 256, 1, 65535, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.midi-channels",
- 16, 16, 256, 0, NULL, NULL);
- fluid_settings_register_num(settings, "synth.gain",
- 0.2f, 0.0f, 10.0f,
- 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.audio-channels",
- 1, 1, 128, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.audio-groups",
- 1, 1, 128, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.effects-channels",
- 2, 2, 2, 0, NULL, NULL);
- fluid_settings_register_num(settings, "synth.sample-rate",
- 44100.0f, 8000.0f, 96000.0f,
- 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.device-id",
- 0, 0, 126, 0, NULL, NULL);
- fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 256, 0, NULL, NULL);
-
- fluid_settings_register_int(settings, "synth.min-note-length", 10, 0, 65535, 0, NULL, NULL);
-
- fluid_settings_register_int(settings, "synth.threadsafe-api", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
- fluid_settings_register_int(settings, "synth.parallel-render", 1, 0, 1,
- FLUID_HINT_TOGGLED, NULL, NULL);
-
- fluid_synth_register_overflow(settings, NULL, NULL);
-
- fluid_settings_register_str(settings, "synth.midi-bank-select", "gs", 0, NULL, NULL);
- fluid_settings_add_option(settings, "synth.midi-bank-select", "gm");
- fluid_settings_add_option(settings, "synth.midi-bank-select", "gs");
- fluid_settings_add_option(settings, "synth.midi-bank-select", "xg");
- fluid_settings_add_option(settings, "synth.midi-bank-select", "mma");
-
+void fluid_synth_settings(fluid_settings_t *settings)
+{
+ fluid_settings_register_int(settings, "synth.verbose", 0, 0, 1, FLUID_HINT_TOGGLED);
+
+ fluid_settings_register_int(settings, "synth.reverb.active", 1, 0, 1, FLUID_HINT_TOGGLED);
+ fluid_settings_register_num(settings, "synth.reverb.room-size", FLUID_REVERB_DEFAULT_ROOMSIZE, 0.0f, 1.0f, 0);
+ fluid_settings_register_num(settings, "synth.reverb.damp", FLUID_REVERB_DEFAULT_DAMP, 0.0f, 1.0f, 0);
+ fluid_settings_register_num(settings, "synth.reverb.width", FLUID_REVERB_DEFAULT_WIDTH, 0.0f, 100.0f, 0);
+ fluid_settings_register_num(settings, "synth.reverb.level", FLUID_REVERB_DEFAULT_LEVEL, 0.0f, 1.0f, 0);
+
+ fluid_settings_register_int(settings, "synth.chorus.active", 1, 0, 1, FLUID_HINT_TOGGLED);
+ fluid_settings_register_int(settings, "synth.chorus.nr", FLUID_CHORUS_DEFAULT_N, 0, 99, 0);
+ fluid_settings_register_num(settings, "synth.chorus.level", FLUID_CHORUS_DEFAULT_LEVEL, 0.0f, 10.0f, 0);
+ fluid_settings_register_num(settings, "synth.chorus.speed", FLUID_CHORUS_DEFAULT_SPEED, 0.29f, 5.0f, 0);
+ fluid_settings_register_num(settings, "synth.chorus.depth", FLUID_CHORUS_DEFAULT_DEPTH, 0.0f, 256.0f, 0);
+
+ fluid_settings_register_int(settings, "synth.ladspa.active", 0, 0, 1, FLUID_HINT_TOGGLED);
+ fluid_settings_register_int(settings, "synth.lock-memory", 1, 0, 1, FLUID_HINT_TOGGLED);
+ fluid_settings_register_str(settings, "midi.portname", "", 0);
+
+#ifdef DEFAULT_SOUNDFONT
+ fluid_settings_register_str(settings, "synth.default-soundfont", DEFAULT_SOUNDFONT, 0);
+#endif
+
+ fluid_settings_register_int(settings, "synth.polyphony", 256, 1, 65535, 0);
+ fluid_settings_register_int(settings, "synth.midi-channels", 16, 16, 256, 0);
+ fluid_settings_register_num(settings, "synth.gain", 0.2f, 0.0f, 10.0f, 0);
+ fluid_settings_register_int(settings, "synth.audio-channels", 1, 1, 128, 0);
+ fluid_settings_register_int(settings, "synth.audio-groups", 1, 1, 128, 0);
+ fluid_settings_register_int(settings, "synth.effects-channels", 2, 2, 2, 0);
+ fluid_settings_register_int(settings, "synth.effects-groups", 1, 1, 128, 0);
+ fluid_settings_register_num(settings, "synth.sample-rate", 44100.0f, 8000.0f, 96000.0f, 0);
+ fluid_settings_register_int(settings, "synth.device-id", 0, 0, 126, 0);
+ fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 256, 0);
+
+ fluid_settings_register_int(settings, "synth.min-note-length", 10, 0, 65535, 0);
+
+ fluid_settings_register_int(settings, "synth.threadsafe-api", 1, 0, 1, FLUID_HINT_TOGGLED);
+
+ fluid_settings_register_num(settings, "synth.overflow.percussion", 4000, -10000, 10000, 0);
+ fluid_settings_register_num(settings, "synth.overflow.sustained", -1000, -10000, 10000, 0);
+ fluid_settings_register_num(settings, "synth.overflow.released", -2000, -10000, 10000, 0);
+ fluid_settings_register_num(settings, "synth.overflow.age", 1000, -10000, 10000, 0);
+ fluid_settings_register_num(settings, "synth.overflow.volume", 500, -10000, 10000, 0);
+ fluid_settings_register_num(settings, "synth.overflow.important", 5000, -50000, 50000, 0);
+ fluid_settings_register_str(settings, "synth.overflow.important-channels", "", 0);
+
+ fluid_settings_register_str(settings, "synth.midi-bank-select", "gs", 0);
+ fluid_settings_add_option(settings, "synth.midi-bank-select", "gm");
+ fluid_settings_add_option(settings, "synth.midi-bank-select", "gs");
+ fluid_settings_add_option(settings, "synth.midi-bank-select", "xg");
+ fluid_settings_add_option(settings, "synth.midi-bank-select", "mma");
+
+ fluid_settings_register_int(settings, "synth.dynamic-sample-loading", 0, 0, 1, FLUID_HINT_TOGGLED);
}
/**
@@ -236,9 +257,9 @@ void fluid_synth_settings(fluid_settings_t* settings)
*/
void fluid_version(int *major, int *minor, int *micro)
{
- *major = FLUIDSYNTH_VERSION_MAJOR;
- *minor = FLUIDSYNTH_VERSION_MINOR;
- *micro = FLUIDSYNTH_VERSION_MICRO;
+ *major = FLUIDSYNTH_VERSION_MAJOR;
+ *minor = FLUIDSYNTH_VERSION_MINOR;
+ *micro = FLUIDSYNTH_VERSION_MICRO;
}
/**
@@ -246,25 +267,12 @@ void fluid_version(int *major, int *minor, int *micro)
* @return FluidSynth version string, which is internal and should not be
* modified or freed.
*/
-char *
-fluid_version_str (void)
+const char *
+fluid_version_str(void)
{
- return FLUIDSYNTH_VERSION;
+ return FLUIDSYNTH_VERSION;
}
-#define FLUID_API_ENTRY_CHAN(fail_value) \
- fluid_return_val_if_fail (synth != NULL, fail_value); \
- fluid_return_val_if_fail (chan >= 0, fail_value); \
- fluid_synth_api_enter(synth); \
- if (chan >= synth->midi_channels) { \
- fluid_synth_api_exit(synth); \
- return fail_value; \
- } \
-
-#define FLUID_API_RETURN(return_value) \
- do { fluid_synth_api_exit(synth); \
- return return_value; } while (0)
-
/*
* void fluid_synth_init
*
@@ -273,253 +281,286 @@ fluid_version_str (void)
static void
fluid_synth_init(void)
{
- fluid_synth_initialized++;
-
#ifdef TRAP_ON_FPE
- /* Turn on floating point exception traps */
- feenableexcept (FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID);
+ /* Turn on floating point exception traps */
+ feenableexcept(FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID);
#endif
- fluid_conversion_config();
-
- fluid_rvoice_dsp_config();
-
- fluid_sys_config();
-
- init_dither();
-
-
- /* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
- fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */
- FLUID_MOD_VELOCITY, /* Source. VELOCITY corresponds to 'index=2'. */
- FLUID_MOD_GC /* Not a MIDI continuous controller */
- | FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */
- | FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */
- | FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */
- );
- fluid_mod_set_source2(&default_vel2att_mod, 0, 0); /* No 2nd source */
- fluid_mod_set_dest(&default_vel2att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
- fluid_mod_set_amount(&default_vel2att_mod, 960.0); /* Modulation amount: 960 */
-
-
-
- /* SF2.01 page 53 section 8.4.2: MIDI Note-On Velocity to Filter Cutoff
- * Have to make a design decision here. The specs don't make any sense this way or another.
- * One sound font, 'Kingston Piano', which has been praised for its quality, tries to
- * override this modulator with an amount of 0 and positive polarity (instead of what
- * the specs say, D=1) for the secondary source.
- * So if we change the polarity to 'positive', one of the best free sound fonts works...
- */
- fluid_mod_set_source1(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_NEGATIVE /* D=1 */
- );
- fluid_mod_set_source2(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_SWITCH /* type=3 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- // do not remove | FLUID_MOD_NEGATIVE /* D=1 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_dest(&default_vel2filter_mod, GEN_FILTERFC); /* Target: Initial filter cutoff */
- fluid_mod_set_amount(&default_vel2filter_mod, -2400);
-
-
-
- /* SF2.01 page 53 section 8.4.3: MIDI Channel pressure to Vibrato LFO pitch depth */
- fluid_mod_set_source1(&default_at2viblfo_mod, FLUID_MOD_CHANNELPRESSURE, /* Index=13 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_at2viblfo_mod, 0,0); /* no second source */
- fluid_mod_set_dest(&default_at2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
- fluid_mod_set_amount(&default_at2viblfo_mod, 50);
-
-
-
- /* SF2.01 page 53 section 8.4.4: Mod wheel (Controller 1) to Vibrato LFO pitch depth */
- fluid_mod_set_source1(&default_mod2viblfo_mod, 1, /* Index=1 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_mod2viblfo_mod, 0,0); /* no second source */
- fluid_mod_set_dest(&default_mod2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
- fluid_mod_set_amount(&default_mod2viblfo_mod, 50);
-
-
-
- /* SF2.01 page 55 section 8.4.5: MIDI continuous controller 7 to initial attenuation*/
- fluid_mod_set_source1(&default_att_mod, 7, /* index=7 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_CONCAVE /* type=1 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_NEGATIVE /* D=1 */
- );
- fluid_mod_set_source2(&default_att_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
- fluid_mod_set_amount(&default_att_mod, 960.0); /* Amount: 960 */
-
-
-
- /* SF2.01 page 55 section 8.4.6 MIDI continuous controller 10 to Pan Position */
- fluid_mod_set_source1(&default_pan_mod, 10, /* index=10 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_BIPOLAR /* P=1 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_pan_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_pan_mod, GEN_PAN); /* Target: pan */
- /* Amount: 500. The SF specs $8.4.6, p. 55 syas: "Amount = 1000
- tenths of a percent". The center value (64) corresponds to 50%,
- so it follows that amount = 50% x 1000/% = 500. */
- fluid_mod_set_amount(&default_pan_mod, 500.0);
-
-
- /* SF2.01 page 55 section 8.4.7: MIDI continuous controller 11 to initial attenuation*/
- fluid_mod_set_source1(&default_expr_mod, 11, /* index=11 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_CONCAVE /* type=1 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_NEGATIVE /* D=1 */
- );
- fluid_mod_set_source2(&default_expr_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_expr_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
- fluid_mod_set_amount(&default_expr_mod, 960.0); /* Amount: 960 */
-
-
-
- /* SF2.01 page 55 section 8.4.8: MIDI continuous controller 91 to Reverb send */
- fluid_mod_set_source1(&default_reverb_mod, 91, /* index=91 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_reverb_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_reverb_mod, GEN_REVERBSEND); /* Target: Reverb send */
- fluid_mod_set_amount(&default_reverb_mod, 200); /* Amount: 200 ('tenths of a percent') */
-
-
-
- /* SF2.01 page 55 section 8.4.9: MIDI continuous controller 93 to Chorus send */
- fluid_mod_set_source1(&default_chorus_mod, 93, /* index=93 */
- FLUID_MOD_CC /* CC=1 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_chorus_mod, 0, 0); /* No second source */
- fluid_mod_set_dest(&default_chorus_mod, GEN_CHORUSSEND); /* Target: Chorus */
- fluid_mod_set_amount(&default_chorus_mod, 200); /* Amount: 200 ('tenths of a percent') */
-
-
-
- /* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */
- fluid_mod_set_source1(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEEL, /* Index=14 */
- FLUID_MOD_GC /* CC =0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_BIPOLAR /* P=1 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_source2(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEELSENS, /* Index = 16 */
- FLUID_MOD_GC /* CC=0 */
- | FLUID_MOD_LINEAR /* type=0 */
- | FLUID_MOD_UNIPOLAR /* P=0 */
- | FLUID_MOD_POSITIVE /* D=0 */
- );
- fluid_mod_set_dest(&default_pitch_bend_mod, GEN_PITCH); /* Destination: Initial pitch */
- fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */
-}
-
-static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t* synth)
-{
- if (synth->eventhandler->is_threadsafe)
+ fluid_conversion_config();
+
+ fluid_rvoice_dsp_config();
+
+ init_dither();
+
+ /* custom_breath2att_mod is not a default modulator specified in SF2.01.
+ it is intended to replace default_vel2att_mod on demand using
+ API fluid_set_breath_mode() or command shell setbreathmode.
+ */
+ fluid_mod_set_source1(&custom_breath2att_mod, /* The modulator we are programming here */
+ BREATH_MSB, /* Source. breath MSB corresponds to 2. */
+ FLUID_MOD_CC /* MIDI continuous controller */
+ | FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */
+ | FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */
+ | FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */
+ );
+ fluid_mod_set_source2(&custom_breath2att_mod, 0, 0); /* No 2nd source */
+ fluid_mod_set_dest(&custom_breath2att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
+ fluid_mod_set_amount(&custom_breath2att_mod, FLUID_PEAK_ATTENUATION); /* Modulation amount: 960 */
+
+ /* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
+ fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */
+ FLUID_MOD_VELOCITY, /* Source. VELOCITY corresponds to 'index=2'. */
+ FLUID_MOD_GC /* Not a MIDI continuous controller */
+ | FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */
+ | FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */
+ | FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */
+ );
+ fluid_mod_set_source2(&default_vel2att_mod, 0, 0); /* No 2nd source */
+ fluid_mod_set_dest(&default_vel2att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
+ fluid_mod_set_amount(&default_vel2att_mod, FLUID_PEAK_ATTENUATION); /* Modulation amount: 960 */
+
+
+
+ /* SF2.01 page 53 section 8.4.2: MIDI Note-On Velocity to Filter Cutoff
+ * Have to make a design decision here. The specs don't make any sense this way or another.
+ * One sound font, 'Kingston Piano', which has been praised for its quality, tries to
+ * override this modulator with an amount of 0 and positive polarity (instead of what
+ * the specs say, D=1) for the secondary source.
+ * So if we change the polarity to 'positive', one of the best free sound fonts works...
+ */
+ fluid_mod_set_source1(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
+ FLUID_MOD_GC /* CC=0 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_NEGATIVE /* D=1 */
+ );
+ fluid_mod_set_source2(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */
+ FLUID_MOD_GC /* CC=0 */
+ | FLUID_MOD_SWITCH /* type=3 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ // do not remove | FLUID_MOD_NEGATIVE /* D=1 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_dest(&default_vel2filter_mod, GEN_FILTERFC); /* Target: Initial filter cutoff */
+ fluid_mod_set_amount(&default_vel2filter_mod, -2400);
+
+
+
+ /* SF2.01 page 53 section 8.4.3: MIDI Channel pressure to Vibrato LFO pitch depth */
+ fluid_mod_set_source1(&default_at2viblfo_mod, FLUID_MOD_CHANNELPRESSURE, /* Index=13 */
+ FLUID_MOD_GC /* CC=0 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_source2(&default_at2viblfo_mod, 0, 0); /* no second source */
+ fluid_mod_set_dest(&default_at2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
+ fluid_mod_set_amount(&default_at2viblfo_mod, 50);
+
+
+
+ /* SF2.01 page 53 section 8.4.4: Mod wheel (Controller 1) to Vibrato LFO pitch depth */
+ fluid_mod_set_source1(&default_mod2viblfo_mod, MODULATION_MSB, /* Index=1 */
+ FLUID_MOD_CC /* CC=1 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_source2(&default_mod2viblfo_mod, 0, 0); /* no second source */
+ fluid_mod_set_dest(&default_mod2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */
+ fluid_mod_set_amount(&default_mod2viblfo_mod, 50);
+
+
+
+ /* SF2.01 page 55 section 8.4.5: MIDI continuous controller 7 to initial attenuation*/
+ fluid_mod_set_source1(&default_att_mod, VOLUME_MSB, /* index=7 */
+ FLUID_MOD_CC /* CC=1 */
+ | FLUID_MOD_CONCAVE /* type=1 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_NEGATIVE /* D=1 */
+ );
+ fluid_mod_set_source2(&default_att_mod, 0, 0); /* No second source */
+ fluid_mod_set_dest(&default_att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
+ fluid_mod_set_amount(&default_att_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */
+
+
+
+ /* SF2.01 page 55 section 8.4.6 MIDI continuous controller 10 to Pan Position */
+ fluid_mod_set_source1(&default_pan_mod, PAN_MSB, /* index=10 */
+ FLUID_MOD_CC /* CC=1 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_BIPOLAR /* P=1 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_source2(&default_pan_mod, 0, 0); /* No second source */
+ fluid_mod_set_dest(&default_pan_mod, GEN_PAN); /* Target: pan */
+ /* Amount: 500. The SF specs $8.4.6, p. 55 syas: "Amount = 1000
+ tenths of a percent". The center value (64) corresponds to 50%,
+ so it follows that amount = 50% x 1000/% = 500. */
+ fluid_mod_set_amount(&default_pan_mod, 500.0);
+
+
+ /* SF2.01 page 55 section 8.4.7: MIDI continuous controller 11 to initial attenuation*/
+ fluid_mod_set_source1(&default_expr_mod, EXPRESSION_MSB, /* index=11 */
+ FLUID_MOD_CC /* CC=1 */
+ | FLUID_MOD_CONCAVE /* type=1 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_NEGATIVE /* D=1 */
+ );
+ fluid_mod_set_source2(&default_expr_mod, 0, 0); /* No second source */
+ fluid_mod_set_dest(&default_expr_mod, GEN_ATTENUATION); /* Target: Initial attenuation */
+ fluid_mod_set_amount(&default_expr_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */
+
+
+
+ /* SF2.01 page 55 section 8.4.8: MIDI continuous controller 91 to Reverb send */
+ fluid_mod_set_source1(&default_reverb_mod, EFFECTS_DEPTH1, /* index=91 */
+ FLUID_MOD_CC /* CC=1 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_source2(&default_reverb_mod, 0, 0); /* No second source */
+ fluid_mod_set_dest(&default_reverb_mod, GEN_REVERBSEND); /* Target: Reverb send */
+ fluid_mod_set_amount(&default_reverb_mod, 200); /* Amount: 200 ('tenths of a percent') */
+
+
+
+ /* SF2.01 page 55 section 8.4.9: MIDI continuous controller 93 to Chorus send */
+ fluid_mod_set_source1(&default_chorus_mod, EFFECTS_DEPTH3, /* index=93 */
+ FLUID_MOD_CC /* CC=1 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_source2(&default_chorus_mod, 0, 0); /* No second source */
+ fluid_mod_set_dest(&default_chorus_mod, GEN_CHORUSSEND); /* Target: Chorus */
+ fluid_mod_set_amount(&default_chorus_mod, 200); /* Amount: 200 ('tenths of a percent') */
+
+
+
+ /* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */
+ fluid_mod_set_source1(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEEL, /* Index=14 */
+ FLUID_MOD_GC /* CC =0 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_BIPOLAR /* P=1 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_source2(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEELSENS, /* Index = 16 */
+ FLUID_MOD_GC /* CC=0 */
+ | FLUID_MOD_LINEAR /* type=0 */
+ | FLUID_MOD_UNIPOLAR /* P=0 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_dest(&default_pitch_bend_mod, GEN_PITCH); /* Destination: Initial pitch */
+ fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */
+
+
+ /* Non-standard MIDI continuous controller 8 to channel stereo balance */
+ fluid_mod_set_source1(&custom_balance_mod, BALANCE_MSB, /* Index=8 */
+ FLUID_MOD_CC /* CC=1 */
+ | FLUID_MOD_CONCAVE /* type=1 */
+ | FLUID_MOD_BIPOLAR /* P=1 */
+ | FLUID_MOD_POSITIVE /* D=0 */
+ );
+ fluid_mod_set_source2(&custom_balance_mod, 0, 0);
+ fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */
+ /* Amount: 96 dB of attenuation (on the opposite channel) */
+ fluid_mod_set_amount(&custom_balance_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */
+}
+
+static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t *synth)
+{
return fluid_atomic_int_get(&synth->ticks_since_start);
- else
- return synth->ticks_since_start;
}
-static FLUID_INLINE void fluid_synth_add_ticks(fluid_synth_t* synth, int val)
+static FLUID_INLINE void fluid_synth_add_ticks(fluid_synth_t *synth, int val)
{
- if (synth->eventhandler->is_threadsafe)
- fluid_atomic_int_add((int*) &synth->ticks_since_start, val);
- else
- synth->ticks_since_start += val;
+ fluid_atomic_int_add(&synth->ticks_since_start, val);
}
/***************************************************************
- * FLUID SAMPLE TIMERS
- * Timers that use written audio data as timing reference
+ * FLUID SAMPLE TIMERS
+ * Timers that use written audio data as timing reference
*/
struct _fluid_sample_timer_t
{
- fluid_sample_timer_t* next; /* Single linked list of timers */
- unsigned long starttick;
- fluid_timer_callback_t callback;
- void* data;
- int isfinished;
+ fluid_sample_timer_t *next; /* Single linked list of timers */
+ unsigned long starttick;
+ fluid_timer_callback_t callback;
+ void *data;
+ int isfinished;
};
/*
* fluid_sample_timer_process - called when synth->ticks is updated
*/
-static void fluid_sample_timer_process(fluid_synth_t* synth)
-{
- fluid_sample_timer_t* st;
- long msec;
- int cont;
- unsigned int ticks = fluid_synth_get_ticks(synth);
-
- for (st=synth->sample_timers; st; st=st->next) {
- if (st->isfinished) {
- continue;
- }
-
- msec = (long) (1000.0*((double) (ticks - st->starttick))/synth->sample_rate);
- cont = (*st->callback)(st->data, msec);
- if (cont == 0) {
- st->isfinished = 1;
- }
- }
-}
-
-fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data)
-{
- fluid_sample_timer_t* result = FLUID_NEW(fluid_sample_timer_t);
- if (result == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- result->starttick = fluid_synth_get_ticks(synth);
- result->isfinished = 0;
- result->data = data;
- result->callback = callback;
- result->next = synth->sample_timers;
- synth->sample_timers = result;
- return result;
-}
-
-int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer)
-{
- fluid_sample_timer_t** ptr = &synth->sample_timers;
- while (*ptr) {
- if (*ptr == timer) {
- *ptr = timer->next;
- FLUID_FREE(timer);
- return FLUID_OK;
- }
- ptr = &((*ptr)->next);
- }
- FLUID_LOG(FLUID_ERR,"delete_fluid_sample_timer failed, no timer found");
- return FLUID_FAILED;
+static void fluid_sample_timer_process(fluid_synth_t *synth)
+{
+ fluid_sample_timer_t *st, *stnext;
+ long msec;
+ int cont;
+ unsigned int ticks = fluid_synth_get_ticks(synth);
+
+ for(st = synth->sample_timers; st; st = stnext)
+ {
+ /* st may be freed in the callback below. cache it's successor now to avoid use after free */
+ stnext = st->next;
+
+ if(st->isfinished)
+ {
+ continue;
+ }
+
+ msec = (long)(1000.0 * ((double)(ticks - st->starttick)) / synth->sample_rate);
+ cont = (*st->callback)(st->data, msec);
+
+ if(cont == 0)
+ {
+ st->isfinished = 1;
+ }
+ }
+}
+
+fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data)
+{
+ fluid_sample_timer_t *result = FLUID_NEW(fluid_sample_timer_t);
+
+ if(result == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ result->starttick = fluid_synth_get_ticks(synth);
+ result->isfinished = 0;
+ result->data = data;
+ result->callback = callback;
+ result->next = synth->sample_timers;
+ synth->sample_timers = result;
+ return result;
+}
+
+void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer)
+{
+ fluid_sample_timer_t **ptr;
+ fluid_return_if_fail(synth != NULL);
+ fluid_return_if_fail(timer != NULL);
+
+ ptr = &synth->sample_timers;
+
+ while(*ptr)
+ {
+ if(*ptr == timer)
+ {
+ *ptr = timer->next;
+ FLUID_FREE(timer);
+ return;
+ }
+
+ ptr = &((*ptr)->next);
+ }
}
@@ -529,362 +570,536 @@ int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer)
*/
static FLUID_INLINE void
-fluid_synth_update_mixer(fluid_synth_t* synth, void* method, int intparam,
- fluid_real_t realparam)
+fluid_synth_update_mixer(fluid_synth_t *synth, fluid_rvoice_function_t method, int intparam,
+ fluid_real_t realparam)
{
- fluid_return_if_fail(synth != NULL || synth->eventhandler != NULL);
- fluid_return_if_fail(synth->eventhandler->mixer != NULL);
- fluid_rvoice_eventhandler_push(synth->eventhandler, method,
- synth->eventhandler->mixer,
- intparam, realparam);
+ fluid_return_if_fail(synth != NULL && synth->eventhandler != NULL);
+ fluid_return_if_fail(synth->eventhandler->mixer != NULL);
+ fluid_rvoice_eventhandler_push_int_real(synth->eventhandler, method,
+ synth->eventhandler->mixer,
+ intparam, realparam);
}
+static FLUID_INLINE unsigned int fluid_synth_get_min_note_length_LOCAL(fluid_synth_t *synth)
+{
+ int i;
+ fluid_settings_getint(synth->settings, "synth.min-note-length", &i);
+ return (unsigned int)(i * synth->sample_rate / 1000.0f);
+}
/**
* Create new FluidSynth instance.
* @param settings Configuration parameters to use (used directly).
* @return New FluidSynth instance or NULL on error
*
- * NOTE: The settings parameter is used directly and should not be modified
+ * @note The settings parameter is used directly and should not be modified
* or freed independently.
*/
-fluid_synth_t*
+fluid_synth_t *
new_fluid_synth(fluid_settings_t *settings)
{
- fluid_synth_t* synth;
- fluid_sfloader_t* loader;
- double gain;
- int i, nbuf;
+ fluid_synth_t *synth;
+ fluid_sfloader_t *loader;
+ char *important_channels;
+ int i, nbuf, prio_level = 0;
+ int with_ladspa = 0;
- /* initialize all the conversion tables and other stuff */
- if (fluid_synth_initialized == 0) {
- fluid_synth_init();
- }
+ /* initialize all the conversion tables and other stuff */
+ if(fluid_atomic_int_compare_and_exchange(&fluid_synth_initialized, 0, 1))
+ {
+ fluid_synth_init();
+ }
- /* allocate a new synthesizer object */
- synth = FLUID_NEW(fluid_synth_t);
- if (synth == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
-
- fluid_rec_mutex_init(synth->mutex);
- fluid_settings_getint(settings, "synth.threadsafe-api", &synth->use_mutex);
- synth->public_api_count = 0;
-
- synth->settings = settings;
-
- fluid_settings_getint(settings, "synth.reverb.active", &synth->with_reverb);
- fluid_settings_getint(settings, "synth.chorus.active", &synth->with_chorus);
- fluid_settings_getint(settings, "synth.verbose", &synth->verbose);
- fluid_settings_getint(settings, "synth.dump", &synth->dump);
-
- fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony);
- fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate);
- fluid_settings_getint(settings, "synth.midi-channels", &synth->midi_channels);
- fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels);
- fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
- fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
- fluid_settings_getnum(settings, "synth.gain", &gain);
- synth->gain = gain;
- fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
- fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
-
- /* register the callbacks */
- fluid_settings_register_num(settings, "synth.sample-rate",
- 44100.0f, 8000.0f, 96000.0f, 0,
- (fluid_num_update_t) fluid_synth_update_sample_rate, synth);
- fluid_settings_register_num(settings, "synth.gain",
- 0.2f, 0.0f, 10.0f, 0,
- (fluid_num_update_t) fluid_synth_update_gain, synth);
- fluid_settings_register_int(settings, "synth.polyphony",
- synth->polyphony, 1, 65535, 0,
- (fluid_int_update_t) fluid_synth_update_polyphony,
- synth);
- fluid_settings_register_int(settings, "synth.device-id",
- synth->device_id, 126, 0, 0,
- (fluid_int_update_t) fluid_synth_update_device_id, synth);
-
- fluid_synth_register_overflow(settings,
- (fluid_num_update_t) fluid_synth_update_overflow, synth);
-
- /* do some basic sanity checking on the settings */
-
- if (synth->midi_channels % 16 != 0) {
- int n = synth->midi_channels / 16;
- synth->midi_channels = (n + 1) * 16;
- fluid_settings_setint(settings, "synth.midi-channels", synth->midi_channels);
- FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is not a multiple of 16. "
- "I'll increase the number of channels to the next multiple.");
- }
-
- if (synth->audio_channels < 1) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio channels is smaller than 1. "
- "Changing this setting to 1.");
- synth->audio_channels = 1;
- } else if (synth->audio_channels > 128) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio channels is too big (%d). "
- "Limiting this setting to 128.", synth->audio_channels);
- synth->audio_channels = 128;
- }
-
- if (synth->audio_groups < 1) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio groups is smaller than 1. "
- "Changing this setting to 1.");
- synth->audio_groups = 1;
- } else if (synth->audio_groups > 128) {
- FLUID_LOG(FLUID_WARN, "Requested number of audio groups is too big (%d). "
- "Limiting this setting to 128.", synth->audio_groups);
- synth->audio_groups = 128;
- }
-
- if (synth->effects_channels < 2) {
- FLUID_LOG(FLUID_WARN, "Invalid number of effects channels (%d)."
- "Setting effects channels to 2.", synth->effects_channels);
- synth->effects_channels = 2;
- }
-
-
- /* The number of buffers is determined by the higher number of nr
- * groups / nr audio channels. If LADSPA is unused, they should be
- * the same. */
- nbuf = synth->audio_channels;
- if (synth->audio_groups > nbuf) {
- nbuf = synth->audio_groups;
- }
-
- /* as soon as the synth is created it starts playing. */
- synth->state = FLUID_SYNTH_PLAYING;
- synth->sfont_info = NULL;
- synth->sfont_hash = new_fluid_hashtable (NULL, NULL);
- synth->noteid = 0;
- synth->ticks_since_start = 0;
- synth->tuning = NULL;
- fluid_private_init(synth->tuning_iter);
-
- /* Allocate event queue for rvoice mixer */
- fluid_settings_getint(settings, "synth.parallel-render", &i);
- /* In an overflow situation, a new voice takes about 50 spaces in the queue! */
- synth->eventhandler = new_fluid_rvoice_eventhandler(i, synth->polyphony*64,
- synth->polyphony, nbuf, synth->effects_channels, synth->sample_rate);
-
- if (synth->eventhandler == NULL)
- goto error_recovery;
+ /* allocate a new synthesizer object */
+ synth = FLUID_NEW(fluid_synth_t);
+ if(synth == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
+
+ fluid_rec_mutex_init(synth->mutex);
+ fluid_settings_getint(settings, "synth.threadsafe-api", &synth->use_mutex);
+ synth->public_api_count = 0;
+
+ synth->settings = settings;
+
+ fluid_settings_getint(settings, "synth.reverb.active", &synth->with_reverb);
+ fluid_settings_getint(settings, "synth.chorus.active", &synth->with_chorus);
+ fluid_settings_getint(settings, "synth.verbose", &synth->verbose);
+
+ fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony);
+ fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate);
+ fluid_settings_getint(settings, "synth.midi-channels", &synth->midi_channels);
+ fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels);
+ fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
+ fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
+ fluid_settings_getint(settings, "synth.effects-groups", &synth->effects_groups);
+ fluid_settings_getnum_float(settings, "synth.gain", &synth->gain);
+ fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
+ fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
+
+ fluid_settings_getnum_float(settings, "synth.overflow.percussion", &synth->overflow.percussion);
+ fluid_settings_getnum_float(settings, "synth.overflow.released", &synth->overflow.released);
+ fluid_settings_getnum_float(settings, "synth.overflow.sustained", &synth->overflow.sustained);
+ fluid_settings_getnum_float(settings, "synth.overflow.volume", &synth->overflow.volume);
+ fluid_settings_getnum_float(settings, "synth.overflow.age", &synth->overflow.age);
+ fluid_settings_getnum_float(settings, "synth.overflow.important", &synth->overflow.important);
+
+ /* register the callbacks */
+ fluid_settings_callback_num(settings, "synth.sample-rate",
+ fluid_synth_handle_sample_rate, synth);
+ fluid_settings_callback_num(settings, "synth.gain",
+ fluid_synth_handle_gain, synth);
+ fluid_settings_callback_int(settings, "synth.polyphony",
+ fluid_synth_handle_polyphony, synth);
+ fluid_settings_callback_int(settings, "synth.device-id",
+ fluid_synth_handle_device_id, synth);
+ fluid_settings_callback_num(settings, "synth.overflow.percussion",
+ fluid_synth_handle_overflow, synth);
+ fluid_settings_callback_num(settings, "synth.overflow.sustained",
+ fluid_synth_handle_overflow, synth);
+ fluid_settings_callback_num(settings, "synth.overflow.released",
+ fluid_synth_handle_overflow, synth);
+ fluid_settings_callback_num(settings, "synth.overflow.age",
+ fluid_synth_handle_overflow, synth);
+ fluid_settings_callback_num(settings, "synth.overflow.volume",
+ fluid_synth_handle_overflow, synth);
+ fluid_settings_callback_num(settings, "synth.overflow.important",
+ fluid_synth_handle_overflow, synth);
+ fluid_settings_callback_str(settings, "synth.overflow.important-channels",
+ fluid_synth_handle_important_channels, synth);
+ fluid_settings_callback_num(settings, "synth.reverb.room-size",
+ fluid_synth_handle_reverb_chorus_num, synth);
+ fluid_settings_callback_num(settings, "synth.reverb.damp",
+ fluid_synth_handle_reverb_chorus_num, synth);
+ fluid_settings_callback_num(settings, "synth.reverb.width",
+ fluid_synth_handle_reverb_chorus_num, synth);
+ fluid_settings_callback_num(settings, "synth.reverb.level",
+ fluid_synth_handle_reverb_chorus_num, synth);
+ fluid_settings_callback_int(settings, "synth.reverb.active",
+ fluid_synth_handle_reverb_chorus_int, synth);
+ fluid_settings_callback_int(settings, "synth.chorus.active",
+ fluid_synth_handle_reverb_chorus_int, synth);
+ fluid_settings_callback_int(settings, "synth.chorus.nr",
+ fluid_synth_handle_reverb_chorus_int, synth);
+ fluid_settings_callback_num(settings, "synth.chorus.level",
+ fluid_synth_handle_reverb_chorus_num, synth);
+ fluid_settings_callback_num(settings, "synth.chorus.depth",
+ fluid_synth_handle_reverb_chorus_num, synth);
+ fluid_settings_callback_num(settings, "synth.chorus.speed",
+ fluid_synth_handle_reverb_chorus_num, synth);
+
+ /* do some basic sanity checking on the settings */
+
+ if(synth->midi_channels % 16 != 0)
+ {
+ int n = synth->midi_channels / 16;
+ synth->midi_channels = (n + 1) * 16;
+ fluid_settings_setint(settings, "synth.midi-channels", synth->midi_channels);
+ FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is not a multiple of 16. "
+ "I'll increase the number of channels to the next multiple.");
+ }
+
+ if(synth->audio_channels < 1)
+ {
+ FLUID_LOG(FLUID_WARN, "Requested number of audio channels is smaller than 1. "
+ "Changing this setting to 1.");
+ synth->audio_channels = 1;
+ }
+ else if(synth->audio_channels > 128)
+ {
+ FLUID_LOG(FLUID_WARN, "Requested number of audio channels is too big (%d). "
+ "Limiting this setting to 128.", synth->audio_channels);
+ synth->audio_channels = 128;
+ }
+
+ if(synth->audio_groups < 1)
+ {
+ FLUID_LOG(FLUID_WARN, "Requested number of audio groups is smaller than 1. "
+ "Changing this setting to 1.");
+ synth->audio_groups = 1;
+ }
+ else if(synth->audio_groups > 128)
+ {
+ FLUID_LOG(FLUID_WARN, "Requested number of audio groups is too big (%d). "
+ "Limiting this setting to 128.", synth->audio_groups);
+ synth->audio_groups = 128;
+ }
+
+ if(synth->effects_channels < 2)
+ {
+ FLUID_LOG(FLUID_WARN, "Invalid number of effects channels (%d)."
+ "Setting effects channels to 2.", synth->effects_channels);
+ synth->effects_channels = 2;
+ }
+
+ /* The number of buffers is determined by the higher number of nr
+ * groups / nr audio channels. If LADSPA is unused, they should be
+ * the same. */
+ nbuf = synth->audio_channels;
+
+ if(synth->audio_groups > nbuf)
+ {
+ nbuf = synth->audio_groups;
+ }
+
+ if(fluid_settings_dupstr(settings, "synth.overflow.important-channels",
+ &important_channels) == FLUID_OK)
+ {
+ if(fluid_synth_set_important_channels(synth, important_channels) != FLUID_OK)
+ {
+ FLUID_LOG(FLUID_WARN, "Failed to set overflow important channels");
+ }
+
+ FLUID_FREE(important_channels);
+ }
+
+ /* as soon as the synth is created it starts playing. */
+ synth->state = FLUID_SYNTH_PLAYING;
+
+ synth->fromkey_portamento = INVALID_NOTE; /* disable portamento */
+
+ fluid_atomic_int_set(&synth->ticks_since_start, 0);
+ synth->tuning = NULL;
+ fluid_private_init(synth->tuning_iter);
+
+ /* Initialize multi-core variables if multiple cores enabled */
+ if(synth->cores > 1)
+ {
+ fluid_settings_getint(synth->settings, "audio.realtime-prio", &prio_level);
+ }
+
+ /* Allocate event queue for rvoice mixer */
+ /* In an overflow situation, a new voice takes about 50 spaces in the queue! */
+ synth->eventhandler = new_fluid_rvoice_eventhandler(synth->polyphony * 64,
+ synth->polyphony, nbuf, synth->effects_channels, synth->effects_groups, synth->sample_rate, synth->cores - 1, prio_level);
+
+ if(synth->eventhandler == NULL)
+ {
+ goto error_recovery;
+ }
+
+ /* Setup the list of default modulators.
+ * Needs to happen after eventhandler has been set up, as fluid_synth_enter_api is called in the process */
+ synth->default_mod = NULL;
+ fluid_synth_add_default_mod(synth, &default_vel2att_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_vel2filter_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_at2viblfo_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_mod2viblfo_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_att_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_pan_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_expr_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_reverb_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_chorus_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &default_pitch_bend_mod, FLUID_SYNTH_ADD);
+ fluid_synth_add_default_mod(synth, &custom_balance_mod, FLUID_SYNTH_ADD);
+
+ /* Create and initialize the Fx unit.*/
+ fluid_settings_getint(settings, "synth.ladspa.active", &with_ladspa);
+
+ if(with_ladspa)
+ {
#ifdef LADSPA
- /* Create and initialize the Fx unit.*/
- synth->LADSPA_FxUnit = new_fluid_LADSPA_FxUnit(synth);
- fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->LADSPA_FxUnit);
-#endif
-
- /* allocate and add the default sfont loader */
- loader = new_fluid_defsfloader(settings);
-
- if (loader == NULL) {
- FLUID_LOG(FLUID_WARN, "Failed to create the default SoundFont loader");
- } else {
- fluid_synth_add_sfloader(synth, loader);
- }
-
- /* allocate all channel objects */
- synth->channel = FLUID_ARRAY(fluid_channel_t*, synth->midi_channels);
- if (synth->channel == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- goto error_recovery;
- }
- for (i = 0; i < synth->midi_channels; i++) {
- synth->channel[i] = new_fluid_channel(synth, i);
- if (synth->channel[i] == NULL) {
- goto error_recovery;
- }
- }
-
- /* allocate all synthesis processes */
- synth->nvoice = synth->polyphony;
- synth->voice = FLUID_ARRAY(fluid_voice_t*, synth->nvoice);
- if (synth->voice == NULL) {
- goto error_recovery;
- }
- for (i = 0; i < synth->nvoice; i++) {
- synth->voice[i] = new_fluid_voice(synth->sample_rate);
- if (synth->voice[i] == NULL) {
- goto error_recovery;
- }
- }
-
- fluid_synth_set_sample_rate(synth, synth->sample_rate);
-
- fluid_synth_update_overflow(synth, "", 0.0f);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
- synth->polyphony, 0.0f);
- fluid_synth_set_reverb_on(synth, synth->with_reverb);
- fluid_synth_set_chorus_on(synth, synth->with_chorus);
-
- synth->cur = FLUID_BUFSIZE;
- synth->curmax = 0;
- synth->dither_index = 0;
-
- synth->reverb_roomsize = FLUID_REVERB_DEFAULT_ROOMSIZE;
- synth->reverb_damping = FLUID_REVERB_DEFAULT_DAMP;
- synth->reverb_width = FLUID_REVERB_DEFAULT_WIDTH;
- synth->reverb_level = FLUID_REVERB_DEFAULT_LEVEL;
-
- fluid_rvoice_eventhandler_push5(synth->eventhandler,
- fluid_rvoice_mixer_set_reverb_params,
- synth->eventhandler->mixer,
- FLUID_REVMODEL_SET_ALL, synth->reverb_roomsize,
- synth->reverb_damping, synth->reverb_width,
- synth->reverb_level, 0.0f);
-
- /* Initialize multi-core variables if multiple cores enabled */
- if (synth->cores > 1)
- {
- int prio_level = 0;
- fluid_settings_getint (synth->settings, "audio.realtime-prio", &prio_level);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_threads,
- synth->cores-1, prio_level);
- }
-
- synth->bank_select = FLUID_BANK_STYLE_GS;
- if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "gm") == 1)
- synth->bank_select = FLUID_BANK_STYLE_GM;
- else if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "gs") == 1)
+ synth->ladspa_fx = new_fluid_ladspa_fx(synth->sample_rate,
+ FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE);
+
+ if(synth->ladspa_fx == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+
+ fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->ladspa_fx,
+ synth->audio_groups);
+#else /* LADSPA */
+ FLUID_LOG(FLUID_WARN, "FluidSynth has not been compiled with LADSPA support");
+#endif /* LADSPA */
+ }
+
+ /* allocate and add the default sfont loader */
+ loader = new_fluid_defsfloader(settings);
+
+ if(loader == NULL)
+ {
+ FLUID_LOG(FLUID_WARN, "Failed to create the default SoundFont loader");
+ }
+ else
+ {
+ fluid_synth_add_sfloader(synth, loader);
+ }
+
+ /* allocate all channel objects */
+ synth->channel = FLUID_ARRAY(fluid_channel_t *, synth->midi_channels);
+
+ if(synth->channel == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+
+ for(i = 0; i < synth->midi_channels; i++)
+ {
+ synth->channel[i] = new_fluid_channel(synth, i);
+
+ if(synth->channel[i] == NULL)
+ {
+ goto error_recovery;
+ }
+ }
+
+ /* allocate all synthesis processes */
+ synth->nvoice = synth->polyphony;
+ synth->voice = FLUID_ARRAY(fluid_voice_t *, synth->nvoice);
+
+ if(synth->voice == NULL)
+ {
+ goto error_recovery;
+ }
+
+ for(i = 0; i < synth->nvoice; i++)
+ {
+ synth->voice[i] = new_fluid_voice(synth->eventhandler, synth->sample_rate);
+
+ if(synth->voice[i] == NULL)
+ {
+ goto error_recovery;
+ }
+ }
+
+ /* sets a default basic channel */
+ /* Sets one basic channel: basic channel 0, mode 0 (Omni On - Poly) */
+ /* (i.e all channels are polyphonic) */
+ /* Must be called after channel objects allocation */
+ fluid_synth_set_basic_channel_LOCAL(synth, 0, FLUID_CHANNEL_MODE_OMNION_POLY,
+ synth->midi_channels);
+
+ synth->min_note_length_ticks = fluid_synth_get_min_note_length_LOCAL(synth);
+
+
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
+ synth->polyphony, 0.0f);
+ fluid_synth_set_reverb_on(synth, synth->with_reverb);
+ fluid_synth_set_chorus_on(synth, synth->with_chorus);
+
+ synth->cur = FLUID_BUFSIZE;
+ synth->curmax = 0;
+ synth->dither_index = 0;
+
+ {
+ double room, damp, width, level;
+
+ fluid_settings_getnum(settings, "synth.reverb.room-size", &room);
+ fluid_settings_getnum(settings, "synth.reverb.damp", &damp);
+ fluid_settings_getnum(settings, "synth.reverb.width", &width);
+ fluid_settings_getnum(settings, "synth.reverb.level", &level);
+
+ fluid_synth_set_reverb_full_LOCAL(synth,
+ FLUID_REVMODEL_SET_ALL,
+ room,
+ damp,
+ width,
+ level);
+ }
+
+ {
+ double level, speed, depth;
+
+ fluid_settings_getint(settings, "synth.chorus.nr", &i);
+ fluid_settings_getnum(settings, "synth.chorus.level", &level);
+ fluid_settings_getnum(settings, "synth.chorus.speed", &speed);
+ fluid_settings_getnum(settings, "synth.chorus.depth", &depth);
+
+ fluid_synth_set_chorus_full_LOCAL(synth,
+ FLUID_CHORUS_SET_ALL,
+ i,
+ level,
+ speed,
+ depth,
+ FLUID_CHORUS_DEFAULT_TYPE);
+ }
+
+
synth->bank_select = FLUID_BANK_STYLE_GS;
- else if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "xg") == 1)
- synth->bank_select = FLUID_BANK_STYLE_XG;
- else if (fluid_settings_str_equal (settings, "synth.midi-bank-select", "mma") == 1)
- synth->bank_select = FLUID_BANK_STYLE_MMA;
- fluid_synth_process_event_queue(synth);
+ if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "gm"))
+ {
+ synth->bank_select = FLUID_BANK_STYLE_GM;
+ }
+ else if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "gs"))
+ {
+ synth->bank_select = FLUID_BANK_STYLE_GS;
+ }
+ else if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "xg"))
+ {
+ synth->bank_select = FLUID_BANK_STYLE_XG;
+ }
+ else if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "mma"))
+ {
+ synth->bank_select = FLUID_BANK_STYLE_MMA;
+ }
- /* FIXME */
- synth->start = fluid_curtime();
+ fluid_synth_process_event_queue(synth);
- return synth;
+ /* FIXME */
+ synth->start = fluid_curtime();
- error_recovery:
- delete_fluid_synth(synth);
- return NULL;
+ return synth;
+
+error_recovery:
+ delete_fluid_synth(synth);
+ return NULL;
}
/**
* Delete a FluidSynth instance.
* @param synth FluidSynth instance to delete
- * @return FLUID_OK
*
- * NOTE: Other users of a synthesizer instance, such as audio and MIDI drivers,
+ * @note Other users of a synthesizer instance, such as audio and MIDI drivers,
* should be deleted prior to freeing the FluidSynth instance.
*/
-int
-delete_fluid_synth(fluid_synth_t* synth)
+void
+delete_fluid_synth(fluid_synth_t *synth)
{
- int i, k;
- fluid_list_t *list;
- fluid_sfont_info_t* sfont_info;
-// fluid_event_queue_t* queue;
- fluid_sfloader_t* loader;
+ int i, k;
+ fluid_list_t *list;
+ fluid_sfont_t *sfont;
+ fluid_sfloader_t *loader;
+ fluid_mod_t *default_mod;
+ fluid_mod_t *mod;
- if (synth == NULL) {
- return FLUID_OK;
- }
-
- fluid_profiling_print();
-
- /* turn off all voices, needed to unload SoundFont data */
- if (synth->voice != NULL) {
- for (i = 0; i < synth->nvoice; i++) {
- fluid_voice_t* voice = synth->voice[i];
- if (!voice)
- continue;
- fluid_voice_unlock_rvoice(voice);
- fluid_voice_overflow_rvoice_finished(voice);
- if (fluid_voice_is_playing(voice))
- fluid_voice_off(voice);
- }
- }
-
- /* also unset all presets for clean SoundFont unload */
- if (synth->channel != NULL)
- for (i = 0; i < synth->midi_channels; i++)
- if (synth->channel[i] != NULL)
- fluid_channel_set_preset(synth->channel[i], NULL);
-
- if (synth->eventhandler)
- delete_fluid_rvoice_eventhandler(synth->eventhandler);
+ fluid_return_if_fail(synth != NULL);
+
+ fluid_profiling_print();
+
+ /* turn off all voices, needed to unload SoundFont data */
+ if(synth->voice != NULL)
+ {
+ for(i = 0; i < synth->nvoice; i++)
+ {
+ fluid_voice_t *voice = synth->voice[i];
+
+ if(!voice)
+ {
+ continue;
+ }
+
+ fluid_voice_unlock_rvoice(voice);
+ fluid_voice_overflow_rvoice_finished(voice);
+
+ if(fluid_voice_is_playing(voice))
+ {
+ fluid_voice_off(voice);
+ /* If we only use fluid_voice_off(voice) it will trigger a delayed
+ * fluid_voice_stop(voice) via fluid_synth_check_finished_voices().
+ * But here, we are deleting the fluid_synth_t instance so
+ * fluid_voice_stop() will be never triggered resulting in
+ * SoundFont data never unloaded (i.e a serious memory leak).
+ * So, fluid_voice_stop() must be explicitly called to insure
+ * unloading SoundFont data
+ */
+ fluid_voice_stop(voice);
+ }
+ }
+ }
- /* delete all the SoundFonts */
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
- delete_fluid_sfont (sfont_info->sfont);
- FLUID_FREE (sfont_info);
- }
+ /* also unset all presets for clean SoundFont unload */
+ if(synth->channel != NULL)
+ {
+ for(i = 0; i < synth->midi_channels; i++)
+ {
+ fluid_channel_set_preset(synth->channel[i], NULL);
+ }
+ }
- delete_fluid_list(synth->sfont_info);
+ delete_fluid_rvoice_eventhandler(synth->eventhandler);
+ /* delete all the SoundFonts */
+ for(list = synth->sfont; list; list = fluid_list_next(list))
+ {
+ sfont = fluid_list_get(list);
+ fluid_sfont_delete_internal(sfont);
+ }
- /* Delete the SoundFont info hash */
- if (synth->sfont_hash) delete_fluid_hashtable (synth->sfont_hash);
+ delete_fluid_list(synth->sfont);
+ /* delete all the SoundFont loaders */
- /* delete all the SoundFont loaders */
+ for(list = synth->loaders; list; list = fluid_list_next(list))
+ {
+ loader = (fluid_sfloader_t *) fluid_list_get(list);
+ fluid_sfloader_delete(loader);
+ }
- for (list = synth->loaders; list; list = fluid_list_next(list)) {
- loader = (fluid_sfloader_t*) fluid_list_get(list);
- fluid_sfloader_delete(loader);
- }
+ delete_fluid_list(synth->loaders);
- delete_fluid_list(synth->loaders);
+ if(synth->channel != NULL)
+ {
+ for(i = 0; i < synth->midi_channels; i++)
+ {
+ delete_fluid_channel(synth->channel[i]);
+ }
- if (synth->channel != NULL) {
- for (i = 0; i < synth->midi_channels; i++) {
- if (synth->channel[i] != NULL) {
- delete_fluid_channel(synth->channel[i]);
- }
+ FLUID_FREE(synth->channel);
}
- FLUID_FREE(synth->channel);
- }
- if (synth->voice != NULL) {
- for (i = 0; i < synth->nvoice; i++) {
- if (synth->voice[i] != NULL) {
- delete_fluid_voice(synth->voice[i]);
- }
+ if(synth->voice != NULL)
+ {
+ for(i = 0; i < synth->nvoice; i++)
+ {
+ delete_fluid_voice(synth->voice[i]);
+ }
+
+ FLUID_FREE(synth->voice);
}
- FLUID_FREE(synth->voice);
- }
- /* free the tunings, if any */
- if (synth->tuning != NULL) {
- for (i = 0; i < 128; i++) {
- if (synth->tuning[i] != NULL) {
- for (k = 0; k < 128; k++) {
- if (synth->tuning[i][k] != NULL) {
- delete_fluid_tuning(synth->tuning[i][k]);
- }
- }
- FLUID_FREE(synth->tuning[i]);
- }
+ /* free the tunings, if any */
+ if(synth->tuning != NULL)
+ {
+ for(i = 0; i < 128; i++)
+ {
+ if(synth->tuning[i] != NULL)
+ {
+ for(k = 0; k < 128; k++)
+ {
+ delete_fluid_tuning(synth->tuning[i][k]);
+ }
+
+ FLUID_FREE(synth->tuning[i]);
+ }
+ }
+
+ FLUID_FREE(synth->tuning);
}
- FLUID_FREE(synth->tuning);
- }
- fluid_private_free (synth->tuning_iter);
+ fluid_private_free(synth->tuning_iter);
#ifdef LADSPA
- /* Release the LADSPA Fx unit */
- fluid_LADSPA_shutdown(synth->LADSPA_FxUnit);
- FLUID_FREE(synth->LADSPA_FxUnit);
+ /* Release the LADSPA effects unit */
+ delete_fluid_ladspa_fx(synth->ladspa_fx);
#endif
- fluid_rec_mutex_destroy(synth->mutex);
+ /* delete all default modulators */
+ default_mod = synth->default_mod;
- FLUID_FREE(synth);
+ while(default_mod != NULL)
+ {
+ mod = default_mod;
+ default_mod = mod->next;
+ delete_fluid_mod(mod);
+ }
+
+ FLUID_FREE(synth->overflow.important_channels);
- return FLUID_OK;
+ fluid_rec_mutex_destroy(synth->mutex);
+
+ FLUID_FREE(synth);
}
/**
@@ -896,10 +1111,10 @@ delete_fluid_synth(fluid_synth_t* synth)
*/
/* FIXME - The error messages are not thread-safe, yet. They are still stored
* in a global message buffer (see fluid_sys.c). */
-char*
-fluid_synth_error(fluid_synth_t* synth)
+const char *
+fluid_synth_error(fluid_synth_t *synth)
{
- return fluid_error();
+ return fluid_error();
}
/**
@@ -908,137 +1123,311 @@ fluid_synth_error(fluid_synth_t* synth)
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param key MIDI note number (0-127)
* @param vel MIDI velocity (0-127, 0=noteoff)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
+fluid_synth_noteon(fluid_synth_t *synth, int chan, int key, int vel)
{
- int result;
- fluid_return_val_if_fail (key >= 0 && key <= 127, FLUID_FAILED);
- fluid_return_val_if_fail (vel >= 0 && vel <= 127, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ int result;
+ fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED);
+ fluid_return_val_if_fail(vel >= 0 && vel <= 127, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- result = fluid_synth_noteon_LOCAL (synth, chan, key, vel);
- FLUID_API_RETURN(result);
+ result = fluid_synth_noteon_LOCAL(synth, chan, key, vel);
+ FLUID_API_RETURN(result);
}
/* Local synthesis thread variant of fluid_synth_noteon */
static int
-fluid_synth_noteon_LOCAL(fluid_synth_t* synth, int chan, int key, int vel)
+fluid_synth_noteon_LOCAL(fluid_synth_t *synth, int chan, int key, int vel)
{
- fluid_channel_t* channel;
+ fluid_channel_t *channel ;
- /* notes with velocity zero go to noteoff */
- if (vel == 0) return fluid_synth_noteoff_LOCAL(synth, chan, key);
-
- channel = synth->channel[chan];
-
- /* make sure this channel has a preset */
- if (channel->preset == NULL) {
- if (synth->verbose) {
- FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d\t%s",
- chan, key, vel, 0,
- fluid_synth_get_ticks(synth) / 44100.0f,
- (fluid_curtime() - synth->start) / 1000.0f,
- 0.0f, 0, "channel has no preset");
+ /* notes with velocity zero go to noteoff */
+ if(vel == 0)
+ {
+ return fluid_synth_noteoff_LOCAL(synth, chan, key);
}
- return FLUID_FAILED;
- }
- /* If there is another voice process on the same channel and key,
- advance it to the release phase. */
- fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, key);
+ channel = synth->channel[chan];
+ /* makes sure this channel has a preset */
+ if(channel->preset == NULL)
+ {
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d\t%s",
+ chan, key, vel, 0,
+ fluid_synth_get_ticks(synth) / 44100.0f,
+ (fluid_curtime() - synth->start) / 1000.0f,
+ 0.0f, 0, "channel has no preset");
+ }
- return fluid_preset_noteon(channel->preset, synth, chan, key, vel);
+ return FLUID_FAILED;
+ }
+
+ if(fluid_channel_is_playing_mono(channel)) /* channel is mono or legato CC is On) */
+ {
+ /* play the noteOn in monophonic */
+ return fluid_synth_noteon_mono_LOCAL(synth, chan, key, vel);
+ }
+ else
+ {
+ /* channel is poly and legato CC is Off) */
+
+ /* plays the noteOn in polyphonic */
+ /* Sets the note at first position in monophonic list */
+ /* In the case where the musician intends to inter the channel in monophonic
+ (by depressing the CC legato on), the next noteOn mono could be played legato
+ with the previous note poly (if the musician choose this).
+ */
+ fluid_channel_set_onenote_monolist(channel, (unsigned char) key,
+ (unsigned char) vel);
+
+ /* If there is another voice process on the same channel and key,
+ advance it to the release phase. */
+ fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, key);
+
+ /* a noteon poly is passed to fluid_synth_noteon_monopoly_legato().
+ This allows an opportunity to get this note played legato with a previous
+ note if a CC PTC have been received before this noteon. This behavior is
+ a MIDI specification (see FluidPolymono-0004.pdf chapter 4.3-a ,3.4.11
+ for details).
+ */
+ return fluid_synth_noteon_monopoly_legato(synth, chan, INVALID_NOTE, key, vel);
+ }
}
/**
- * Send a note-off event to a FluidSynth object.
+ * Sends a note-off event to a FluidSynth object.
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param key MIDI note number (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise (may just mean that no
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise (may just mean that no
* voices matched the note off event)
*/
int
-fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
+fluid_synth_noteoff(fluid_synth_t *synth, int chan, int key)
{
- int result;
- fluid_return_val_if_fail (key >= 0 && key <= 127, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ int result;
+ fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- result = fluid_synth_noteoff_LOCAL (synth, chan, key);
-
- FLUID_API_RETURN(result);
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
+
+ result = fluid_synth_noteoff_LOCAL(synth, chan, key);
+ FLUID_API_RETURN(result);
}
/* Local synthesis thread variant of fluid_synth_noteoff */
static int
-fluid_synth_noteoff_LOCAL(fluid_synth_t* synth, int chan, int key)
-{
- fluid_voice_t* voice;
- int status = FLUID_FAILED;
- int i;
-
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (_ON(voice) && (voice->chan == chan) && (voice->key == key)) {
- if (synth->verbose) {
- int used_voices = 0;
- int k;
- for (k = 0; k < synth->polyphony; k++) {
- if (!_AVAILABLE(synth->voice[k])) {
- used_voices++;
- }
- }
- FLUID_LOG(FLUID_INFO, "noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%d",
- voice->chan, voice->key, 0, voice->id,
- (fluid_curtime() - synth->start) / 1000.0f,
- used_voices);
- } /* if verbose */
-
- fluid_voice_noteoff(voice);
- status = FLUID_OK;
- } /* if voice on */
- } /* for all voices */
- return status;
-}
-
-/* Damp voices on a channel (turn notes off), if they're sustained by
+fluid_synth_noteoff_LOCAL(fluid_synth_t *synth, int chan, int key)
+{
+ int status;
+ fluid_channel_t *channel = synth->channel[chan];
+
+ if(fluid_channel_is_playing_mono(channel)) /* channel is mono or legato CC is On) */
+ {
+ /* play the noteOff in monophonic */
+ status = fluid_synth_noteoff_mono_LOCAL(synth, chan, key);
+ }
+ else
+ {
+ /* channel is poly and legato CC is Off) */
+ /* removes the note from the monophonic list */
+ if(key == fluid_channel_last_note(channel))
+ {
+ fluid_channel_clear_monolist(channel);
+ }
+
+ status = fluid_synth_noteoff_monopoly(synth, chan, key, 0);
+ }
+
+ /* Changes the state (Valid/Invalid) of the most recent note played in a
+ staccato manner */
+ fluid_channel_invalid_prev_note_staccato(channel);
+ return status;
+}
+
+/* Damps voices on a channel (turn notes off), if they're sustained by
sustain pedal */
static int
-fluid_synth_damp_voices_by_sustain_LOCAL(fluid_synth_t* synth, int chan)
+fluid_synth_damp_voices_by_sustain_LOCAL(fluid_synth_t *synth, int chan)
{
- fluid_voice_t* voice;
- int i;
+ fluid_channel_t *channel = synth->channel[chan];
+ fluid_voice_t *voice;
+ int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
- if ((voice->chan == chan) && _SUSTAINED(voice))
- fluid_voice_release(voice);
- }
+ if((fluid_voice_get_channel(voice) == chan) && fluid_voice_is_sustained(voice))
+ {
+ if(voice->key == channel->key_mono_sustained)
+ {
+ /* key_mono_sustained is a possible mono note sustainted
+ (by sustain or sostenuto pedal). It must be marked released
+ (INVALID_NOTE) here because it is released only by sustain pedal */
+ channel->key_mono_sustained = INVALID_NOTE;
+ }
+
+ fluid_voice_release(voice);
+ }
+ }
- return FLUID_OK;
+ return FLUID_OK;
}
-/* Damp voices on a channel (turn notes off), if they're sustained by
+/* Damps voices on a channel (turn notes off), if they're sustained by
sostenuto pedal */
static int
-fluid_synth_damp_voices_by_sostenuto_LOCAL(fluid_synth_t* synth, int chan)
+fluid_synth_damp_voices_by_sostenuto_LOCAL(fluid_synth_t *synth, int chan)
{
- fluid_voice_t* voice;
- int i;
+ fluid_channel_t *channel = synth->channel[chan];
+ fluid_voice_t *voice;
+ int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
- if ((voice->chan == chan) && _HELD_BY_SOSTENUTO(voice))
- fluid_voice_release(voice);
- }
+ if((fluid_voice_get_channel(voice) == chan) && fluid_voice_is_sostenuto(voice))
+ {
+ if(voice->key == channel->key_mono_sustained)
+ {
+ /* key_mono_sustained is a possible mono note sustainted
+ (by sustain or sostenuto pedal). It must be marked released
+ (INVALID_NOTE) here because it is released only by sostenuto pedal */
+ channel->key_mono_sustained = INVALID_NOTE;
+ }
+
+ fluid_voice_release(voice);
+ }
+ }
- return FLUID_OK;
+ return FLUID_OK;
+}
+
+/**
+ * Adds the specified modulator \c mod as default modulator to the synth. \c mod will
+ * take effect for any subsequently created voice.
+ * @param synth FluidSynth instance
+ * @param mod Modulator info (values copied, passed in object can be freed immediately afterwards)
+ * @param mode Determines how to handle an existing identical modulator (#fluid_synth_add_mod)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ *
+ * @note Not realtime safe (due to internal memory allocation) and therefore should not be called
+ * from synthesis context at the risk of stalling audio output.
+ */
+int
+fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode)
+{
+ fluid_mod_t *default_mod;
+ fluid_mod_t *last_mod = NULL;
+ fluid_mod_t *new_mod;
+
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(mod != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+
+ default_mod = synth->default_mod;
+
+ while(default_mod != NULL)
+ {
+ if(fluid_mod_test_identity(default_mod, mod))
+ {
+ if(mode == FLUID_SYNTH_ADD)
+ {
+ default_mod->amount += mod->amount;
+ }
+ else if(mode == FLUID_SYNTH_OVERWRITE)
+ {
+ default_mod->amount = mod->amount;
+ }
+ else
+ {
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
+
+ FLUID_API_RETURN(FLUID_OK);
+ }
+
+ last_mod = default_mod;
+ default_mod = default_mod->next;
+ }
+
+ /* Add a new modulator (no existing modulator to add / overwrite). */
+ new_mod = new_fluid_mod();
+
+ if(new_mod == NULL)
+ {
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
+
+ fluid_mod_clone(new_mod, mod);
+ new_mod->next = NULL;
+
+ if(last_mod == NULL)
+ {
+ synth->default_mod = new_mod;
+ }
+ else
+ {
+ last_mod->next = new_mod;
+ }
+
+ FLUID_API_RETURN(FLUID_OK);
+}
+
+/**
+ * Removes the specified modulator \c mod from the synth's default modulator list.
+ * fluid_mod_test_identity() will be used to test modulator matching.
+ * @param synth synth instance
+ * @param mod The modulator to remove
+ * @return #FLUID_OK if a matching modulator was found and successfully removed, #FLUID_FAILED otherwise
+ *
+ * @note Not realtime safe (due to internal memory allocation) and therefore should not be called
+ * from synthesis context at the risk of stalling audio output.
+ */
+int
+fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod)
+{
+ fluid_mod_t *default_mod;
+ fluid_mod_t *last_mod;
+
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(mod != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+
+ last_mod = default_mod = synth->default_mod;
+
+ while(default_mod != NULL)
+ {
+ if(fluid_mod_test_identity(default_mod, mod))
+ {
+ if(synth->default_mod == default_mod)
+ {
+ synth->default_mod = synth->default_mod->next;
+ }
+ else
+ {
+ last_mod->next = default_mod->next;
+ }
+
+ delete_fluid_mod(default_mod);
+ FLUID_API_RETURN(FLUID_OK);
+ }
+
+ last_mod = default_mod;
+ default_mod = default_mod->next;
+ }
+
+ FLUID_API_RETURN(FLUID_FAILED);
}
@@ -1048,148 +1437,316 @@ fluid_synth_damp_voices_by_sostenuto_LOCAL(fluid_synth_t* synth, int chan)
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param num MIDI controller number (0-127)
* @param val MIDI controller value (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ * @note This function supports MIDI Global Controllers which will be sent to
+ * all channels of the basic channel if this basic channel is in mode OmniOff/Mono.
+ * This is accomplished by sending the CC one MIDI channel below the basic
+ * channel of the receiver.
+ * Examples: let a synthesizer with 16 MIDI channels:
+ * - Let a basic channel 7 in mode 3 (Omni Off, Mono). If MIDI channel 6 is disabled it
+ * could be used as CC global for all channels belonging to basic channel 7.
+ * - Let a basic channel 0 in mode 3. If MIDI channel 15 is disabled it could be used
+ * as CC global for all channels belonging to basic channel 0.
*/
int
-fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
+fluid_synth_cc(fluid_synth_t *synth, int chan, int num, int val)
{
- int result;
- fluid_return_val_if_fail (num >= 0 && num <= 127, FLUID_FAILED);
- fluid_return_val_if_fail (val >= 0 && val <= 127, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ int result = FLUID_FAILED;
+ fluid_channel_t *channel;
+ fluid_return_val_if_fail(num >= 0 && num <= 127, FLUID_FAILED);
+ fluid_return_val_if_fail(val >= 0 && val <= 127, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", chan, num, val);
+ channel = synth->channel[chan];
+
+ if(channel->mode & FLUID_CHANNEL_ENABLED)
+ {
+ /* chan is enabled */
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", chan, num, val);
+ }
+
+ fluid_channel_set_cc(channel, num, val);
+ result = fluid_synth_cc_LOCAL(synth, chan, num);
+ }
+ else /* chan is disabled so it is a candidate for global channel */
+ {
+ /* looks for next basic channel */
+ int n_chan = synth->midi_channels; /* MIDI Channels number */
+ int basicchan ;
+
+ if(chan < n_chan - 1)
+ {
+ basicchan = chan + 1; /* next channel */
+ }
+ else
+ {
+ basicchan = 0; /* wrap to 0 */
+ }
+
+ channel = synth->channel[basicchan];
+
+ /* Channel must be a basicchan in mode OMNIOFF_MONO */
+ if((channel->mode & FLUID_CHANNEL_BASIC) &&
+ ((channel->mode & FLUID_CHANNEL_MODE_MASK) == FLUID_CHANNEL_MODE_OMNIOFF_MONO))
+ {
+ /* sends cc to all channels in this basic channel */
+ int i, nbr = channel->mode_val;
+
+ for(i = basicchan; i < basicchan + nbr; i++)
+ {
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", i, num, val);
+ }
+
+ fluid_channel_set_cc(synth->channel[i], num, val);
+ result = fluid_synth_cc_LOCAL(synth, i, num);
+ }
+ }
+ /* The channel chan is not a valid 'global channel' */
+ else
+ {
+ result = FLUID_FAILED;
+ }
+ }
- fluid_channel_set_cc (synth->channel[chan], num, val);
- result = fluid_synth_cc_LOCAL (synth, chan, num);
- FLUID_API_RETURN(result);
+ FLUID_API_RETURN(result);
}
/* Local synthesis thread variant of MIDI CC set function. */
static int
-fluid_synth_cc_LOCAL (fluid_synth_t* synth, int channum, int num)
-{
- fluid_channel_t* chan = synth->channel[channum];
- int nrpn_select;
- int value;
-
- value = fluid_channel_get_cc (chan, num);
-
- switch (num) {
- case SUSTAIN_SWITCH:
- /* Release voices if Sustain switch is released */
- if (value < 64) /* Sustain is released */
- fluid_synth_damp_voices_by_sustain_LOCAL (synth, channum);
- break;
-
- case SOSTENUTO_SWITCH:
- /* Release voices if Sostetuno switch is released */
- if (value < 64) /* Sostenuto is released */
- fluid_synth_damp_voices_by_sostenuto_LOCAL(synth, channum);
- else /* Sostenuto is depressed */
- /* Update sostenuto order id when pedaling on Sostenuto */
- chan->sostenuto_orderid = synth->noteid; /* future voice id value */
- break;
-
- case BANK_SELECT_MSB:
- fluid_channel_set_bank_msb (chan, value & 0x7F);
- break;
- case BANK_SELECT_LSB:
- fluid_channel_set_bank_lsb (chan, value & 0x7F);
- break;
- case ALL_NOTES_OFF:
- fluid_synth_all_notes_off_LOCAL (synth, channum);
- break;
- case ALL_SOUND_OFF:
- fluid_synth_all_sounds_off_LOCAL (synth, channum);
- break;
- case ALL_CTRL_OFF:
- fluid_channel_init_ctrl (chan, 1);
- fluid_synth_modulate_voices_all_LOCAL (synth, channum);
- break;
- case DATA_ENTRY_MSB:
- {
- int data = (value << 7) + fluid_channel_get_cc (chan, DATA_ENTRY_LSB);
-
- if (chan->nrpn_active) /* NRPN is active? */
- { /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
- if ((fluid_channel_get_cc (chan, NRPN_MSB) == 120)
- && (fluid_channel_get_cc (chan, NRPN_LSB) < 100))
- {
- nrpn_select = chan->nrpn_select;
-
- if (nrpn_select < GEN_LAST)
- {
- float val = fluid_gen_scale_nrpn (nrpn_select, data);
- fluid_synth_set_gen_LOCAL (synth, channum, nrpn_select, val, FALSE);
- }
-
- chan->nrpn_select = 0; /* Reset to 0 */
- }
- }
- else if (fluid_channel_get_cc (chan, RPN_MSB) == 0) /* RPN is active: MSB = 0? */
- {
- switch (fluid_channel_get_cc (chan, RPN_LSB))
- {
- case RPN_PITCH_BEND_RANGE: /* Set bend range in semitones */
- fluid_channel_set_pitch_wheel_sensitivity (synth->channel[channum], value);
- fluid_synth_update_pitch_wheel_sens_LOCAL (synth, channum); /* Update bend range */
- /* FIXME - Handle LSB? (Fine bend range in cents) */
- break;
- case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over 1 semitone (+/- 50 cents, 8192 = center) */
- fluid_synth_set_gen_LOCAL (synth, channum, GEN_FINETUNE,
- (data - 8192) / 8192.0 * 50.0, FALSE);
- break;
- case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */
- fluid_synth_set_gen_LOCAL (synth, channum, GEN_COARSETUNE,
- value - 64, FALSE);
- break;
- case RPN_TUNING_PROGRAM_CHANGE:
- fluid_channel_set_tuning_prog (chan, value);
- fluid_synth_activate_tuning (synth, channum,
- fluid_channel_get_tuning_bank (chan),
- value, TRUE);
- break;
- case RPN_TUNING_BANK_SELECT:
- fluid_channel_set_tuning_bank (chan, value);
- break;
- case RPN_MODULATION_DEPTH_RANGE:
- break;
+fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num)
+{
+ fluid_channel_t *chan = synth->channel[channum];
+ int nrpn_select;
+ int value;
+
+ value = fluid_channel_get_cc(chan, num);
+
+ switch(num)
+ {
+
+ /* CC omnioff, omnion, mono, poly */
+ case POLY_OFF:
+ case POLY_ON:
+ case OMNI_OFF:
+ case OMNI_ON:
+
+ /* allowed only if channum is a basic channel */
+ if(chan->mode & FLUID_CHANNEL_BASIC)
+ {
+ /* Construction of new_mode from current channel mode and this CC mode */
+ int new_mode = chan->mode & FLUID_CHANNEL_MODE_MASK;
+
+ switch(num)
+ {
+ case POLY_OFF:
+ new_mode |= FLUID_CHANNEL_POLY_OFF;
+ break;
+
+ case POLY_ON:
+ new_mode &= ~FLUID_CHANNEL_POLY_OFF;
+ break;
+
+ case OMNI_OFF:
+ new_mode |= FLUID_CHANNEL_OMNI_OFF;
+ break;
+
+ case OMNI_ON:
+ new_mode &= ~FLUID_CHANNEL_OMNI_OFF;
+ break;
+
+ default: /* should never happen */
+ return FLUID_FAILED;
+ }
+
+ /* MIDI specs: if value is 0 it means all channels from channum to next
+ basic channel minus 1 (if any) or to MIDI channel count minus 1.
+ However, if value is > 0 (e.g. 4), the group of channels will be be
+ limited to 4.
+ value is ignored for #FLUID_CHANNEL_MODE_OMNIOFF_POLY as this mode
+ implies a group of only one channel.
+ */
+ /* Checks value range and changes this existing basic channel group */
+ value = fluid_synth_check_next_basic_channel(synth, channum, new_mode, value);
+
+ if(value != FLUID_FAILED)
+ {
+ /* reset the current basic channel before changing it */
+ fluid_synth_reset_basic_channel_LOCAL(synth, channum, chan->mode_val);
+ fluid_synth_set_basic_channel_LOCAL(synth, channum, new_mode, value);
+ break; /* FLUID_OK */
+ }
+ }
+
+ return FLUID_FAILED;
+
+ case LEGATO_SWITCH:
+ /* handles Poly/mono commutation on Legato pedal On/Off.*/
+ fluid_channel_cc_legato(chan, value);
+ break;
+
+ case PORTAMENTO_SWITCH:
+ /* Special handling of the monophonic list */
+ /* Invalids the most recent note played in a staccato manner */
+ fluid_channel_invalid_prev_note_staccato(chan);
+ break;
+
+ case SUSTAIN_SWITCH:
+
+ /* Release voices if Sustain switch is released */
+ if(value < 64) /* Sustain is released */
+ {
+ fluid_synth_damp_voices_by_sustain_LOCAL(synth, channum);
+ }
+
+ break;
+
+ case SOSTENUTO_SWITCH:
+
+ /* Release voices if Sostetuno switch is released */
+ if(value < 64) /* Sostenuto is released */
+ {
+ fluid_synth_damp_voices_by_sostenuto_LOCAL(synth, channum);
+ }
+ else /* Sostenuto is depressed */
+ /* Update sostenuto order id when pedaling on Sostenuto */
+ {
+ chan->sostenuto_orderid = synth->noteid; /* future voice id value */
+ }
+
+ break;
+
+ case BANK_SELECT_MSB:
+ fluid_channel_set_bank_msb(chan, value & 0x7F);
+ break;
+
+ case BANK_SELECT_LSB:
+ fluid_channel_set_bank_lsb(chan, value & 0x7F);
+ break;
+
+ case ALL_NOTES_OFF:
+ fluid_synth_all_notes_off_LOCAL(synth, channum);
+ break;
+
+ case ALL_SOUND_OFF:
+ fluid_synth_all_sounds_off_LOCAL(synth, channum);
+ break;
+
+ case ALL_CTRL_OFF:
+ fluid_channel_init_ctrl(chan, 1);
+ fluid_synth_modulate_voices_all_LOCAL(synth, channum);
+ break;
+
+ case DATA_ENTRY_MSB:
+ {
+ int data = (value << 7) + fluid_channel_get_cc(chan, DATA_ENTRY_LSB);
+
+ if(chan->nrpn_active) /* NRPN is active? */
+ {
+ /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
+ if((fluid_channel_get_cc(chan, NRPN_MSB) == 120)
+ && (fluid_channel_get_cc(chan, NRPN_LSB) < 100))
+ {
+ nrpn_select = chan->nrpn_select;
+
+ if(nrpn_select < GEN_LAST)
+ {
+ float val = fluid_gen_scale_nrpn(nrpn_select, data);
+ fluid_synth_set_gen_LOCAL(synth, channum, nrpn_select, val, FALSE);
+ }
+
+ chan->nrpn_select = 0; /* Reset to 0 */
+ }
+ }
+ else if(fluid_channel_get_cc(chan, RPN_MSB) == 0) /* RPN is active: MSB = 0? */
+ {
+ switch(fluid_channel_get_cc(chan, RPN_LSB))
+ {
+ case RPN_PITCH_BEND_RANGE: /* Set bend range in semitones */
+ fluid_channel_set_pitch_wheel_sensitivity(synth->channel[channum], value);
+ fluid_synth_update_pitch_wheel_sens_LOCAL(synth, channum); /* Update bend range */
+ /* FIXME - Handle LSB? (Fine bend range in cents) */
+ break;
+
+ case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over +/-1 semitone (+/- 100 cents, 8192 = center) */
+ fluid_synth_set_gen_LOCAL(synth, channum, GEN_FINETUNE,
+ (data - 8192) / 8192.0 * 100.0, FALSE);
+ break;
+
+ case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */
+ fluid_synth_set_gen_LOCAL(synth, channum, GEN_COARSETUNE,
+ value - 64, FALSE);
+ break;
+
+ case RPN_TUNING_PROGRAM_CHANGE:
+ fluid_channel_set_tuning_prog(chan, value);
+ fluid_synth_activate_tuning(synth, channum,
+ fluid_channel_get_tuning_bank(chan),
+ value, TRUE);
+ break;
+
+ case RPN_TUNING_BANK_SELECT:
+ fluid_channel_set_tuning_bank(chan, value);
+ break;
+
+ case RPN_MODULATION_DEPTH_RANGE:
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case NRPN_MSB:
+ fluid_channel_set_cc(chan, NRPN_LSB, 0);
+ chan->nrpn_select = 0;
+ chan->nrpn_active = 1;
+ break;
+
+ case NRPN_LSB:
+
+ /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
+ if(fluid_channel_get_cc(chan, NRPN_MSB) == 120)
+ {
+ if(value == 100)
+ {
+ chan->nrpn_select += 100;
+ }
+ else if(value == 101)
+ {
+ chan->nrpn_select += 1000;
+ }
+ else if(value == 102)
+ {
+ chan->nrpn_select += 10000;
+ }
+ else if(value < 100)
+ {
+ chan->nrpn_select += value;
+ }
}
- }
- break;
- }
- case NRPN_MSB:
- fluid_channel_set_cc (chan, NRPN_LSB, 0);
- chan->nrpn_select = 0;
- chan->nrpn_active = 1;
- break;
- case NRPN_LSB:
- /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
- if (fluid_channel_get_cc (chan, NRPN_MSB) == 120) {
- if (value == 100) {
- chan->nrpn_select += 100;
- } else if (value == 101) {
- chan->nrpn_select += 1000;
- } else if (value == 102) {
- chan->nrpn_select += 10000;
- } else if (value < 100) {
- chan->nrpn_select += value;
- }
- }
-
- chan->nrpn_active = 1;
- break;
- case RPN_MSB:
- case RPN_LSB:
- chan->nrpn_active = 0;
- break;
- default:
- return fluid_synth_modulate_voices_LOCAL (synth, channum, 1, num);
- }
-
- return FLUID_OK;
+
+ chan->nrpn_active = 1;
+ break;
+
+ case RPN_MSB:
+ case RPN_LSB:
+ chan->nrpn_active = 0;
+ break;
+
+ case BREATH_MSB:
+ /* handles CC Breath On/Off noteOn/noteOff mode */
+ fluid_channel_cc_breath_note_on_off(chan, value);
+
+ /* fall-through */
+ default:
+ return fluid_synth_modulate_voices_LOCAL(synth, channum, 1, num);
+ }
+
+ return FLUID_OK;
}
/**
@@ -1198,30 +1755,35 @@ fluid_synth_cc_LOCAL (fluid_synth_t* synth, int channum, int num)
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param num MIDI controller number (0-127)
* @param pval Location to store MIDI controller value (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_get_cc(fluid_synth_t* synth, int chan, int num, int* pval)
+fluid_synth_get_cc(fluid_synth_t *synth, int chan, int num, int *pval)
{
- fluid_return_val_if_fail (num >= 0 && num < 128, FLUID_FAILED);
- fluid_return_val_if_fail (pval != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(num >= 0 && num < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(pval != NULL, FLUID_FAILED);
+
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- *pval = fluid_channel_get_cc (synth->channel[chan], num);
- FLUID_API_RETURN(FLUID_OK);
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
+
+ *pval = fluid_channel_get_cc(synth->channel[chan], num);
+ FLUID_API_RETURN(FLUID_OK);
}
/*
* Handler for synth.device-id setting.
*/
-static int
-fluid_synth_update_device_id (fluid_synth_t *synth, char *name, int value)
+static void
+fluid_synth_handle_device_id(void *data, const char *name, int value)
{
- fluid_synth_api_enter(synth);
- synth->device_id = value;
- fluid_synth_api_exit(synth);
- return 0;
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+ fluid_return_if_fail(synth != NULL);
+
+ fluid_synth_api_enter(synth);
+ synth->device_id = value;
+ fluid_synth_api_exit(synth);
}
/**
@@ -1237,7 +1799,7 @@ fluid_synth_update_device_id (fluid_synth_t *synth, char *name, int value)
* recognized and handled or not (set to TRUE if it was handled)
* @param dryrun TRUE to just do a dry run but not actually execute the SYSEX
* command (useful for checking if a SYSEX message would be handled)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.0
*/
/* SYSEX format (0xF0 and 0xF7 not passed to this function):
@@ -1249,397 +1811,502 @@ int
fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
char *response, int *response_len, int *handled, int dryrun)
{
- int avail_response = 0;
+ int avail_response = 0;
- if (handled) *handled = FALSE;
+ if(handled)
+ {
+ *handled = FALSE;
+ }
- if (response_len)
- {
- avail_response = *response_len;
- *response_len = 0;
- }
+ if(response_len)
+ {
+ avail_response = *response_len;
+ *response_len = 0;
+ }
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (data != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (len > 0, FLUID_FAILED);
- fluid_return_val_if_fail (!response || response_len, FLUID_FAILED);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(data != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(len > 0, FLUID_FAILED);
+ fluid_return_val_if_fail(!response || response_len, FLUID_FAILED);
- if (len < 4) return FLUID_OK;
+ if(len < 4)
+ {
+ return FLUID_OK;
+ }
- /* MIDI tuning SYSEX message? */
- if ((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME)
- && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL)
- && data[2] == MIDI_SYSEX_MIDI_TUNING_ID)
- {
- int result;
- fluid_synth_api_enter(synth);
- result = fluid_synth_sysex_midi_tuning (synth, data, len, response,
- response_len, avail_response,
- handled, dryrun);
+ /* MIDI tuning SYSEX message? */
+ if((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME)
+ && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL)
+ && data[2] == MIDI_SYSEX_MIDI_TUNING_ID)
+ {
+ int result;
+ fluid_synth_api_enter(synth);
+ result = fluid_synth_sysex_midi_tuning(synth, data, len, response,
+ response_len, avail_response,
+ handled, dryrun);
- FLUID_API_RETURN(result);
- }
- return FLUID_OK;
+ FLUID_API_RETURN(result);
+ }
+
+ return FLUID_OK;
}
/* Handler for MIDI tuning SYSEX messages */
static int
-fluid_synth_sysex_midi_tuning (fluid_synth_t *synth, const char *data, int len,
- char *response, int *response_len, int avail_response,
- int *handled, int dryrun)
-{
- int realtime, msgid;
- int bank = 0, prog, channels;
- double tunedata[128];
- int keys[128];
- char name[17];
- int note, frac, frac2;
- uint8 chksum;
- int i, count, index;
- const char *dataptr;
- char *resptr;;
-
- realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME;
- msgid = data[3];
-
- switch (msgid)
- {
+fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, int len,
+ char *response, int *response_len, int avail_response,
+ int *handled, int dryrun)
+{
+ int realtime, msgid;
+ int bank = 0, prog, channels;
+ double tunedata[128];
+ int keys[128];
+ char name[17];
+ int note, frac, frac2;
+ uint8_t chksum;
+ int i, count, index;
+ const char *dataptr;
+ char *resptr;;
+
+ realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME;
+ msgid = data[3];
+
+ switch(msgid)
+ {
case MIDI_SYSEX_TUNING_BULK_DUMP_REQ:
case MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK:
- if (data[3] == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
- {
- if (len != 5 || data[4] & 0x80 || !response)
- return FLUID_OK;
-
- *response_len = 406;
- prog = data[4];
- }
- else
- {
- if (len != 6 || data[4] & 0x80 || data[5] & 0x80 || !response)
- return FLUID_OK;
-
- *response_len = 407;
- bank = data[4];
- prog = data[5];
- }
-
- if (dryrun)
- {
- if (handled) *handled = TRUE;
- return FLUID_OK;
- }
+ if(data[3] == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
+ {
+ if(len != 5 || data[4] & 0x80 || !response)
+ {
+ return FLUID_OK;
+ }
+
+ *response_len = 406;
+ prog = data[4];
+ }
+ else
+ {
+ if(len != 6 || data[4] & 0x80 || data[5] & 0x80 || !response)
+ {
+ return FLUID_OK;
+ }
+
+ *response_len = 407;
+ bank = data[4];
+ prog = data[5];
+ }
- if (avail_response < *response_len) return FLUID_FAILED;
+ if(dryrun)
+ {
+ if(handled)
+ {
+ *handled = TRUE;
+ }
- /* Get tuning data, return if tuning not found */
- if (fluid_synth_tuning_dump (synth, bank, prog, name, 17, tunedata) == FLUID_FAILED)
- {
- *response_len = 0;
- return FLUID_OK;
- }
+ return FLUID_OK;
+ }
- resptr = response;
+ if(avail_response < *response_len)
+ {
+ return FLUID_FAILED;
+ }
- *resptr++ = MIDI_SYSEX_UNIV_NON_REALTIME;
- *resptr++ = synth->device_id;
- *resptr++ = MIDI_SYSEX_MIDI_TUNING_ID;
- *resptr++ = MIDI_SYSEX_TUNING_BULK_DUMP;
+ /* Get tuning data, return if tuning not found */
+ if(fluid_synth_tuning_dump(synth, bank, prog, name, 17, tunedata) == FLUID_FAILED)
+ {
+ *response_len = 0;
+ return FLUID_OK;
+ }
+
+ resptr = response;
+
+ *resptr++ = MIDI_SYSEX_UNIV_NON_REALTIME;
+ *resptr++ = synth->device_id;
+ *resptr++ = MIDI_SYSEX_MIDI_TUNING_ID;
+ *resptr++ = MIDI_SYSEX_TUNING_BULK_DUMP;
+
+ if(msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK)
+ {
+ *resptr++ = bank;
+ }
- if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK)
- *resptr++ = bank;
+ *resptr++ = prog;
+ FLUID_STRNCPY(resptr, name, 16);
+ resptr += 16;
- *resptr++ = prog;
- FLUID_STRNCPY (resptr, name, 16);
- resptr += 16;
+ for(i = 0; i < 128; i++)
+ {
+ note = tunedata[i] / 100.0;
+ fluid_clip(note, 0, 127);
- for (i = 0; i < 128; i++)
- {
- note = tunedata[i] / 100.0;
- fluid_clip (note, 0, 127);
+ frac = ((tunedata[i] - note * 100.0) * 16384.0 + 50.0) / 100.0;
+ fluid_clip(frac, 0, 16383);
- frac = ((tunedata[i] - note * 100.0) * 16384.0 + 50.0) / 100.0;
- fluid_clip (frac, 0, 16383);
+ *resptr++ = note;
+ *resptr++ = frac >> 7;
+ *resptr++ = frac & 0x7F;
+ }
- *resptr++ = note;
- *resptr++ = frac >> 7;
- *resptr++ = frac & 0x7F;
- }
+ if(msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
+ {
+ /* NOTE: Checksum is not as straight forward as the bank based messages */
+ chksum = MIDI_SYSEX_UNIV_NON_REALTIME ^ MIDI_SYSEX_MIDI_TUNING_ID
+ ^ MIDI_SYSEX_TUNING_BULK_DUMP ^ prog;
+
+ for(i = 21; i < 128 * 3 + 21; i++)
+ {
+ chksum ^= response[i];
+ }
+ }
+ else
+ {
+ for(i = 1, chksum = 0; i < 406; i++)
+ {
+ chksum ^= response[i];
+ }
+ }
- if (msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ)
- { /* NOTE: Checksum is not as straight forward as the bank based messages */
- chksum = MIDI_SYSEX_UNIV_NON_REALTIME ^ MIDI_SYSEX_MIDI_TUNING_ID
- ^ MIDI_SYSEX_TUNING_BULK_DUMP ^ prog;
+ *resptr++ = chksum & 0x7F;
- for (i = 21; i < 128 * 3 + 21; i++)
- chksum ^= response[i];
- }
- else
- {
- for (i = 1, chksum = 0; i < 406; i++)
- chksum ^= response[i];
- }
+ if(handled)
+ {
+ *handled = TRUE;
+ }
- *resptr++ = chksum & 0x7F;
+ break;
- if (handled) *handled = TRUE;
- break;
case MIDI_SYSEX_TUNING_NOTE_TUNE:
case MIDI_SYSEX_TUNING_NOTE_TUNE_BANK:
- dataptr = data + 4;
-
- if (msgid == MIDI_SYSEX_TUNING_NOTE_TUNE)
- {
- if (len < 10 || data[4] & 0x80 || data[5] & 0x80 || len != data[5] * 4 + 6)
- return FLUID_OK;
- }
- else
- {
- if (len < 11 || data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80
- || len != data[5] * 4 + 7)
- return FLUID_OK;
-
- bank = *dataptr++;
- }
-
- if (dryrun)
- {
- if (handled) *handled = TRUE;
- return FLUID_OK;
- }
+ dataptr = data + 4;
- prog = *dataptr++;
- count = *dataptr++;
+ if(msgid == MIDI_SYSEX_TUNING_NOTE_TUNE)
+ {
+ if(len < 10 || data[4] & 0x80 || data[5] & 0x80 || len != data[5] * 4 + 6)
+ {
+ return FLUID_OK;
+ }
+ }
+ else
+ {
+ if(len < 11 || data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80
+ || len != data[6] * 4 + 7)
+ {
+ return FLUID_OK;
+ }
- for (i = 0, index = 0; i < count; i++)
- {
- note = *dataptr++;
- if (note & 0x80) return FLUID_OK;
- keys[index] = note;
+ bank = *dataptr++;
+ }
- note = *dataptr++;
- frac = *dataptr++;
- frac2 = *dataptr++;
+ if(dryrun)
+ {
+ if(handled)
+ {
+ *handled = TRUE;
+ }
- if (note & 0x80 || frac & 0x80 || frac2 & 0x80)
- return FLUID_OK;
+ return FLUID_OK;
+ }
+
+ prog = *dataptr++;
+ count = *dataptr++;
+
+ for(i = 0, index = 0; i < count; i++)
+ {
+ note = *dataptr++;
- frac = frac << 7 | frac2;
+ if(note & 0x80)
+ {
+ return FLUID_OK;
+ }
- /* No change pitch value? Doesn't really make sense to send that, but.. */
- if (note == 0x7F && frac == 16383) continue;
+ keys[index] = note;
- tunedata[index] = note * 100.0 + (frac * 100.0 / 16384.0);
- index++;
- }
+ note = *dataptr++;
+ frac = *dataptr++;
+ frac2 = *dataptr++;
- if (index > 0)
- {
- if (fluid_synth_tune_notes (synth, bank, prog, index, keys, tunedata,
- realtime) == FLUID_FAILED)
- return FLUID_FAILED;
- }
+ if(note & 0x80 || frac & 0x80 || frac2 & 0x80)
+ {
+ return FLUID_OK;
+ }
+
+ frac = frac << 7 | frac2;
+
+ /* No change pitch value? Doesn't really make sense to send that, but.. */
+ if(note == 0x7F && frac == 16383)
+ {
+ continue;
+ }
+
+ tunedata[index] = note * 100.0 + (frac * 100.0 / 16384.0);
+ index++;
+ }
+
+ if(index > 0)
+ {
+ if(fluid_synth_tune_notes(synth, bank, prog, index, keys, tunedata,
+ realtime) == FLUID_FAILED)
+ {
+ return FLUID_FAILED;
+ }
+ }
+
+ if(handled)
+ {
+ *handled = TRUE;
+ }
+
+ break;
- if (handled) *handled = TRUE;
- break;
case MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE:
case MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE:
- if ((msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE && len != 19)
- || (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE && len != 31))
- return FLUID_OK;
+ if((msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE && len != 19)
+ || (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE && len != 31))
+ {
+ return FLUID_OK;
+ }
- if (data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80)
- return FLUID_OK;
+ if(data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80)
+ {
+ return FLUID_OK;
+ }
- if (dryrun)
- {
- if (handled) *handled = TRUE;
- return FLUID_OK;
- }
+ if(dryrun)
+ {
+ if(handled)
+ {
+ *handled = TRUE;
+ }
+
+ return FLUID_OK;
+ }
- channels = (data[4] & 0x03) << 14 | data[5] << 7 | data[6];
+ channels = (data[4] & 0x03) << 14 | data[5] << 7 | data[6];
- if (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE)
- {
- for (i = 0; i < 12; i++)
+ if(msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE)
{
- frac = data[i + 7];
- if (frac & 0x80) return FLUID_OK;
- tunedata[i] = (int)frac - 64;
+ for(i = 0; i < 12; i++)
+ {
+ frac = data[i + 7];
+
+ if(frac & 0x80)
+ {
+ return FLUID_OK;
+ }
+
+ tunedata[i] = (int)frac - 64;
+ }
}
- }
- else
- {
- for (i = 0; i < 12; i++)
+ else
{
- frac = data[i * 2 + 7];
- frac2 = data[i * 2 + 8];
- if (frac & 0x80 || frac2 & 0x80) return FLUID_OK;
- tunedata[i] = (((int)frac << 7 | (int)frac2) - 8192) * (200.0 / 16384.0);
+ for(i = 0; i < 12; i++)
+ {
+ frac = data[i * 2 + 7];
+ frac2 = data[i * 2 + 8];
+
+ if(frac & 0x80 || frac2 & 0x80)
+ {
+ return FLUID_OK;
+ }
+
+ tunedata[i] = (((int)frac << 7 | (int)frac2) - 8192) * (200.0 / 16384.0);
+ }
}
- }
- if (fluid_synth_activate_octave_tuning (synth, 0, 0, "SYSEX",
+ if(fluid_synth_activate_octave_tuning(synth, 0, 0, "SYSEX",
tunedata, realtime) == FLUID_FAILED)
- return FLUID_FAILED;
+ {
+ return FLUID_FAILED;
+ }
+
+ if(channels)
+ {
+ for(i = 0; i < 16; i++)
+ {
+ if(channels & (1 << i))
+ {
+ fluid_synth_activate_tuning(synth, i, 0, 0, realtime);
+ }
+ }
+ }
- if (channels)
- {
- for (i = 0; i < 16; i++)
+ if(handled)
{
- if (channels & (1 << i))
- fluid_synth_activate_tuning (synth, i, 0, 0, realtime);
+ *handled = TRUE;
}
- }
- if (handled) *handled = TRUE;
- break;
- }
+ break;
+ }
- return FLUID_OK;
+ return FLUID_OK;
}
/**
* Turn off all notes on a MIDI channel (put them into release phase).
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1), (chan=-1 selects all channels)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.4
*/
int
-fluid_synth_all_notes_off(fluid_synth_t* synth, int chan)
+fluid_synth_all_notes_off(fluid_synth_t *synth, int chan)
{
- int result;
+ int result;
+
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(chan >= -1, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+
+ if(chan >= synth->midi_channels)
+ {
+ result = FLUID_FAILED;
+ }
+ else
+ {
+ /* Allowed (even for channel disabled) as chan = -1 selects all channels */
+ result = fluid_synth_all_notes_off_LOCAL(synth, chan);
+ }
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= -1, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- if (chan >= synth->midi_channels)
- result = FLUID_FAILED;
- else
- result = fluid_synth_all_notes_off_LOCAL (synth, chan);
- FLUID_API_RETURN(result);
+ FLUID_API_RETURN(result);
}
/* Local synthesis thread variant of all notes off, (chan=-1 selects all channels) */
-static int
-fluid_synth_all_notes_off_LOCAL(fluid_synth_t* synth, int chan)
+//static int
+int
+fluid_synth_all_notes_off_LOCAL(fluid_synth_t *synth, int chan)
{
- fluid_voice_t* voice;
- int i;
+ fluid_voice_t *voice;
+ int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
- if (_PLAYING(voice) && ((-1 == chan) || (chan == voice->chan)))
- fluid_voice_noteoff(voice);
- }
- return FLUID_OK;
+ if(fluid_voice_is_playing(voice) && ((-1 == chan) || (chan == fluid_voice_get_channel(voice))))
+ {
+ fluid_voice_noteoff(voice);
+ }
+ }
+
+ return FLUID_OK;
}
/**
* Immediately stop all notes on a MIDI channel (skips release phase).
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1), (chan=-1 selects all channels)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.4
*/
int
-fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan)
+fluid_synth_all_sounds_off(fluid_synth_t *synth, int chan)
{
- int result;
+ int result;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= -1, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- if (chan >= synth->midi_channels)
- result = FLUID_FAILED;
- else
- result = fluid_synth_all_sounds_off_LOCAL (synth, chan);
- FLUID_API_RETURN(result);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(chan >= -1, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+
+ if(chan >= synth->midi_channels)
+ {
+ result = FLUID_FAILED;
+ }
+ else
+ {
+ /* Allowed (even for channel disabled) as chan = -1 selects all channels */
+ result = fluid_synth_all_sounds_off_LOCAL(synth, chan);
+ }
+
+ FLUID_API_RETURN(result);
}
/* Local synthesis thread variant of all sounds off, (chan=-1 selects all channels) */
static int
-fluid_synth_all_sounds_off_LOCAL(fluid_synth_t* synth, int chan)
+fluid_synth_all_sounds_off_LOCAL(fluid_synth_t *synth, int chan)
{
- fluid_voice_t* voice;
- int i;
+ fluid_voice_t *voice;
+ int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
- if (_PLAYING(voice) && ((-1 == chan) || (chan == voice->chan)))
- fluid_voice_off(voice);
- }
- return FLUID_OK;
+ if(fluid_voice_is_playing(voice) && ((-1 == chan) || (chan == fluid_voice_get_channel(voice))))
+ {
+ fluid_voice_off(voice);
+ }
+ }
+
+ return FLUID_OK;
}
/**
* Reset reverb engine
* @param synth FluidSynth instance
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_reset_reverb(fluid_synth_t* synth)
+fluid_synth_reset_reverb(fluid_synth_t *synth)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_reverb, 0, 0.0f);
- FLUID_API_RETURN(FLUID_OK);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_reverb, 0, 0.0f);
+ FLUID_API_RETURN(FLUID_OK);
}
/**
* Reset chorus engine
* @param synth FluidSynth instance
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_reset_chorus(fluid_synth_t* synth)
+fluid_synth_reset_chorus(fluid_synth_t *synth)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_chorus, 0, 0.0f);
- FLUID_API_RETURN(FLUID_OK);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_chorus, 0, 0.0f);
+ FLUID_API_RETURN(FLUID_OK);
}
/**
- * Send MIDI system reset command (big red 'panic' button), turns off notes and
- * resets controllers.
+ * Send MIDI system reset command (big red 'panic' button), turns off notes, resets
+ * controllers and restores initial basic channel configuration.
* @param synth FluidSynth instance
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_system_reset(fluid_synth_t* synth)
+fluid_synth_system_reset(fluid_synth_t *synth)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- result = fluid_synth_system_reset_LOCAL (synth);
- FLUID_API_RETURN(result);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+ result = fluid_synth_system_reset_LOCAL(synth);
+ FLUID_API_RETURN(result);
}
/* Local variant of the system reset command */
static int
-fluid_synth_system_reset_LOCAL(fluid_synth_t* synth)
+fluid_synth_system_reset_LOCAL(fluid_synth_t *synth)
{
- fluid_voice_t* voice;
- int i;
+ int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+ fluid_synth_all_sounds_off_LOCAL(synth, -1);
- if (_PLAYING(voice))
- fluid_voice_off(voice);
- }
+ for(i = 0; i < synth->midi_channels; i++)
+ {
+ fluid_channel_reset(synth->channel[i]);
+ }
- for (i = 0; i < synth->midi_channels; i++)
- fluid_channel_reset(synth->channel[i]);
+ /* Basic channel 0, Mode Omni On Poly */
+ fluid_synth_set_basic_channel(synth, 0, FLUID_CHANNEL_MODE_OMNION_POLY,
+ synth->midi_channels);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_fx, 0, 0.0f);
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_reverb, 0, 0.0f);
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_chorus, 0, 0.0f);
- return FLUID_OK;
+ return FLUID_OK;
}
/**
@@ -1648,42 +2315,50 @@ fluid_synth_system_reset_LOCAL(fluid_synth_t* synth)
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param is_cc Boolean value indicating if ctrl is a CC controller or not
* @param ctrl MIDI controller value
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
static int
-fluid_synth_modulate_voices_LOCAL(fluid_synth_t* synth, int chan, int is_cc, int ctrl)
+fluid_synth_modulate_voices_LOCAL(fluid_synth_t *synth, int chan, int is_cc, int ctrl)
{
- fluid_voice_t* voice;
- int i;
+ fluid_voice_t *voice;
+ int i;
+
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+ if(fluid_voice_get_channel(voice) == chan)
+ {
+ fluid_voice_modulate(voice, is_cc, ctrl);
+ }
+ }
- if (voice->chan == chan)
- fluid_voice_modulate(voice, is_cc, ctrl);
- }
- return FLUID_OK;
+ return FLUID_OK;
}
/**
* Update voices on a MIDI channel after all MIDI controllers have been changed.
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
static int
-fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan)
+fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t *synth, int chan)
{
- fluid_voice_t* voice;
- int i;
+ fluid_voice_t *voice;
+ int i;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
- if (voice->chan == chan)
- fluid_voice_modulate_all(voice);
- }
- return FLUID_OK;
+ if(fluid_voice_get_channel(voice) == chan)
+ {
+ fluid_voice_modulate_all(voice);
+ }
+ }
+
+ return FLUID_OK;
}
/**
@@ -1691,30 +2366,93 @@ fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t* synth, int chan)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param val MIDI channel pressure value (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val)
+fluid_synth_channel_pressure(fluid_synth_t *synth, int chan, int val)
{
- int result;
- fluid_return_val_if_fail (val >= 0 && val <= 127, FLUID_FAILED);
+ int result;
+ fluid_return_val_if_fail(val >= 0 && val <= 127, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "channelpressure\t%d\t%d", chan, val);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- fluid_channel_set_channel_pressure (synth->channel[chan], val);
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- result = fluid_synth_update_channel_pressure_LOCAL (synth, chan);
- FLUID_API_RETURN(result);
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "channelpressure\t%d\t%d", chan, val);
+ }
+
+ fluid_channel_set_channel_pressure(synth->channel[chan], val);
+ result = fluid_synth_update_channel_pressure_LOCAL(synth, chan);
+
+ FLUID_API_RETURN(result);
}
/* Updates channel pressure from within synthesis thread */
static int
-fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int chan)
+fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t *synth, int chan)
{
- return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_CHANNELPRESSURE);
+ return fluid_synth_modulate_voices_LOCAL(synth, chan, 0, FLUID_MOD_CHANNELPRESSURE);
+}
+
+/**
+ * Set the MIDI polyphonic key pressure controller value.
+ * @param synth FluidSynth instance
+ * @param chan MIDI channel number (0 to MIDI channel count - 1)
+ * @param key MIDI key number (0-127)
+ * @param val MIDI key pressure value (0-127)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ * @since 2.0.0
+ */
+int
+fluid_synth_key_pressure(fluid_synth_t *synth, int chan, int key, int val)
+{
+ int result;
+ fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED);
+ fluid_return_val_if_fail(val >= 0 && val <= 127, FLUID_FAILED);
+
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
+
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "keypressure\t%d\t%d\t%d", chan, key, val);
+ }
+
+ fluid_channel_set_key_pressure(synth->channel[chan], key, val);
+ result = fluid_synth_update_key_pressure_LOCAL(synth, chan, key);
+
+ FLUID_API_RETURN(result);
+}
+
+/* Updates key pressure from within synthesis thread */
+static int
+fluid_synth_update_key_pressure_LOCAL(fluid_synth_t *synth, int chan, int key)
+{
+ fluid_voice_t *voice;
+ int i;
+ int result = FLUID_OK;
+
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
+
+ if(voice->chan == chan && voice->key == key)
+ {
+ result = fluid_voice_modulate(voice, 0, FLUID_MOD_KEYPRESSURE);
+
+ if(result != FLUID_OK)
+ {
+ return result;
+ }
+ }
+ }
+
+ return result;
}
/**
@@ -1722,29 +2460,34 @@ fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t* synth, int chan)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param val MIDI pitch bend value (0-16383 with 8192 being center)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
+fluid_synth_pitch_bend(fluid_synth_t *synth, int chan, int val)
{
- int result;
- fluid_return_val_if_fail (val >= 0 && val <= 16383, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "pitchb\t%d\t%d", chan, val);
+ int result;
+ fluid_return_val_if_fail(val >= 0 && val <= 16383, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- fluid_channel_set_pitch_bend (synth->channel[chan], val);
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "pitchb\t%d\t%d", chan, val);
+ }
- result = fluid_synth_update_pitch_bend_LOCAL (synth, chan);
- FLUID_API_RETURN(result);
+ fluid_channel_set_pitch_bend(synth->channel[chan], val);
+ result = fluid_synth_update_pitch_bend_LOCAL(synth, chan);
+
+ FLUID_API_RETURN(result);
}
/* Local synthesis thread variant of pitch bend */
static int
-fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan)
+fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t *synth, int chan)
{
- return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_PITCHWHEEL);
+ return fluid_synth_modulate_voices_LOCAL(synth, chan, 0, FLUID_MOD_PITCHWHEEL);
}
/**
@@ -1753,16 +2496,22 @@ fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t* synth, int chan)
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param ppitch_bend Location to store MIDI pitch bend value (0-16383 with
* 8192 being center)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend)
+fluid_synth_get_pitch_bend(fluid_synth_t *synth, int chan, int *ppitch_bend)
{
- fluid_return_val_if_fail (ppitch_bend != NULL, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- *ppitch_bend = fluid_channel_get_pitch_bend (synth->channel[chan]);
- FLUID_API_RETURN(FLUID_OK);
+ int result;
+ fluid_return_val_if_fail(ppitch_bend != NULL, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
+
+ *ppitch_bend = fluid_channel_get_pitch_bend(synth->channel[chan]);
+ result = FLUID_OK;
+
+ FLUID_API_RETURN(result);
}
/**
@@ -1770,29 +2519,34 @@ fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param val Pitch wheel sensitivity value in semitones
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val)
+fluid_synth_pitch_wheel_sens(fluid_synth_t *synth, int chan, int val)
{
- int result;
- fluid_return_val_if_fail (val >= 0 && val <= 72, FLUID_FAILED); /* 6 octaves!? Better than no limit.. */
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "pitchsens\t%d\t%d", chan, val);
+ int result;
+ fluid_return_val_if_fail(val >= 0 && val <= 72, FLUID_FAILED); /* 6 octaves!? Better than no limit.. */
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- fluid_channel_set_pitch_wheel_sensitivity (synth->channel[chan], val);
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- result = fluid_synth_update_pitch_wheel_sens_LOCAL (synth, chan);
- FLUID_API_RETURN(result);
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "pitchsens\t%d\t%d", chan, val);
+ }
+
+ fluid_channel_set_pitch_wheel_sensitivity(synth->channel[chan], val);
+ result = fluid_synth_update_pitch_wheel_sens_LOCAL(synth, chan);
+
+ FLUID_API_RETURN(result);
}
/* Local synthesis thread variant of set pitch wheel sensitivity */
static int
-fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan)
+fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t *synth, int chan)
{
- return fluid_synth_modulate_voices_LOCAL (synth, chan, 0, FLUID_MOD_PITCHWHEELSENS);
+ return fluid_synth_modulate_voices_LOCAL(synth, chan, 0, FLUID_MOD_PITCHWHEELSENS);
}
/**
@@ -1800,17 +2554,23 @@ fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t* synth, int chan)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param pval Location to store pitch wheel sensitivity value in semitones
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since Sometime AFTER v1.0 API freeze.
*/
int
-fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval)
+fluid_synth_get_pitch_wheel_sens(fluid_synth_t *synth, int chan, int *pval)
{
- fluid_return_val_if_fail (pval != NULL, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- *pval = fluid_channel_get_pitch_wheel_sensitivity (synth->channel[chan]);
- FLUID_API_RETURN(FLUID_OK);
+ int result;
+ fluid_return_val_if_fail(pval != NULL, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
+
+ *pval = fluid_channel_get_pitch_wheel_sensitivity(synth->channel[chan]);
+ result = FLUID_OK;
+
+ FLUID_API_RETURN(result);
}
/**
@@ -1818,108 +2578,97 @@ fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param preset Preset to assign to channel or NULL to clear (ownership is taken over)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
static int
-fluid_synth_set_preset (fluid_synth_t *synth, int chan, fluid_preset_t *preset)
+fluid_synth_set_preset(fluid_synth_t *synth, int chan, fluid_preset_t *preset)
{
- fluid_channel_t *channel;
+ fluid_channel_t *channel;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- channel = synth->channel[chan];
+ channel = synth->channel[chan];
- return fluid_channel_set_preset (channel, preset);
+ return fluid_channel_set_preset(channel, preset);
}
/* Get a preset by SoundFont, bank and program numbers.
* Returns preset pointer or NULL.
- *
- * NOTE: The returned preset has been allocated, caller owns it and should
- * free it when finished using it.
*/
-static fluid_preset_t*
-fluid_synth_get_preset(fluid_synth_t* synth, unsigned int sfontnum,
- unsigned int banknum, unsigned int prognum)
+static fluid_preset_t *
+fluid_synth_get_preset(fluid_synth_t *synth, int sfontnum,
+ int banknum, int prognum)
{
- fluid_preset_t *preset = NULL;
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
+ fluid_sfont_t *sfont;
+ fluid_list_t *list;
- /* 128 indicates an "unset" operation" */
- if (prognum == FLUID_UNSET_PROGRAM) return NULL;
-
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
+ /* 128 indicates an "unset" operation" */
+ if(prognum == FLUID_UNSET_PROGRAM)
+ {
+ return NULL;
+ }
- if (fluid_sfont_get_id (sfont_info->sfont) == sfontnum)
+ for(list = synth->sfont; list; list = fluid_list_next(list))
{
- preset = fluid_sfont_get_preset (sfont_info->sfont,
- banknum - sfont_info->bankofs, prognum);
- if (preset) sfont_info->refcount++; /* Add reference to SoundFont */
- break;
+ sfont = fluid_list_get(list);
+
+ if(fluid_sfont_get_id(sfont) == sfontnum)
+ {
+ return fluid_sfont_get_preset(sfont, banknum - sfont->bankofs, prognum);
+ }
}
- }
- return preset;
+ return NULL;
}
/* Get a preset by SoundFont name, bank and program.
* Returns preset pointer or NULL.
- *
- * NOTE: The returned preset has been allocated, caller owns it and should
- * free it when finished using it.
*/
-static fluid_preset_t*
-fluid_synth_get_preset_by_sfont_name(fluid_synth_t* synth, const char *sfontname,
- unsigned int banknum, unsigned int prognum)
+static fluid_preset_t *
+fluid_synth_get_preset_by_sfont_name(fluid_synth_t *synth, const char *sfontname,
+ int banknum, int prognum)
{
- fluid_preset_t *preset = NULL;
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
-
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
+ fluid_sfont_t *sfont;
+ fluid_list_t *list;
- if (FLUID_STRCMP (fluid_sfont_get_name (sfont_info->sfont), sfontname) == 0)
+ for(list = synth->sfont; list; list = fluid_list_next(list))
{
- preset = fluid_sfont_get_preset (sfont_info->sfont,
- banknum - sfont_info->bankofs, prognum);
- if (preset) sfont_info->refcount++; /* Add reference to SoundFont */
- break;
+ sfont = fluid_list_get(list);
+
+ if(FLUID_STRCMP(fluid_sfont_get_name(sfont), sfontname) == 0)
+ {
+ return fluid_sfont_get_preset(sfont, banknum - sfont->bankofs, prognum);
+ }
}
- }
- return preset;
+ return NULL;
}
/* Find a preset by bank and program numbers.
* Returns preset pointer or NULL.
- *
- * NOTE: The returned preset has been allocated, caller owns it and should
- * free it when finished using it. */
-fluid_preset_t*
-fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
- unsigned int prognum)
+ */
+fluid_preset_t *
+fluid_synth_find_preset(fluid_synth_t *synth, int banknum,
+ int prognum)
{
- fluid_preset_t *preset = NULL;
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
-
- for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
+ fluid_preset_t *preset;
+ fluid_sfont_t *sfont;
+ fluid_list_t *list;
- preset = fluid_sfont_get_preset (sfont_info->sfont,
- banknum - sfont_info->bankofs, prognum);
- if (preset)
+ for(list = synth->sfont; list; list = fluid_list_next(list))
{
- sfont_info->refcount++; /* Add reference to SoundFont */
- break;
+ sfont = fluid_list_get(list);
+
+ preset = fluid_sfont_get_preset(sfont, banknum - sfont->bankofs, prognum);
+
+ if(preset)
+ {
+ return preset;
+ }
}
- }
- return preset;
+ return NULL;
}
/**
@@ -1927,7 +2676,7 @@ fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param prognum MIDI program number (0-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
/* FIXME - Currently not real-time safe, due to preset allocation and mutex lock,
* and may be called from within synthesis context. */
@@ -1935,72 +2684,90 @@ fluid_synth_find_preset(fluid_synth_t* synth, unsigned int banknum,
/* As of 1.1.1 prognum can be set to 128 to unset the preset. Not documented
* since fluid_synth_unset_program() should be used instead. */
int
-fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
-{
- fluid_preset_t* preset = NULL;
- fluid_channel_t* channel;
- int subst_bank, subst_prog, banknum = 0, result;
-
- fluid_return_val_if_fail (prognum >= 0 && prognum <= 128, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- channel = synth->channel[chan];
- if (channel->channel_type == CHANNEL_TYPE_DRUM)
- banknum = DRUM_INST_BANK;
- else
- fluid_channel_get_sfont_bank_prog(channel, NULL, &banknum, NULL);
-
- if (synth->verbose)
- FLUID_LOG(FLUID_INFO, "prog\t%d\t%d\t%d", chan, banknum, prognum);
-
- /* I think this is a hack for MIDI files that do bank changes in GM mode.
- * Proper way to handle this would probably be to ignore bank changes when in
- * GM mode. - JG
- * This is now possible by setting synth.midi-bank-select=gm, but let the hack
- * stay for the time being. - DH
- */
- if (prognum != FLUID_UNSET_PROGRAM)
- {
- subst_bank = banknum;
- subst_prog = prognum;
-
- preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
-
- /* Fallback to another preset if not found */
- if (!preset) {
- /* Percussion: Fallback to preset 0 in percussion bank */
- if (subst_bank == DRUM_INST_BANK) {
- subst_prog = 0;
- preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
- }
- /* Melodic instrument */
- else {
- /* Fallback first to bank 0:prognum */
- subst_bank = 0;
+fluid_synth_program_change(fluid_synth_t *synth, int chan, int prognum)
+{
+ fluid_preset_t *preset = NULL;
+ fluid_channel_t *channel;
+ int subst_bank, subst_prog, banknum = 0, result = FLUID_FAILED;
+
+ fluid_return_val_if_fail(prognum >= 0 && prognum <= 128, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
+
+ channel = synth->channel[chan];
+
+ if(channel->channel_type == CHANNEL_TYPE_DRUM)
+ {
+ banknum = DRUM_INST_BANK;
+ }
+ else
+ {
+ fluid_channel_get_sfont_bank_prog(channel, NULL, &banknum, NULL);
+ }
+
+ if(synth->verbose)
+ {
+ FLUID_LOG(FLUID_INFO, "prog\t%d\t%d\t%d", chan, banknum, prognum);
+ }
+
+ /* I think this is a hack for MIDI files that do bank changes in GM mode.
+ * Proper way to handle this would probably be to ignore bank changes when in
+ * GM mode. - JG
+ * This is now possible by setting synth.midi-bank-select=gm, but let the hack
+ * stay for the time being. - DH
+ */
+ if(prognum != FLUID_UNSET_PROGRAM)
+ {
+ subst_bank = banknum;
+ subst_prog = prognum;
+
preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
- /* Fallback to first preset in bank 0 (usually piano...) */
- if (!preset)
+ /* Fallback to another preset if not found */
+ if(!preset)
{
- subst_prog = 0;
- preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
+ /* Percussion: Fallback to preset 0 in percussion bank */
+ if(channel->channel_type == CHANNEL_TYPE_DRUM)
+ {
+ subst_prog = 0;
+ subst_bank = DRUM_INST_BANK;
+ preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
+ }
+ /* Melodic instrument */
+ else
+ {
+ /* Fallback first to bank 0:prognum */
+ subst_bank = 0;
+ preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
+
+ /* Fallback to first preset in bank 0 (usually piano...) */
+ if(!preset)
+ {
+ subst_prog = 0;
+ preset = fluid_synth_find_preset(synth, subst_bank, subst_prog);
+ }
+ }
+
+ if(preset)
+ {
+ FLUID_LOG(FLUID_WARN, "Instrument not found on channel %d [bank=%d prog=%d], substituted [bank=%d prog=%d]",
+ chan, banknum, prognum, subst_bank, subst_prog);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_WARN, "No preset found on channel %d [bank=%d prog=%d]", chan, banknum, prognum);
+ }
}
- }
-
- if (preset)
- FLUID_LOG(FLUID_WARN, "Instrument not found on channel %d [bank=%d prog=%d], substituted [bank=%d prog=%d]",
- chan, banknum, prognum, subst_bank, subst_prog);
- else
- FLUID_LOG(FLUID_WARN, "No preset found on channel %d [bank=%d prog=%d]",
- chan, banknum, prognum);
}
- }
- /* Assign the SoundFont ID and program number to the channel */
- fluid_channel_set_sfont_bank_prog (channel, preset ? fluid_sfont_get_id (preset->sfont) : 0,
- -1, prognum);
- result = fluid_synth_set_preset (synth, chan, preset);
- FLUID_API_RETURN(result);
+ /* Assign the SoundFont ID and program number to the channel */
+ fluid_channel_set_sfont_bank_prog(channel, preset ? fluid_sfont_get_id(preset->sfont) : 0,
+ -1, prognum);
+ result = fluid_synth_set_preset(synth, chan, preset);
+
+ FLUID_API_RETURN(result);
}
/**
@@ -2008,16 +2775,28 @@ fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param bank MIDI bank number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ * @note This function does not change the instrument currently assigned to \c chan,
+ * as it is usually called prior to fluid_synth_program_change(). If you still want
+ * instrument changes to take effect immediately, call fluid_synth_program_reset()
+ * after having set up the bank configuration.
+ *
*/
int
-fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank)
+fluid_synth_bank_select(fluid_synth_t *synth, int chan, int bank)
{
- fluid_return_val_if_fail (bank <= 16383, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- fluid_channel_set_sfont_bank_prog (synth->channel[chan], -1, bank, -1);
- FLUID_API_RETURN(FLUID_OK);
+ int result;
+ fluid_return_val_if_fail(bank <= 16383, FLUID_FAILED);
+ fluid_return_val_if_fail(bank >= 0, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
+
+ fluid_channel_set_sfont_bank_prog(synth->channel[chan], -1, bank, -1);
+ result = FLUID_OK;
+
+ FLUID_API_RETURN(result);
}
/**
@@ -2025,16 +2804,25 @@ fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param sfont_id ID of a loaded SoundFont
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ * @note This function does not change the instrument currently assigned to \c chan,
+ * as it is usually called prior to fluid_synth_bank_select() or fluid_synth_program_change().
+ * If you still want instrument changes to take effect immediately, call fluid_synth_program_reset()
+ * after having selected the soundfont.
*/
int
-fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id)
+fluid_synth_sfont_select(fluid_synth_t *synth, int chan, int sfont_id)
{
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- fluid_channel_set_sfont_bank_prog(synth->channel[chan], sfont_id, -1, -1);
+ int result;
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- FLUID_API_RETURN(FLUID_OK);
+ fluid_channel_set_sfont_bank_prog(synth->channel[chan], sfont_id, -1, -1);
+ result = FLUID_OK;
+
+ FLUID_API_RETURN(result);
}
/**
@@ -2044,18 +2832,15 @@ fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id)
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.1
*
- * Note: Channel retains its SoundFont ID and bank numbers, while the program
+ * @note Channel retains its SoundFont ID and bank numbers, while the program
* number is set to an "unset" state. MIDI program changes may re-assign a
* preset if one matches.
*/
int
-fluid_synth_unset_program (fluid_synth_t *synth, int chan)
+fluid_synth_unset_program(fluid_synth_t *synth, int chan)
{
- int result;
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- result = fluid_synth_program_change (synth, chan, FLUID_UNSET_PROGRAM);
- FLUID_API_RETURN(result);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ FLUID_API_RETURN(fluid_synth_program_change(synth, chan, FLUID_UNSET_PROGRAM));
}
/**
@@ -2065,27 +2850,35 @@ fluid_synth_unset_program (fluid_synth_t *synth, int chan)
* @param sfont_id Location to store SoundFont ID
* @param bank_num Location to store MIDI bank number
* @param preset_num Location to store MIDI program number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_get_program(fluid_synth_t* synth, int chan, unsigned int* sfont_id,
- unsigned int* bank_num, unsigned int* preset_num)
+fluid_synth_get_program(fluid_synth_t *synth, int chan, int *sfont_id,
+ int *bank_num, int *preset_num)
{
- fluid_channel_t* channel;
+ int result;
+ fluid_channel_t *channel;
- fluid_return_val_if_fail (sfont_id != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (bank_num != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (preset_num != NULL, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ fluid_return_val_if_fail(sfont_id != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(bank_num != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(preset_num != NULL, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- channel = synth->channel[chan];
- fluid_channel_get_sfont_bank_prog(channel, (int *)sfont_id, (int *)bank_num,
- (int *)preset_num);
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- /* 128 indicates that the preset is unset. Set to 0 to be backwards compatible. */
- if (*preset_num == FLUID_UNSET_PROGRAM) *preset_num = 0;
+ channel = synth->channel[chan];
+ fluid_channel_get_sfont_bank_prog(channel, sfont_id, bank_num, preset_num);
- FLUID_API_RETURN(FLUID_OK);
+ /* 128 indicates that the preset is unset. Set to 0 to be backwards compatible. */
+ if(*preset_num == FLUID_UNSET_PROGRAM)
+ {
+ *preset_num = 0;
+ }
+
+ result = FLUID_OK;
+
+ FLUID_API_RETURN(result);
}
/**
@@ -2095,34 +2888,40 @@ fluid_synth_get_program(fluid_synth_t* synth, int chan, unsigned int* sfont_id,
* @param sfont_id ID of a loaded SoundFont
* @param bank_num MIDI bank number
* @param preset_num MIDI program number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_program_select(fluid_synth_t* synth, int chan, unsigned int sfont_id,
- unsigned int bank_num, unsigned int preset_num)
+fluid_synth_program_select(fluid_synth_t *synth, int chan, int sfont_id,
+ int bank_num, int preset_num)
{
- fluid_preset_t* preset = NULL;
- fluid_channel_t* channel;
- int result;
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ fluid_preset_t *preset = NULL;
+ fluid_channel_t *channel;
+ int result;
+ fluid_return_val_if_fail(bank_num >= 0, FLUID_FAILED);
+ fluid_return_val_if_fail(preset_num >= 0, FLUID_FAILED);
- channel = synth->channel[chan];
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- /* ++ Allocate preset */
- preset = fluid_synth_get_preset (synth, sfont_id, bank_num, preset_num);
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- if (preset == NULL) {
- FLUID_LOG(FLUID_ERR,
- "There is no preset with bank number %d and preset number %d in SoundFont %d",
- bank_num, preset_num, sfont_id);
- FLUID_API_RETURN(FLUID_FAILED);
- }
+ channel = synth->channel[chan];
+
+ preset = fluid_synth_get_preset(synth, sfont_id, bank_num, preset_num);
+
+ if(preset == NULL)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "There is no preset with bank number %d and preset number %d in SoundFont %d",
+ bank_num, preset_num, sfont_id);
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
+
+ /* Assign the new SoundFont ID, bank and program number to the channel */
+ fluid_channel_set_sfont_bank_prog(channel, sfont_id, bank_num, preset_num);
+ result = fluid_synth_set_preset(synth, chan, preset);
- /* Assign the new SoundFont ID, bank and program number to the channel */
- fluid_channel_set_sfont_bank_prog (channel, sfont_id, bank_num, preset_num);
- result = fluid_synth_set_preset (synth, chan, preset);
-
- FLUID_API_RETURN(result);
+ FLUID_API_RETURN(result);
}
/**
@@ -2132,37 +2931,42 @@ fluid_synth_program_select(fluid_synth_t* synth, int chan, unsigned int sfont_id
* @param sfont_name Name of a loaded SoundFont
* @param bank_num MIDI bank number
* @param preset_num MIDI program number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.0
*/
int
-fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
- const char *sfont_name, unsigned int bank_num,
- unsigned int preset_num)
-{
- fluid_preset_t* preset = NULL;
- fluid_channel_t* channel;
- int result;
- fluid_return_val_if_fail (sfont_name != NULL, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- channel = synth->channel[chan];
-
- /* ++ Allocate preset */
- preset = fluid_synth_get_preset_by_sfont_name (synth, sfont_name, bank_num,
- preset_num);
- if (preset == NULL) {
- FLUID_LOG(FLUID_ERR,
- "There is no preset with bank number %d and preset number %d in SoundFont %s",
- bank_num, preset_num, sfont_name);
- FLUID_API_RETURN(FLUID_FAILED);
- }
+fluid_synth_program_select_by_sfont_name(fluid_synth_t *synth, int chan,
+ const char *sfont_name, int bank_num,
+ int preset_num)
+{
+ fluid_preset_t *preset = NULL;
+ fluid_channel_t *channel;
+ int result;
+ fluid_return_val_if_fail(sfont_name != NULL, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* Allowed only on MIDI channel enabled */
+ FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED);
- /* Assign the new SoundFont ID, bank and program number to the channel */
- fluid_channel_set_sfont_bank_prog (channel, fluid_sfont_get_id (preset->sfont),
- bank_num, preset_num);
- result = fluid_synth_set_preset (synth, chan, preset);
- FLUID_API_RETURN(result);
+ channel = synth->channel[chan];
+
+ preset = fluid_synth_get_preset_by_sfont_name(synth, sfont_name, bank_num,
+ preset_num);
+
+ if(preset == NULL)
+ {
+ FLUID_LOG(FLUID_ERR,
+ "There is no preset with bank number %d and preset number %d in SoundFont %s",
+ bank_num, preset_num, sfont_name);
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
+
+ /* Assign the new SoundFont ID, bank and program number to the channel */
+ fluid_channel_set_sfont_bank_prog(channel, fluid_sfont_get_id(preset->sfont),
+ bank_num, preset_num);
+ result = fluid_synth_set_preset(synth, chan, preset);
+
+ FLUID_API_RETURN(result);
}
/*
@@ -2171,63 +2975,66 @@ fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
* unloaded or reloaded.
*/
static void
-fluid_synth_update_presets(fluid_synth_t* synth)
+fluid_synth_update_presets(fluid_synth_t *synth)
{
- fluid_channel_t *channel;
- fluid_preset_t *preset;
- int sfont, bank, prog;
- int chan;
+ fluid_channel_t *channel;
+ fluid_preset_t *preset;
+ int sfont, bank, prog;
+ int chan;
- for (chan = 0; chan < synth->midi_channels; chan++) {
- channel = synth->channel[chan];
- fluid_channel_get_sfont_bank_prog (channel, &sfont, &bank, &prog);
- preset = fluid_synth_get_preset (synth, sfont, bank, prog);
- fluid_synth_set_preset (synth, chan, preset);
- }
+ for(chan = 0; chan < synth->midi_channels; chan++)
+ {
+ channel = synth->channel[chan];
+ fluid_channel_get_sfont_bank_prog(channel, &sfont, &bank, &prog);
+ preset = fluid_synth_get_preset(synth, sfont, bank, prog);
+ fluid_synth_set_preset(synth, chan, preset);
+ }
}
-/* Handler for synth.gain setting. */
-static int
-fluid_synth_update_sample_rate(fluid_synth_t* synth, char* name, double value)
+/* Handler for synth.sample-rate setting. */
+static void
+fluid_synth_handle_sample_rate(void *data, const char *name, double value)
{
- fluid_synth_set_sample_rate(synth, (float) value);
- return 0;
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+ fluid_synth_set_sample_rate(synth, (float) value);
}
+
/**
- * Set sample rate of the synth.
- * NOTE: This function is currently experimental and should only be
- * used when no voices or notes are active, and before any rendering calls.
+ * Set sample rate of the synth.
+ * @note This function should only be used when no voices or notes are active.
* @param synth FluidSynth instance
* @param sample_rate New sample rate (Hz)
* @since 1.1.2
*/
-void
-fluid_synth_set_sample_rate(fluid_synth_t* synth, float sample_rate)
+void
+fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate)
{
- int i;
- fluid_return_if_fail (synth != NULL);
- fluid_synth_api_enter(synth);
- fluid_clip (sample_rate, 8000.0f, 96000.0f);
- synth->sample_rate = sample_rate;
-
- fluid_settings_getint(synth->settings, "synth.min-note-length", &i);
- synth->min_note_length_ticks = (unsigned int) (i*synth->sample_rate/1000.0f);
-
- for (i=0; i < synth->polyphony; i++)
- fluid_voice_set_output_rate(synth->voice[i], sample_rate);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_samplerate,
- 0, sample_rate);
- fluid_synth_api_exit(synth);
+ int i;
+ fluid_return_if_fail(synth != NULL);
+ fluid_synth_api_enter(synth);
+ fluid_clip(sample_rate, 8000.0f, 96000.0f);
+ synth->sample_rate = sample_rate;
+
+ synth->min_note_length_ticks = fluid_synth_get_min_note_length_LOCAL(synth);
+
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ fluid_voice_set_output_rate(synth->voice[i], sample_rate);
+ }
+
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_samplerate,
+ 0, sample_rate);
+ fluid_synth_api_exit(synth);
}
/* Handler for synth.gain setting. */
-static int
-fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value)
+static void
+fluid_synth_handle_gain(void *data, const char *name, double value)
{
- fluid_synth_set_gain(synth, (float) value);
- return 0;
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+ fluid_synth_set_gain(synth, (float) value);
}
/**
@@ -2236,33 +3043,37 @@ fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value)
* @param gain Gain value (function clamps value to the range 0.0 to 10.0)
*/
void
-fluid_synth_set_gain(fluid_synth_t* synth, float gain)
+fluid_synth_set_gain(fluid_synth_t *synth, float gain)
{
- fluid_return_if_fail (synth != NULL);
- fluid_synth_api_enter(synth);
-
- fluid_clip (gain, 0.0f, 10.0f);
+ fluid_return_if_fail(synth != NULL);
+ fluid_synth_api_enter(synth);
+
+ fluid_clip(gain, 0.0f, 10.0f);
- synth->gain = gain;
- fluid_synth_update_gain_LOCAL (synth);
- fluid_synth_api_exit(synth);
+ synth->gain = gain;
+ fluid_synth_update_gain_LOCAL(synth);
+ fluid_synth_api_exit(synth);
}
/* Called by synthesis thread to update the gain in all voices */
static void
-fluid_synth_update_gain_LOCAL(fluid_synth_t* synth)
+fluid_synth_update_gain_LOCAL(fluid_synth_t *synth)
{
- fluid_voice_t *voice;
- float gain;
- int i;
+ fluid_voice_t *voice;
+ float gain;
+ int i;
+
+ gain = synth->gain;
- gain = synth->gain;
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
- for (i = 0; i < synth->polyphony; i++)
- {
- voice = synth->voice[i];
- if (_PLAYING (voice)) fluid_voice_set_gain (voice, gain);
- }
+ if(fluid_voice_is_playing(voice))
+ {
+ fluid_voice_set_gain(voice, gain);
+ }
+ }
}
/**
@@ -2271,80 +3082,98 @@ fluid_synth_update_gain_LOCAL(fluid_synth_t* synth)
* @return Synth gain value (0.0 to 10.0)
*/
float
-fluid_synth_get_gain(fluid_synth_t* synth)
+fluid_synth_get_gain(fluid_synth_t *synth)
{
- float result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ float result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = synth->gain;
- FLUID_API_RETURN(result);
+ result = synth->gain;
+ FLUID_API_RETURN(result);
}
/*
* Handler for synth.polyphony setting.
*/
-static int
-fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value)
+static void
+fluid_synth_handle_polyphony(void *data, const char *name, int value)
{
- fluid_synth_set_polyphony(synth, value);
- return 0;
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+ fluid_synth_set_polyphony(synth, value);
}
/**
* Set synthesizer polyphony (max number of voices).
* @param synth FluidSynth instance
* @param polyphony Polyphony to assign
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.0.6
*/
int
-fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony)
+fluid_synth_set_polyphony(fluid_synth_t *synth, int polyphony)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (polyphony >= 1 && polyphony <= 65535, FLUID_FAILED);
- fluid_synth_api_enter(synth);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(polyphony >= 1 && polyphony <= 65535, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- result = fluid_synth_update_polyphony_LOCAL(synth, polyphony);
+ result = fluid_synth_update_polyphony_LOCAL(synth, polyphony);
- FLUID_API_RETURN(result);
+ FLUID_API_RETURN(result);
}
/* Called by synthesis thread to update the polyphony value */
static int
-fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth, int new_polyphony)
-{
- fluid_voice_t *voice;
- int i;
-
- if (new_polyphony > synth->nvoice) {
- /* Create more voices */
- fluid_voice_t** new_voices = FLUID_REALLOC(synth->voice,
- sizeof(fluid_voice_t*) * new_polyphony);
- if (new_voices == NULL)
- return FLUID_FAILED;
- synth->voice = new_voices;
- for (i = synth->nvoice; i < new_polyphony; i++) {
- synth->voice[i] = new_fluid_voice(synth->sample_rate);
- if (synth->voice[i] == NULL)
- return FLUID_FAILED;
- }
- synth->nvoice = new_polyphony;
- }
-
- synth->polyphony = new_polyphony;
- /* turn off any voices above the new limit */
- for (i = synth->polyphony; i < synth->nvoice; i++)
- {
- voice = synth->voice[i];
- if (_PLAYING (voice)) fluid_voice_off (voice);
- }
-
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
- synth->polyphony, 0.0f);
-
- return FLUID_OK;
+fluid_synth_update_polyphony_LOCAL(fluid_synth_t *synth, int new_polyphony)
+{
+ fluid_voice_t *voice;
+ int i;
+
+ if(new_polyphony > synth->nvoice)
+ {
+ /* Create more voices */
+ fluid_voice_t **new_voices = FLUID_REALLOC(synth->voice,
+ sizeof(fluid_voice_t *) * new_polyphony);
+
+ if(new_voices == NULL)
+ {
+ return FLUID_FAILED;
+ }
+
+ synth->voice = new_voices;
+
+ for(i = synth->nvoice; i < new_polyphony; i++)
+ {
+ synth->voice[i] = new_fluid_voice(synth->eventhandler, synth->sample_rate);
+
+ if(synth->voice[i] == NULL)
+ {
+ return FLUID_FAILED;
+ }
+
+ fluid_voice_set_custom_filter(synth->voice[i], synth->custom_filter_type, synth->custom_filter_flags);
+ }
+
+ synth->nvoice = new_polyphony;
+ }
+
+ synth->polyphony = new_polyphony;
+
+ /* turn off any voices above the new limit */
+ for(i = synth->polyphony; i < synth->nvoice; i++)
+ {
+ voice = synth->voice[i];
+
+ if(fluid_voice_is_playing(voice))
+ {
+ fluid_voice_off(voice);
+ }
+ }
+
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
+ synth->polyphony, 0.0f);
+
+ return FLUID_OK;
}
/**
@@ -2354,36 +3183,43 @@ fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth, int new_polyphony)
* @since 1.0.6
*/
int
-fluid_synth_get_polyphony(fluid_synth_t* synth)
+fluid_synth_get_polyphony(fluid_synth_t *synth)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
-
- result = synth->polyphony;
- FLUID_API_RETURN(result);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+
+ result = synth->polyphony;
+ FLUID_API_RETURN(result);
}
/**
- * Get current number of active voices.
+ * @brief Get current number of active voices.
+ *
+ * I.e. the no. of voices that have been
+ * started and have not yet finished. Unless called from synthesis context,
+ * this number does not necessarily have to be equal to the number of voices
+ * currently processed by the DSP loop, see below.
* @param synth FluidSynth instance
* @return Number of currently active voices.
* @since 1.1.0
*
- * Note: To generate accurate continuous statistics of the voice count, caller
+ * @note To generate accurate continuous statistics of the voice count, caller
* should ensure this function is called synchronously with the audio synthesis
- * process. This can be done in the new_fluid_audio_driver2() audio callback
- * function for example.
+ * process. This can be done in the new_fluid_audio_driver2() audio callback
+ * function for example. Otherwise every call to this function may return different
+ * voice counts as it may change after any (concurrent) call to fluid_synth_write_*() made by
+ * e.g. an audio driver or the applications audio rendering thread.
*/
int
-fluid_synth_get_active_voice_count(fluid_synth_t* synth)
+fluid_synth_get_active_voice_count(fluid_synth_t *synth)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- result = synth->active_voice_count;
- FLUID_API_RETURN(result);
+ result = synth->active_voice_count;
+ FLUID_API_RETURN(result);
}
/**
@@ -2394,171 +3230,485 @@ fluid_synth_get_active_voice_count(fluid_synth_t* synth)
* Audio is synthesized this number of frames at a time. Defaults to 64 frames.
*/
int
-fluid_synth_get_internal_bufsize(fluid_synth_t* synth)
+fluid_synth_get_internal_bufsize(fluid_synth_t *synth)
{
- return FLUID_BUFSIZE;
+ return FLUID_BUFSIZE;
}
/**
- * Resend a bank select and a program change for every channel.
+ * Resend a bank select and a program change for every channel and assign corresponding instruments.
* @param synth FluidSynth instance
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* This function is called mainly after a SoundFont has been loaded,
* unloaded or reloaded.
*/
int
-fluid_synth_program_reset(fluid_synth_t* synth)
+fluid_synth_program_reset(fluid_synth_t *synth)
{
- int i, prog;
- fluid_synth_api_enter(synth);
- /* try to set the correct presets */
- for (i = 0; i < synth->midi_channels; i++){
- fluid_channel_get_sfont_bank_prog (synth->channel[i], NULL, NULL, &prog);
- fluid_synth_program_change(synth, i, prog);
- }
- FLUID_API_RETURN(FLUID_OK);
+ int i, prog;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+
+ /* try to set the correct presets */
+ for(i = 0; i < synth->midi_channels; i++)
+ {
+ fluid_channel_get_sfont_bank_prog(synth->channel[i], NULL, NULL, &prog);
+ fluid_synth_program_change(synth, i, prog);
+ }
+
+ FLUID_API_RETURN(FLUID_OK);
}
/**
- * Synthesize a block of floating point audio to audio buffers.
+ * Synthesize a block of floating point audio to separate audio buffers (multichannel rendering). First effect channel used by reverb, second for chorus.
* @param synth FluidSynth instance
* @param len Count of audio frames to synthesize
- * @param left Array of floats to store left channel of audio (len in size)
- * @param right Array of floats to store right channel of audio (len in size)
- * @param fx_left Not currently used
- * @param fx_right Not currently used
- * @return FLUID_OK on success, FLUID_FAIL otherwise
+ * @param left Array of float buffers to store left channel of planar audio (as many as \c synth.audio-channels buffers, each of \c len in size)
+ * @param right Array of float buffers to store right channel of planar audio (size: dito)
+ * @param fx_left Since 1.1.7: If not \c NULL, array of float buffers to store left effect channels (as many as \c synth.effects-channels buffers, each of \c len in size)
+ * @param fx_right Since 1.1.7: If not \c NULL, array of float buffers to store right effect channels (size: dito)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ *
+ * @note Should only be called from synthesis thread.
+ *
+ * @deprecated fluid_synth_nwrite_float() is deprecated and will be removed in a future release. It may continue to work or it may return #FLUID_FAILED in the future. Consider using the more powerful and flexible fluid_synth_process().
*
- * NOTE: Should only be called from synthesis thread.
+ * Usage example:
+ * @code{.cpp}
+ const int FramesToRender = 64;
+ int channels;
+ // retrieve number of stereo audio channels
+ fluid_settings_getint(settings, "synth.audio-channels", &channels);
+
+ // we need twice as many (mono-)buffers
+ channels *= 2;
+
+ // fluid_synth_nwrite_float renders planar audio, e.g. if synth.audio-channels==16: each midi channel gets rendered to its own stereo buffer, rather than having one buffer and interleaved PCM
+ float** mix_buf = new float*[channels];
+ for(int i = 0; i < channels; i++)
+ {
+ mix_buf[i] = new float[FramesToRender];
+ }
+
+ // retrieve number of (stereo) effect channels (internally hardcoded to reverb (first chan) and chrous (second chan))
+ fluid_settings_getint(settings, "synth.effects-channels", &channels);
+ channels *= 2;
+
+ float** fx_buf = new float*[channels];
+ for(int i = 0; i < channels; i++)
+ {
+ fx_buf[i] = new float[FramesToRender];
+ }
+
+ float** mix_buf_l = mix_buf;
+ float** mix_buf_r = &mix_buf[channels/2];
+
+ float** fx_buf_l = fx_buf;
+ float** fx_buf_r = &fx_buf[channels/2];
+
+ fluid_synth_nwrite_float(synth, FramesToRender, mix_buf_l, mix_buf_r, fx_buf_l, fx_buf_r)
+ * @endcode
*/
int
-fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
- float** left, float** right,
- float** fx_left, float** fx_right)
-{
- fluid_real_t** left_in;
- fluid_real_t** right_in;
- double time = fluid_utime();
- int i, num, available, count;
+fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
+ float **left, float **right,
+ float **fx_left, float **fx_right)
+{
+ fluid_real_t *left_in, *fx_left_in;
+ fluid_real_t *right_in, *fx_right_in;
+ double time = fluid_utime();
+ int i, num, available, count;
#ifdef WITH_FLOAT
- int bytes;
+ int bytes;
#endif
- float cpu_load;
+ float cpu_load;
- if (!synth->eventhandler->is_threadsafe)
- fluid_synth_api_enter(synth);
-
- /* First, take what's still available in the buffer */
- count = 0;
- num = synth->cur;
- if (synth->cur < FLUID_BUFSIZE) {
- available = FLUID_BUFSIZE - synth->cur;
- fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(left != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(right != NULL, FLUID_FAILED);
+
+ /* First, take what's still available in the buffer */
+ count = 0;
+ num = synth->cur;
+
+ if(synth->cur < FLUID_BUFSIZE)
+ {
+ available = FLUID_BUFSIZE - synth->cur;
+ fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+ fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in);
- num = (available > len)? len : available;
+ num = (available > len) ? len : available;
#ifdef WITH_FLOAT
- bytes = num * sizeof(float);
+ bytes = num * sizeof(float);
#endif
- for (i = 0; i < synth->audio_channels; i++) {
+ for(i = 0; i < synth->audio_channels; i++)
+ {
#ifdef WITH_FLOAT
- FLUID_MEMCPY(left[i], left_in[i] + synth->cur, bytes);
- FLUID_MEMCPY(right[i], right_in[i] + synth->cur, bytes);
+ FLUID_MEMCPY(left[i], &left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes);
+ FLUID_MEMCPY(right[i], &right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes);
#else //WITH_FLOAT
- int j;
- for (j = 0; j < num; j++) {
- left[i][j] = (float) left_in[i][j + synth->cur];
- right[i][j] = (float) right_in[i][j + synth->cur];
- }
+ int j;
+
+ for(j = 0; j < num; j++)
+ {
+ left[i][j] = (float) left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
+ right[i][j] = (float) right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
+ }
+
#endif //WITH_FLOAT
+ }
+
+ for(i = 0; i < synth->effects_channels; i++)
+ {
+#ifdef WITH_FLOAT
+
+ if(fx_left != NULL)
+ {
+ FLUID_MEMCPY(fx_left[i], &fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes);
+ }
+
+ if(fx_right != NULL)
+ {
+ FLUID_MEMCPY(fx_right[i], &fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes);
+ }
+
+#else //WITH_FLOAT
+ int j;
+
+ if(fx_left != NULL)
+ {
+ for(j = 0; j < num; j++)
+ {
+ fx_left[i][j] = (float) fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
+ }
+ }
+
+ if(fx_right != NULL)
+ {
+ for(j = 0; j < num; j++)
+ {
+ fx_right[i][j] = (float) fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur];
+ }
+ }
+
+#endif //WITH_FLOAT
+ }
+
+ count += num;
+ num += synth->cur; /* if we're now done, num becomes the new synth->cur below */
}
- count += num;
- num += synth->cur; /* if we're now done, num becomes the new synth->cur below */
- }
- /* Then, run one_block() and copy till we have 'len' samples */
- while (count < len) {
- fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 0);
- fluid_synth_render_blocks(synth, 1); // TODO:
- fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+ /* Then, run one_block() and copy till we have 'len' samples */
+ while(count < len)
+ {
+ fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 0);
+ fluid_synth_render_blocks(synth, 1); // TODO:
+ fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+ fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in);
- num = (FLUID_BUFSIZE > len - count)? len - count : FLUID_BUFSIZE;
+ num = (FLUID_BUFSIZE > len - count) ? len - count : FLUID_BUFSIZE;
#ifdef WITH_FLOAT
- bytes = num * sizeof(float);
+ bytes = num * sizeof(float);
#endif
- for (i = 0; i < synth->audio_channels; i++) {
+ for(i = 0; i < synth->audio_channels; i++)
+ {
+#ifdef WITH_FLOAT
+ FLUID_MEMCPY(left[i] + count, &left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes);
+ FLUID_MEMCPY(right[i] + count, &right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes);
+#else //WITH_FLOAT
+ int j;
+
+ for(j = 0; j < num; j++)
+ {
+ left[i][j + count] = (float) left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
+ right[i][j + count] = (float) right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
+ }
+
+#endif //WITH_FLOAT
+ }
+
+ for(i = 0; i < synth->effects_channels; i++)
+ {
#ifdef WITH_FLOAT
- FLUID_MEMCPY(left[i] + count, left_in[i], bytes);
- FLUID_MEMCPY(right[i] + count, right_in[i], bytes);
+
+ if(fx_left != NULL)
+ {
+ FLUID_MEMCPY(fx_left[i] + count, &fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes);
+ }
+
+ if(fx_right != NULL)
+ {
+ FLUID_MEMCPY(fx_right[i] + count, &fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes);
+ }
+
#else //WITH_FLOAT
- int j;
- for (j = 0; j < num; j++) {
- left[i][j + count] = (float) left_in[i][j];
- right[i][j + count] = (float) right_in[i][j];
- }
+ int j;
+
+ if(fx_left != NULL)
+ {
+ for(j = 0; j < num; j++)
+ {
+ fx_left[i][j + count] = (float) fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
+ }
+ }
+
+ if(fx_right != NULL)
+ {
+ for(j = 0; j < num; j++)
+ {
+ fx_right[i][j + count] = (float) fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j];
+ }
+ }
+
#endif //WITH_FLOAT
+ }
+
+ count += num;
}
- count += num;
- }
+ synth->cur = num;
- synth->cur = num;
+ time = fluid_utime() - time;
+ cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0);
+ fluid_atomic_float_set(&synth->cpu_load, cpu_load);
- time = fluid_utime() - time;
- cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
- fluid_atomic_float_set (&synth->cpu_load, cpu_load);
+ return FLUID_OK;
+}
- if (!synth->eventhandler->is_threadsafe)
- fluid_synth_api_exit(synth);
-
- return FLUID_OK;
+/**
+ * mixes the samples of \p in to \p out
+ *
+ * @param out the output sample buffer to mix to
+ * @param ooff sample offset in \p out
+ * @param in the rvoice_mixer input sample buffer to mix from
+ * @param ioff sample offset in \p in
+ * @param buf_idx the sample buffer index of \p in to mix from
+ * @param num number of samples to mix
+ */
+static FLUID_INLINE void fluid_synth_mix_single_buffer(float *FLUID_RESTRICT out,
+ int ooff,
+ const fluid_real_t *FLUID_RESTRICT in,
+ int ioff,
+ int buf_idx,
+ int num)
+{
+ if(out != NULL)
+ {
+ int j;
+ for(j = 0; j < num; j++)
+ {
+ out[j + ooff] += (float) in[buf_idx * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + ioff];
+ }
+ }
}
/**
- * Synthesize floating point audio to audio buffers.
+ * @brief Synthesize floating point audio to stereo audio channels (implements the default interface #fluid_audio_func_t).
+ *
+ * Synthesize and <strong>mix</strong> audio to a given number of planar audio buffers.
+ * Therefore pass <code>nout = N*2</code> float buffers to \p out in order to render
+ * the synthesized audio to \p N stereo channels. Each float buffer must be
+ * able to hold \p len elements.
+ *
+ * \p out contains an array of planar buffers for normal, dry, stereo
+ * audio (alternating left and right). Like:
+@code{.cpp}
+out[0] = left_buffer_audio_channel_0
+out[1] = right_buffer_audio_channel_0
+out[2] = left_buffer_audio_channel_1
+out[3] = right_buffer_audio_channel_1
+...
+out[ (i * 2 + 0) % nout ] = left_buffer_audio_channel_i
+out[ (i * 2 + 1) % nout ] = right_buffer_audio_channel_i
+@endcode
+ *
+ * for zero-based channel index \p i.
+ * The buffer layout of \p fx used for storing effects
+ * like reverb and chorus looks similar:
+@code{.cpp}
+fx[0] = left_buffer_channel_of_reverb_unit_0
+fx[1] = right_buffer_channel_of_reverb_unit_0
+fx[2] = left_buffer_channel_of_chorus_unit_0
+fx[3] = right_buffer_channel_of_chorus_unit_0
+fx[4] = left_buffer_channel_of_reverb_unit_1
+fx[5] = right_buffer_channel_of_reverb_unit_1
+fx[6] = left_buffer_channel_of_chorus_unit_1
+fx[7] = right_buffer_channel_of_chorus_unit_1
+fx[8] = left_buffer_channel_of_reverb_unit_2
+...
+fx[ ((k * fluid_synth_count_effects_channels() + j) * 2 + 0) % nfx ] = left_buffer_for_effect_channel_j_of_unit_k
+fx[ ((k * fluid_synth_count_effects_channels() + j) * 2 + 1) % nfx ] = right_buffer_for_effect_channel_j_of_unit_k
+@endcode
+ * where <code>0 <= k < fluid_synth_count_effects_groups()</code> is a zero-based index denoting the effects unit and
+ * <code>0 <= j < fluid_synth_count_effects_channels()</code> is a zero-based index denoting the effect channel within
+ * unit \p k.
+ *
+ * Any voice playing is assigned to audio channels based on the MIDI channel its playing on. Let \p chan be the
+ * zero-based MIDI channel index an arbitrary voice is playing on. To determine the audio channel and effects unit it is
+ * going to be rendered to use:
+ *
+ * <code>i = chan % fluid_synth_count_audio_groups()</code>
+ *
+ * <code>k = chan % fluid_synth_count_effects_groups()</code>
+ *
* @param synth FluidSynth instance
- * @param len Count of audio frames to synthesize
- * @param nin Ignored
- * @param in Ignored
- * @param nout Count of arrays in 'out'
- * @param out Array of arrays to store audio to
- * @return FLUID_OK on success, FLUID_FAIL otherwise
+ * @param len Count of audio frames to synthesize and store in every single buffer provided by \p out and \p fx.
+ * @param nfx Count of arrays in \c fx. Must be a multiple of 2 (because of stereo)
+ * and in the range <code>0 <= nfx/2 <= (fluid_synth_count_effects_channels() * fluid_synth_count_effects_groups())</code>.
+ * @param fx Array of buffers to store effects audio to. Buffers may
+alias with buffers of \c out. NULL buffers are permitted and will cause to skip mixing any audio into that buffer.
+ * @param nout Count of arrays in \c out. Must be a multiple of 2
+(because of stereo) and in the range <code>0 <= nout/2 <= fluid_synth_count_audio_channels()</code>.
+ * @param out Array of buffers to store (dry) audio to. Buffers may
+alias with buffers of \c fx. NULL buffers are permitted and will cause to skip mixing any audio into that buffer.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise.
*
- * This function implements the default interface defined in fluidsynth/audio.h.
- * NOTE: Should only be called from synthesis thread.
- */
-/*
- * FIXME: Currently if nout != 2 memory allocation will occur!
+ * @parblock
+ * @note The owner of the sample buffers must zero them out before calling this
+ * function, because any synthesized audio is mixed (i.e. added) to the buffers.
+ * E.g. if fluid_synth_process() is called from a custom audio driver process function
+ * (see new_fluid_audio_driver2()), the audio driver takes care of zeroing the buffers.
+ * @endparblock
+ *
+ * @parblock
+ * @note No matter how many buffers you pass in, fluid_synth_process()
+ * will always render all audio channels to the
+ * buffers in \c out and all effects channels to the
+ * buffers in \c fx, provided that <code>nout > 0</code> and <code>nfx > 0</code> respectively. If
+ * <code>nout/2 < fluid_synth_count_audio_channels()</code> it will wrap around. Same
+ * is true for effects audio if <code>nfx/2 < (fluid_synth_count_effects_channels() * fluid_synth_count_effects_groups())</code>.
+ * See usage examples below.
+ * @endparblock
+ *
+ * @parblock
+ * @note Should only be called from synthesis thread.
+ * @endparblock
*/
int
-fluid_synth_process(fluid_synth_t* synth, int len, int nin, float** in,
- int nout, float** out)
-{
- if (nout==2) {
- return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1);
- }
- else {
- float **left, **right;
- int i;
- left = FLUID_ARRAY(float*, nout/2);
- right = FLUID_ARRAY(float*, nout/2);
- if ((left == NULL) || (right == NULL)) {
- FLUID_LOG(FLUID_ERR, "Out of memory.");
- FLUID_FREE(left);
- FLUID_FREE(right);
- return FLUID_FAILED;
- }
- for(i=0; i<nout/2; i++) {
- left[i] = out[2*i];
- right[i] = out[2*i+1];
- }
- fluid_synth_nwrite_float(synth, len, left, right, NULL, NULL);
- FLUID_FREE(left);
- FLUID_FREE(right);
+fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
+ int nout, float *out[])
+{
+ fluid_real_t *left_in, *fx_left_in;
+ fluid_real_t *right_in, *fx_right_in;
+ int nfxchan, nfxunits, naudchan;
+
+ double time = fluid_utime();
+ int i, f, num, count;
+
+ float cpu_load;
+
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(nfx % 2 == 0, FLUID_FAILED);
+ fluid_return_val_if_fail(nout % 2 == 0, FLUID_FAILED);
+
+ nfxchan = synth->effects_channels;
+ nfxunits = synth->effects_groups;
+ naudchan = synth->audio_channels;
+
+ fluid_return_val_if_fail(0 <= nfx / 2 && nfx / 2 <= nfxchan * nfxunits, FLUID_FAILED);
+ fluid_return_val_if_fail(0 <= nout / 2 && nout / 2 <= naudchan, FLUID_FAILED);
+
+ fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+ fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in);
+ fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, FALSE);
+
+
+ /* First, take what's still available in the buffer */
+ count = 0;
+ num = synth->cur;
+
+ if(synth->cur < FLUID_BUFSIZE)
+ {
+ int available = FLUID_BUFSIZE - synth->cur;
+ num = (available > len) ? len : available;
+
+ if(nout != 0)
+ {
+ for(i = 0; i < naudchan; i++)
+ {
+ float *out_buf = out[(i * 2) % nout];
+ fluid_synth_mix_single_buffer(out_buf, 0, left_in, synth->cur, i, num);
+
+ out_buf = out[(i * 2 + 1) % nout];
+ fluid_synth_mix_single_buffer(out_buf, 0, right_in, synth->cur, i, num);
+ }
+ }
+
+ if(nfx != 0)
+ {
+ // loop over all effects units
+ for(f = 0; f < nfxunits; f++)
+ {
+ // write out all effects (i.e. reverb and chorus)
+ for(i = 0; i < nfxchan; i++)
+ {
+ int buf_idx = f * nfxchan + i;
+
+ float *out_buf = fx[(buf_idx * 2) % nfx];
+ fluid_synth_mix_single_buffer(out_buf, 0, fx_left_in, synth->cur, buf_idx, num);
+
+ out_buf = fx[(buf_idx * 2 + 1) % nfx];
+ fluid_synth_mix_single_buffer(out_buf, 0, fx_right_in, synth->cur, buf_idx, num);
+ }
+ }
+ }
+
+ count += num;
+ num += synth->cur; /* if we're now done, num becomes the new synth->cur below */
+ }
+
+ /* Then, render blocks and copy till we have 'len' samples */
+ while(count < len)
+ {
+ int blocksleft = (len - count + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
+ int blockcount = fluid_synth_render_blocks(synth, blocksleft);
+
+ num = (blockcount * FLUID_BUFSIZE > len - count) ? len - count : blockcount * FLUID_BUFSIZE;
+
+ if(nout != 0)
+ {
+ for(i = 0; i < naudchan; i++)
+ {
+ float *out_buf = out[(i * 2) % nout];
+ fluid_synth_mix_single_buffer(out_buf, count, left_in, 0, i, num);
+
+ out_buf = out[(i * 2 + 1) % nout];
+ fluid_synth_mix_single_buffer(out_buf, count, right_in, 0, i, num);
+ }
+ }
+
+ if(nfx != 0)
+ {
+ // loop over all effects units
+ for(f = 0; f < nfxunits; f++)
+ {
+ // write out all effects (i.e. reverb and chorus)
+ for(i = 0; i < nfxchan; i++)
+ {
+ int buf_idx = f * nfxchan + i;
+
+ float *out_buf = fx[(buf_idx * 2) % nfx];
+ fluid_synth_mix_single_buffer(out_buf, count, fx_left_in, 0, buf_idx, num);
+
+ out_buf = fx[(buf_idx * 2 + 1) % nfx];
+ fluid_synth_mix_single_buffer(out_buf, count, fx_right_in, 0, buf_idx, num);
+ }
+ }
+ }
+
+ count += num;
+ }
+
+ synth->cur = num;
+
+ time = fluid_utime() - time;
+ cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0);
+ fluid_atomic_float_set(&synth->cpu_load, cpu_load);
+
return FLUID_OK;
- }
}
/**
@@ -2571,59 +3721,63 @@ fluid_synth_process(fluid_synth_t* synth, int len, int nin, float** in,
* @param rout Array of floats to store right channel of audio
* @param roff Offset index in 'rout' for first sample
* @param rincr Increment between samples stored to 'rout'
- * @return FLUID_OK on success, FLUID_FAIL otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* Useful for storing interleaved stereo (lout = rout, loff = 0, roff = 1,
* lincr = 2, rincr = 2).
*
- * NOTE: Should only be called from synthesis thread.
+ * @note Should only be called from synthesis thread.
+ * @note Reverb and Chorus are mixed to \c lout resp. \c rout.
*/
int
-fluid_synth_write_float(fluid_synth_t* synth, int len,
- void* lout, int loff, int lincr,
- void* rout, int roff, int rincr)
-{
- int i, j, k, l;
- float* left_out = (float*) lout;
- float* right_out = (float*) rout;
- fluid_real_t** left_in;
- fluid_real_t** right_in;
- double time = fluid_utime();
- float cpu_load;
-
- fluid_profile_ref_var (prof_ref);
- if (!synth->eventhandler->is_threadsafe)
- fluid_synth_api_enter(synth);
-
- fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
- l = synth->cur;
- fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
-
- for (i = 0, j = loff, k = roff; i < len; i++, l++, j += lincr, k += rincr) {
- /* fill up the buffers as needed */
- if (l >= synth->curmax) {
- int blocksleft = (len-i+FLUID_BUFSIZE-1) / FLUID_BUFSIZE;
- synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
- fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+fluid_synth_write_float(fluid_synth_t *synth, int len,
+ void *lout, int loff, int lincr,
+ void *rout, int roff, int rincr)
+{
+ int i, j, k, l;
+ float *left_out = (float *) lout;
+ float *right_out = (float *) rout;
+ fluid_real_t *left_in;
+ fluid_real_t *right_in;
+ double time = fluid_utime();
+ float cpu_load;
+
+ fluid_profile_ref_var(prof_ref);
+
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(lout != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(rout != NULL, FLUID_FAILED);
+
+ fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
+ l = synth->cur;
+ fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
- l = 0;
- }
+ for(i = 0, j = loff, k = roff; i < len; i++, l++, j += lincr, k += rincr)
+ {
+ /* fill up the buffers as needed */
+ if(l >= synth->curmax)
+ {
+ int blocksleft = (len - i + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
+ synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
+ fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
- left_out[j] = (float) left_in[0][l];
- right_out[k] = (float) right_in[0][l];
- }
+ l = 0;
+ }
- synth->cur = l;
+ left_out[j] = (float) left_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + l];
+ right_out[k] = (float) right_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + l];
+ }
- time = fluid_utime() - time;
- cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
- fluid_atomic_float_set (&synth->cpu_load, cpu_load);
+ synth->cur = l;
- if (!synth->eventhandler->is_threadsafe)
- fluid_synth_api_exit(synth);
- fluid_profile(FLUID_PROF_WRITE, prof_ref);
-
- return FLUID_OK;
+ time = fluid_utime() - time;
+ cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0);
+ fluid_atomic_float_set(&synth->cpu_load, cpu_load);
+
+ fluid_profile_write(FLUID_PROF_WRITE, prof_ref,
+ fluid_rvoice_mixer_get_active_voices(synth->eventhandler->mixer),
+ len);
+ return FLUID_OK;
}
#define DITHER_SIZE 48000
@@ -2632,31 +3786,39 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
static float rand_table[DITHER_CHANNELS][DITHER_SIZE];
/* Init dither table */
-static void
+static void
init_dither(void)
{
- float d, dp;
- int c, i;
+ float d, dp;
+ int c, i;
- for (c = 0; c < DITHER_CHANNELS; c++) {
- dp = 0;
- for (i = 0; i < DITHER_SIZE-1; i++) {
- d = rand() / (float)RAND_MAX - 0.5f;
- rand_table[c][i] = d - dp;
- dp = d;
+ for(c = 0; c < DITHER_CHANNELS; c++)
+ {
+ dp = 0;
+
+ for(i = 0; i < DITHER_SIZE - 1; i++)
+ {
+ d = rand() / (float)RAND_MAX - 0.5f;
+ rand_table[c][i] = d - dp;
+ dp = d;
+ }
+
+ rand_table[c][DITHER_SIZE - 1] = 0 - dp;
}
- rand_table[c][DITHER_SIZE-1] = 0 - dp;
- }
}
/* A portable replacement for roundf(), seems it may actually be faster too! */
-static inline int
-roundi (float x)
+static FLUID_INLINE int
+roundi(float x)
{
- if (x >= 0.0f)
- return (int)(x+0.5f);
- else
- return (int)(x-0.5f);
+ if(x >= 0.0f)
+ {
+ return (int)(x + 0.5f);
+ }
+ else
+ {
+ return (int)(x - 0.5f);
+ }
}
/**
@@ -2669,84 +3831,98 @@ roundi (float x)
* @param rout Array of 16 bit words to store right channel of audio
* @param roff Offset index in 'rout' for first sample
* @param rincr Increment between samples stored to 'rout'
- * @return FLUID_OK on success, FLUID_FAIL otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* Useful for storing interleaved stereo (lout = rout, loff = 0, roff = 1,
* lincr = 2, rincr = 2).
*
- * NOTE: Should only be called from synthesis thread.
- * NOTE: Dithering is performed when converting from internal floating point to
+ * @note Should only be called from synthesis thread.
+ * @note Reverb and Chorus are mixed to \c lout resp. \c rout.
+ * @note Dithering is performed when converting from internal floating point to
* 16 bit audio.
*/
int
-fluid_synth_write_s16(fluid_synth_t* synth, int len,
- void* lout, int loff, int lincr,
- void* rout, int roff, int rincr)
-{
- int i, j, k, cur;
- signed short* left_out = (signed short*) lout;
- signed short* right_out = (signed short*) rout;
- fluid_real_t** left_in;
- fluid_real_t** right_in;
- fluid_real_t left_sample;
- fluid_real_t right_sample;
- double time = fluid_utime();
- int di;
- //double prof_ref_on_block;
- float cpu_load;
- fluid_profile_ref_var (prof_ref);
-
- if (!synth->eventhandler->is_threadsafe)
- fluid_synth_api_enter(synth);
-
- fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
- fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+fluid_synth_write_s16(fluid_synth_t *synth, int len,
+ void *lout, int loff, int lincr,
+ void *rout, int roff, int rincr)
+{
+ int i, j, k, cur;
+ signed short *left_out = (signed short *) lout;
+ signed short *right_out = (signed short *) rout;
+ fluid_real_t *left_in;
+ fluid_real_t *right_in;
+ fluid_real_t left_sample;
+ fluid_real_t right_sample;
+ double time = fluid_utime();
+ int di;
+ float cpu_load;
+
+ fluid_profile_ref_var(prof_ref);
+
+ fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
+ fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
- cur = synth->cur;
- di = synth->dither_index;
+ cur = synth->cur;
+ di = synth->dither_index;
- for (i = 0, j = loff, k = roff; i < len; i++, cur++, j += lincr, k += rincr) {
+ for(i = 0, j = loff, k = roff; i < len; i++, cur++, j += lincr, k += rincr)
+ {
- /* fill up the buffers as needed */
- if (cur >= synth->curmax) {
- int blocksleft = (len-i+FLUID_BUFSIZE-1) / FLUID_BUFSIZE;
- //prof_ref_on_block = fluid_profile_ref();
- synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
- fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
- cur = 0;
+ /* fill up the buffers as needed */
+ if(cur >= synth->curmax)
+ {
+ int blocksleft = (len - i + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
+ synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
+ fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
+ cur = 0;
+ }
- //fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref_on_block);
- }
+ left_sample = roundi(left_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + cur] * 32766.0f + rand_table[0][di]);
+ right_sample = roundi(right_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + cur] * 32766.0f + rand_table[1][di]);
+
+ di++;
+
+ if(di >= DITHER_SIZE)
+ {
+ di = 0;
+ }
- left_sample = roundi (left_in[0][cur] * 32766.0f + rand_table[0][di]);
- right_sample = roundi (right_in[0][cur] * 32766.0f + rand_table[1][di]);
+ /* digital clipping */
+ if(left_sample > 32767.0f)
+ {
+ left_sample = 32767.0f;
+ }
- di++;
- if (di >= DITHER_SIZE) di = 0;
+ if(left_sample < -32768.0f)
+ {
+ left_sample = -32768.0f;
+ }
- /* digital clipping */
- if (left_sample > 32767.0f) left_sample = 32767.0f;
- if (left_sample < -32768.0f) left_sample = -32768.0f;
- if (right_sample > 32767.0f) right_sample = 32767.0f;
- if (right_sample < -32768.0f) right_sample = -32768.0f;
+ if(right_sample > 32767.0f)
+ {
+ right_sample = 32767.0f;
+ }
- left_out[j] = (signed short) left_sample;
- right_out[k] = (signed short) right_sample;
- }
+ if(right_sample < -32768.0f)
+ {
+ right_sample = -32768.0f;
+ }
- synth->cur = cur;
- synth->dither_index = di; /* keep dither buffer continous */
+ left_out[j] = (signed short) left_sample;
+ right_out[k] = (signed short) right_sample;
+ }
- fluid_profile(FLUID_PROF_WRITE, prof_ref);
+ synth->cur = cur;
+ synth->dither_index = di; /* keep dither buffer continous */
- time = fluid_utime() - time;
- cpu_load = 0.5 * (synth->cpu_load + time * synth->sample_rate / len / 10000.0);
- fluid_atomic_float_set (&synth->cpu_load, cpu_load);
+ time = fluid_utime() - time;
+ cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0);
+ fluid_atomic_float_set(&synth->cpu_load, cpu_load);
- if (!synth->eventhandler->is_threadsafe)
- fluid_synth_api_exit(synth);
-
- return 0;
+ fluid_profile_write(FLUID_PROF_WRITE, prof_ref,
+ fluid_rvoice_mixer_get_active_voices(synth->eventhandler->mixer),
+ len);
+ return 0;
}
/**
@@ -2764,63 +3940,87 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
* @param roff Offset index in 'rout' for first sample
* @param rincr Increment between samples stored to 'rout'
*
- * NOTE: Currently private to libfluidsynth.
+ * @note Currently private to libfluidsynth.
*/
void
-fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
- void* lout, int loff, int lincr,
- void* rout, int roff, int rincr)
-{
- int i, j, k;
- signed short* left_out = (signed short*) lout;
- signed short* right_out = (signed short*) rout;
- fluid_real_t left_sample;
- fluid_real_t right_sample;
- int di = *dither_index;
- fluid_profile_ref_var (prof_ref);
+fluid_synth_dither_s16(int *dither_index, int len, float *lin, float *rin,
+ void *lout, int loff, int lincr,
+ void *rout, int roff, int rincr)
+{
+ int i, j, k;
+ signed short *left_out = (signed short *) lout;
+ signed short *right_out = (signed short *) rout;
+ fluid_real_t left_sample;
+ fluid_real_t right_sample;
+ int di = *dither_index;
+ fluid_profile_ref_var(prof_ref);
+
+ for(i = 0, j = loff, k = roff; i < len; i++, j += lincr, k += rincr)
+ {
- for (i = 0, j = loff, k = roff; i < len; i++, j += lincr, k += rincr) {
+ left_sample = roundi(lin[i] * 32766.0f + rand_table[0][di]);
+ right_sample = roundi(rin[i] * 32766.0f + rand_table[1][di]);
- left_sample = roundi (lin[i] * 32766.0f + rand_table[0][di]);
- right_sample = roundi (rin[i] * 32766.0f + rand_table[1][di]);
+ di++;
- di++;
- if (di >= DITHER_SIZE) di = 0;
+ if(di >= DITHER_SIZE)
+ {
+ di = 0;
+ }
+
+ /* digital clipping */
+ if(left_sample > 32767.0f)
+ {
+ left_sample = 32767.0f;
+ }
+
+ if(left_sample < -32768.0f)
+ {
+ left_sample = -32768.0f;
+ }
- /* digital clipping */
- if (left_sample > 32767.0f) left_sample = 32767.0f;
- if (left_sample < -32768.0f) left_sample = -32768.0f;
- if (right_sample > 32767.0f) right_sample = 32767.0f;
- if (right_sample < -32768.0f) right_sample = -32768.0f;
+ if(right_sample > 32767.0f)
+ {
+ right_sample = 32767.0f;
+ }
- left_out[j] = (signed short) left_sample;
- right_out[k] = (signed short) right_sample;
- }
+ if(right_sample < -32768.0f)
+ {
+ right_sample = -32768.0f;
+ }
- *dither_index = di; /* keep dither buffer continous */
+ left_out[j] = (signed short) left_sample;
+ right_out[k] = (signed short) right_sample;
+ }
+
+ *dither_index = di; /* keep dither buffer continous */
- fluid_profile(FLUID_PROF_WRITE, prof_ref);
+ fluid_profile(FLUID_PROF_WRITE, prof_ref, 0, len);
}
static void
-fluid_synth_check_finished_voices(fluid_synth_t* synth)
-{
- int j;
- fluid_rvoice_t* fv;
-
- while (NULL != (fv = fluid_rvoice_eventhandler_get_finished_voice(synth->eventhandler))) {
- for (j=0; j < synth->polyphony; j++) {
- if (synth->voice[j]->rvoice == fv) {
- fluid_voice_unlock_rvoice(synth->voice[j]);
- fluid_voice_off(synth->voice[j]);
- break;
- }
- else if (synth->voice[j]->overflow_rvoice == fv) {
- fluid_voice_overflow_rvoice_finished(synth->voice[j]);
- break;
- }
+fluid_synth_check_finished_voices(fluid_synth_t *synth)
+{
+ int j;
+ fluid_rvoice_t *fv;
+
+ while(NULL != (fv = fluid_rvoice_eventhandler_get_finished_voice(synth->eventhandler)))
+ {
+ for(j = 0; j < synth->polyphony; j++)
+ {
+ if(synth->voice[j]->rvoice == fv)
+ {
+ fluid_voice_unlock_rvoice(synth->voice[j]);
+ fluid_voice_stop(synth->voice[j]);
+ break;
+ }
+ else if(synth->voice[j]->overflow_rvoice == fv)
+ {
+ fluid_voice_overflow_rvoice_finished(synth->voice[j]);
+ break;
+ }
+ }
}
- }
}
/**
@@ -2828,9 +4028,9 @@ fluid_synth_check_finished_voices(fluid_synth_t* synth)
* Make sure no (other) rendering is running in parallel when
* you call this function!
*/
-void fluid_synth_process_event_queue(fluid_synth_t* synth)
+void fluid_synth_process_event_queue(fluid_synth_t *synth)
{
- fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler);
+ fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler);
}
@@ -2840,102 +4040,206 @@ void fluid_synth_process_event_queue(fluid_synth_t* synth)
* @return number of blocks rendered. Might (often) return less than requested
*/
static int
-fluid_synth_render_blocks(fluid_synth_t* synth, int blockcount)
+fluid_synth_render_blocks(fluid_synth_t *synth, int blockcount)
{
- int i;
- fluid_profile_ref_var (prof_ref);
+ int i, maxblocks;
+ fluid_profile_ref_var(prof_ref);
- /* Assign ID of synthesis thread */
+ /* Assign ID of synthesis thread */
// synth->synth_thread_id = fluid_thread_get_id ();
- fluid_check_fpe("??? Just starting up ???");
-
- fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler);
-
- for (i=0; i < blockcount; i++) {
- fluid_sample_timer_process(synth);
- fluid_synth_add_ticks(synth, FLUID_BUFSIZE);
- if (fluid_rvoice_eventhandler_dispatch_count(synth->eventhandler)) {
- // Something has happened, we can't process more
- blockcount = i+1;
- break;
+ fluid_check_fpe("??? Just starting up ???");
+
+ fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler);
+
+ /* do not render more blocks than we can store internally */
+ maxblocks = fluid_rvoice_mixer_get_bufcount(synth->eventhandler->mixer);
+
+ if(blockcount > maxblocks)
+ {
+ blockcount = maxblocks;
+ }
+
+ for(i = 0; i < blockcount; i++)
+ {
+ fluid_sample_timer_process(synth);
+ fluid_synth_add_ticks(synth, FLUID_BUFSIZE);
+
+ /* If events have been queued waiting for fluid_rvoice_eventhandler_dispatch_all()
+ * (should only happen with parallel render) stop processing and go for rendering
+ */
+ if(fluid_rvoice_eventhandler_dispatch_count(synth->eventhandler))
+ {
+ // Something has happened, we can't process more
+ blockcount = i + 1;
+ break;
+ }
}
- }
- fluid_check_fpe("fluid_sample_timer_process");
+ fluid_check_fpe("fluid_sample_timer_process");
- blockcount = fluid_rvoice_mixer_render(synth->eventhandler->mixer, blockcount);
+ blockcount = fluid_rvoice_mixer_render(synth->eventhandler->mixer, blockcount);
- /* Testcase, that provokes a denormal floating point error */
+ /* Testcase, that provokes a denormal floating point error */
#if 0
- {float num=1;while (num != 0){num*=0.5;};};
+ {
+ float num = 1;
+
+ while(num != 0)
+ {
+ num *= 0.5;
+ };
+ };
#endif
- fluid_check_fpe("??? Remainder of synth_one_block ???");
- fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref);
- return blockcount;
+ fluid_check_fpe("??? Remainder of synth_one_block ???");
+ fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref,
+ fluid_rvoice_mixer_get_active_voices(synth->eventhandler->mixer),
+ blockcount * FLUID_BUFSIZE);
+ return blockcount;
}
+/*
+ * Handler for synth.reverb.* and synth.chorus.* double settings.
+ */
+static void fluid_synth_handle_reverb_chorus_num(void *data, const char *name, double value)
+{
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+ fluid_return_if_fail(synth != NULL);
-static int fluid_synth_update_overflow (fluid_synth_t *synth, char *name,
- fluid_real_t value)
+ if(FLUID_STRCMP(name, "synth.reverb.room-size") == 0)
+ {
+ fluid_synth_set_reverb_roomsize(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.reverb.damp") == 0)
+ {
+ fluid_synth_set_reverb_damp(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.reverb.width") == 0)
+ {
+ fluid_synth_set_reverb_width(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.reverb.level") == 0)
+ {
+ fluid_synth_set_reverb_level(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.chorus.depth") == 0)
+ {
+ fluid_synth_set_chorus_depth(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.chorus.speed") == 0)
+ {
+ fluid_synth_set_chorus_speed(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.chorus.level") == 0)
+ {
+ fluid_synth_set_chorus_level(synth, value);
+ }
+}
+
+/*
+ * Handler for synth.reverb.* and synth.chorus.* integer settings.
+ */
+static void fluid_synth_handle_reverb_chorus_int(void *data, const char *name, int value)
{
- double d;
- fluid_synth_api_enter(synth);
-
- fluid_settings_getnum(synth->settings, "synth.overflow.percussion", &d);
- synth->overflow.percussion = d;
- fluid_settings_getnum(synth->settings, "synth.overflow.released", &d);
- synth->overflow.released = d;
- fluid_settings_getnum(synth->settings, "synth.overflow.sustained", &d);
- synth->overflow.sustained = d;
- fluid_settings_getnum(synth->settings, "synth.overflow.volume", &d);
- synth->overflow.volume = d;
- fluid_settings_getnum(synth->settings, "synth.overflow.age", &d);
- synth->overflow.age = d;
-
- FLUID_API_RETURN(0);
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+ fluid_return_if_fail(synth != NULL);
+
+ if(FLUID_STRCMP(name, "synth.reverb.active") == 0)
+ {
+ fluid_synth_set_reverb_on(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.chorus.active") == 0)
+ {
+ fluid_synth_set_chorus_on(synth, value);
+ }
+ else if(FLUID_STRCMP(name, "synth.chorus.nr") == 0)
+ {
+ fluid_synth_set_chorus_nr(synth, value);
+ }
}
+/*
+ * Handler for synth.overflow.* settings.
+ */
+static void fluid_synth_handle_overflow(void *data, const char *name, double value)
+{
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+ fluid_return_if_fail(synth != NULL);
+
+ fluid_synth_api_enter(synth);
+
+ if(FLUID_STRCMP(name, "synth.overflow.percussion") == 0)
+ {
+ synth->overflow.percussion = value;
+ }
+ else if(FLUID_STRCMP(name, "synth.overflow.released") == 0)
+ {
+ synth->overflow.released = value;
+ }
+ else if(FLUID_STRCMP(name, "synth.overflow.sustained") == 0)
+ {
+ synth->overflow.sustained = value;
+ }
+ else if(FLUID_STRCMP(name, "synth.overflow.volume") == 0)
+ {
+ synth->overflow.volume = value;
+ }
+ else if(FLUID_STRCMP(name, "synth.overflow.age") == 0)
+ {
+ synth->overflow.age = value;
+ }
+ else if(FLUID_STRCMP(name, "synth.overflow.important") == 0)
+ {
+ synth->overflow.important = value;
+ }
+
+ fluid_synth_api_exit(synth);
+}
/* Selects a voice for killing. */
-static fluid_voice_t*
-fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth)
+static fluid_voice_t *
+fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t *synth)
{
- int i;
- fluid_real_t best_prio = OVERFLOW_PRIO_CANNOT_KILL-1;
- fluid_real_t this_voice_prio;
- fluid_voice_t* voice;
- int best_voice_index=-1;
- unsigned int ticks = fluid_synth_get_ticks(synth);
-
- for (i = 0; i < synth->polyphony; i++) {
+ int i;
+ float best_prio = OVERFLOW_PRIO_CANNOT_KILL - 1;
+ float this_voice_prio;
+ fluid_voice_t *voice;
+ int best_voice_index = -1;
+ unsigned int ticks = fluid_synth_get_ticks(synth);
- voice = synth->voice[i];
+ for(i = 0; i < synth->polyphony; i++)
+ {
- /* safeguard against an available voice. */
- if (_AVAILABLE(voice)) {
- return voice;
- }
- this_voice_prio = fluid_voice_get_overflow_prio(voice, &synth->overflow,
- ticks);
+ voice = synth->voice[i];
+
+ /* safeguard against an available voice. */
+ if(_AVAILABLE(voice))
+ {
+ return voice;
+ }
+
+ this_voice_prio = fluid_voice_get_overflow_prio(voice, &synth->overflow,
+ ticks);
- /* check if this voice has less priority than the previous candidate. */
- if (this_voice_prio < best_prio) {
- best_voice_index = i;
- best_prio = this_voice_prio;
+ /* check if this voice has less priority than the previous candidate. */
+ if(this_voice_prio < best_prio)
+ {
+ best_voice_index = i;
+ best_prio = this_voice_prio;
+ }
}
- }
- if (best_voice_index < 0) {
- return NULL;
- }
+ if(best_voice_index < 0)
+ {
+ return NULL;
+ }
- voice = synth->voice[best_voice_index];
- FLUID_LOG(FLUID_DBG, "Killing voice %d, index %d, chan %d, key %d ",
- voice->id, best_voice_index, voice->chan, voice->key);
- fluid_voice_off(voice);
+ voice = synth->voice[best_voice_index];
+ FLUID_LOG(FLUID_DBG, "Killing voice %d, index %d, chan %d, key %d ",
+ fluid_voice_get_id(voice), best_voice_index, fluid_voice_get_channel(voice), fluid_voice_get_key(voice));
+ fluid_voice_off(voice);
- return voice;
+ return voice;
}
@@ -2952,108 +4256,150 @@ fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth)
* The returned voice comes with default modulators and generators.
* A single noteon event may create any number of voices, when the preset is layered.
*
- * NOTE: Should only be called from within synthesis thread, which includes
+ * @note Should only be called from within synthesis thread, which includes
* SoundFont loader preset noteon method.
*/
-fluid_voice_t*
-fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan, int key, int vel)
-{
- int i, k;
- fluid_voice_t* voice = NULL;
- fluid_channel_t* channel = NULL;
- unsigned int ticks;
-
- fluid_return_val_if_fail (sample != NULL, NULL);
- FLUID_API_ENTRY_CHAN(NULL);
-
- /* check if there's an available synthesis process */
- for (i = 0; i < synth->polyphony; i++) {
- if (_AVAILABLE(synth->voice[i])) {
- voice = synth->voice[i];
- break;
- }
- }
-
- /* No success yet? Then stop a running voice. */
- if (voice == NULL) {
- FLUID_LOG(FLUID_DBG, "Polyphony exceeded, trying to kill a voice");
- voice = fluid_synth_free_voice_by_kill_LOCAL(synth);
- }
-
- if (voice == NULL) {
- FLUID_LOG(FLUID_WARN, "Failed to allocate a synthesis process. (chan=%d,key=%d)", chan, key);
- FLUID_API_RETURN(NULL);
- }
- ticks = fluid_synth_get_ticks(synth);
-
- if (synth->verbose) {
- k = 0;
- for (i = 0; i < synth->polyphony; i++) {
- if (!_AVAILABLE(synth->voice[i])) {
- k++;
- }
- }
-
- FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d",
- chan, key, vel, synth->storeid,
- (float) ticks / 44100.0f,
- (fluid_curtime() - synth->start) / 1000.0f,
- 0.0f,
- k);
- }
-
- if (chan >= 0) {
- channel = synth->channel[chan];
- }
-
- if (fluid_voice_init (voice, sample, channel, key, vel,
- synth->storeid, ticks, synth->gain) != FLUID_OK) {
- FLUID_LOG(FLUID_WARN, "Failed to initialize voice");
- FLUID_API_RETURN(NULL);
- }
-
- /* add the default modulators to the synthesis process. */
- fluid_voice_add_mod(voice, &default_vel2att_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.1 */
- fluid_voice_add_mod(voice, &default_vel2filter_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.2 */
- fluid_voice_add_mod(voice, &default_at2viblfo_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.3 */
- fluid_voice_add_mod(voice, &default_mod2viblfo_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.4 */
- fluid_voice_add_mod(voice, &default_att_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.5 */
- fluid_voice_add_mod(voice, &default_pan_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.6 */
- fluid_voice_add_mod(voice, &default_expr_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.7 */
- fluid_voice_add_mod(voice, &default_reverb_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.8 */
- fluid_voice_add_mod(voice, &default_chorus_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.9 */
- fluid_voice_add_mod(voice, &default_pitch_bend_mod, FLUID_VOICE_DEFAULT); /* SF2.01 $8.4.10 */
-
- FLUID_API_RETURN(voice);
+fluid_voice_t *
+fluid_synth_alloc_voice(fluid_synth_t *synth, fluid_sample_t *sample,
+ int chan, int key, int vel)
+{
+ fluid_return_val_if_fail(sample != NULL, NULL);
+ FLUID_API_ENTRY_CHAN(NULL);
+ FLUID_API_RETURN(fluid_synth_alloc_voice_LOCAL(synth, sample, chan, key, vel, NULL));
+
+}
+
+fluid_voice_t *
+fluid_synth_alloc_voice_LOCAL(fluid_synth_t *synth, fluid_sample_t *sample, int chan, int key, int vel, fluid_zone_range_t *zone_range)
+{
+ int i, k;
+ fluid_voice_t *voice = NULL;
+ fluid_channel_t *channel = NULL;
+ unsigned int ticks;
+
+ /* check if there's an available synthesis process */
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ if(_AVAILABLE(synth->voice[i]))
+ {
+ voice = synth->voice[i];
+ break;
+ }
+ }
+
+ /* No success yet? Then stop a running voice. */
+ if(voice == NULL)
+ {
+ FLUID_LOG(FLUID_DBG, "Polyphony exceeded, trying to kill a voice");
+ voice = fluid_synth_free_voice_by_kill_LOCAL(synth);
+ }
+
+ if(voice == NULL)
+ {
+ FLUID_LOG(FLUID_WARN, "Failed to allocate a synthesis process. (chan=%d,key=%d)", chan, key);
+ return NULL;
+ }
+
+ ticks = fluid_synth_get_ticks(synth);
+
+ if(synth->verbose)
+ {
+ k = 0;
+
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ if(!_AVAILABLE(synth->voice[i]))
+ {
+ k++;
+ }
+ }
+
+ FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d",
+ chan, key, vel, synth->storeid,
+ (float) ticks / 44100.0f,
+ (fluid_curtime() - synth->start) / 1000.0f,
+ 0.0f,
+ k);
+ }
+
+ channel = synth->channel[chan];
+
+ if(fluid_voice_init(voice, sample, zone_range, channel, key, vel,
+ synth->storeid, ticks, synth->gain) != FLUID_OK)
+ {
+ FLUID_LOG(FLUID_WARN, "Failed to initialize voice");
+ return NULL;
+ }
+
+ /* add the default modulators to the synthesis process. */
+ /* custom_breath2att_modulator is not a default modulator specified in SF
+ it is intended to replace default_vel2att_mod for this channel on demand using
+ API fluid_synth_set_breath_mode() or shell command setbreathmode for this channel.
+ */
+ {
+ int mono = fluid_channel_is_playing_mono(channel);
+ fluid_mod_t *default_mod = synth->default_mod;
+
+ while(default_mod != NULL)
+ {
+ if(
+ /* See if default_mod is the velocity_to_attenuation modulator */
+ fluid_mod_test_identity(default_mod, &default_vel2att_mod) &&
+ // See if a replacement by custom_breath2att_modulator has been demanded
+ // for this channel
+ ((!mono && (channel->mode & FLUID_CHANNEL_BREATH_POLY)) ||
+ (mono && (channel->mode & FLUID_CHANNEL_BREATH_MONO)))
+ )
+ {
+ // Replacement of default_vel2att modulator by custom_breath2att_modulator
+ fluid_voice_add_mod(voice, &custom_breath2att_mod, FLUID_VOICE_DEFAULT);
+ }
+ else
+ {
+ fluid_voice_add_mod(voice, default_mod, FLUID_VOICE_DEFAULT);
+ }
+
+ // Next default modulator to add to the voice
+ default_mod = default_mod->next;
+ }
+ }
+
+ return voice;
}
/* Kill all voices on a given channel, which have the same exclusive class
* generator as new_voice.
*/
static void
-fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t* synth,
- fluid_voice_t* new_voice)
+fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t *synth,
+ fluid_voice_t *new_voice)
{
- int excl_class = _GEN(new_voice,GEN_EXCLUSIVECLASS);
- fluid_voice_t* existing_voice;
- int i;
+ int excl_class = fluid_voice_gen_value(new_voice, GEN_EXCLUSIVECLASS);
+ int i;
- /* Excl. class 0: No exclusive class */
- if (excl_class == 0) return;
+ /* Excl. class 0: No exclusive class */
+ if(excl_class == 0)
+ {
+ return;
+ }
- /* Kill all notes on the same channel with the same exclusive class */
- for (i = 0; i < synth->polyphony; i++) {
- existing_voice = synth->voice[i];
+ /* Kill all notes on the same channel with the same exclusive class */
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ fluid_voice_t *existing_voice = synth->voice[i];
+ int existing_excl_class = fluid_voice_gen_value(existing_voice, GEN_EXCLUSIVECLASS);
- /* If voice is playing, on the same channel, has same exclusive
- * class and is not part of the same noteon event (voice group), then kill it */
+ /* If voice is playing, on the same channel, has same exclusive
+ * class and is not part of the same noteon event (voice group), then kill it */
- if (_PLAYING(existing_voice)
- && existing_voice->chan == new_voice->chan
- && (int)_GEN (existing_voice, GEN_EXCLUSIVECLASS) == excl_class
- && fluid_voice_get_id (existing_voice) != fluid_voice_get_id(new_voice))
- fluid_voice_kill_excl(existing_voice);
- }
+ if(fluid_voice_is_playing(existing_voice)
+ && fluid_voice_get_channel(existing_voice) == fluid_voice_get_channel(new_voice)
+ && existing_excl_class == excl_class
+ && fluid_voice_get_id(existing_voice) != fluid_voice_get_id(new_voice))
+ {
+ fluid_voice_kill_excl(existing_voice);
+ }
+ }
}
/**
@@ -3064,34 +4410,33 @@ fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t* synth,
* This function is called by a SoundFont's preset in response to a noteon
* event. Exclusive classes are processed here.
*
- * NOTE: Should only be called from within synthesis thread, which includes
+ * @note Should only be called from within synthesis thread, which includes
* SoundFont loader preset noteon method.
*/
void
-fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
+fluid_synth_start_voice(fluid_synth_t *synth, fluid_voice_t *voice)
{
- fluid_return_if_fail (synth != NULL);
- fluid_return_if_fail (voice != NULL);
+ fluid_return_if_fail(synth != NULL);
+ fluid_return_if_fail(voice != NULL);
// fluid_return_if_fail (fluid_synth_is_synth_thread (synth));
- fluid_synth_api_enter(synth);
+ fluid_synth_api_enter(synth);
- /* Find the exclusive class of this voice. If set, kill all voices
- * that match the exclusive class and are younger than the first
- * voice process created by this noteon event. */
- fluid_synth_kill_by_exclusive_class_LOCAL(synth, voice);
+ /* Find the exclusive class of this voice. If set, kill all voices
+ * that match the exclusive class and are younger than the first
+ * voice process created by this noteon event. */
+ fluid_synth_kill_by_exclusive_class_LOCAL(synth, voice);
- fluid_voice_start(voice); /* Start the new voice */
- if (synth->eventhandler->is_threadsafe)
+ fluid_voice_start(voice); /* Start the new voice */
fluid_voice_lock_rvoice(voice);
- fluid_rvoice_eventhandler_add_rvoice(synth->eventhandler, voice->rvoice);
- fluid_synth_api_exit(synth);
+ fluid_rvoice_eventhandler_add_rvoice(synth->eventhandler, voice->rvoice);
+ fluid_synth_api_exit(synth);
}
/**
- * Add a SoundFont loader interface.
+ * Add a SoundFont loader to the synth. This function takes ownership of \c loader
+ * and frees it automatically upon \c synth destruction.
* @param synth FluidSynth instance
- * @param loader Loader API structure, used directly and should remain allocated
- * as long as the synth instance is used.
+ * @param loader Loader API structure
*
* SoundFont loaders are used to add custom instrument loading to FluidSynth.
* The caller supplied functions for loading files, allocating presets,
@@ -3099,20 +4444,22 @@ fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
* method even non SoundFont instruments can be synthesized, although limited
* to the SoundFont synthesis model.
*
- * NOTE: Should only be called before any SoundFont files are loaded.
+ * @note Should only be called before any SoundFont files are loaded.
*/
void
-fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader)
+fluid_synth_add_sfloader(fluid_synth_t *synth, fluid_sfloader_t *loader)
{
- gboolean sfont_already_loaded;
+ fluid_return_if_fail(synth != NULL);
+ fluid_return_if_fail(loader != NULL);
+ fluid_synth_api_enter(synth);
- fluid_return_if_fail (synth != NULL);
- fluid_return_if_fail (loader != NULL);
- fluid_synth_api_enter(synth);
- sfont_already_loaded = synth->sfont_info != NULL;
- if (!sfont_already_loaded)
- synth->loaders = fluid_list_prepend(synth->loaders, loader);
- fluid_synth_api_exit(synth);
+ /* Test if sfont is already loaded */
+ if(synth->sfont == NULL)
+ {
+ synth->loaders = fluid_list_prepend(synth->loaders, loader);
+ }
+
+ fluid_synth_api_exit(synth);
}
/**
@@ -3121,301 +4468,287 @@ fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader)
* stack. Presets are searched starting from the SoundFont on the
* top of the stack, working the way down the stack until a preset is found.
*
- * @param synth SoundFont instance
+ * @param synth FluidSynth instance
* @param filename File to load
- * @param reset_presets TRUE to re-assign presets for all MIDI channels
- * @return SoundFont ID on success, FLUID_FAILED on error
+ * @param reset_presets TRUE to re-assign presets for all MIDI channels (equivalent to calling fluid_synth_program_reset())
+ * @return SoundFont ID on success, #FLUID_FAILED on error
*/
int
-fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets)
+fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets)
{
- fluid_sfont_info_t *sfont_info;
- fluid_sfont_t *sfont;
- fluid_list_t *list;
- fluid_sfloader_t *loader;
- unsigned int sfont_id;
-
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (filename != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
-
- /* MT NOTE: Loaders list should not change. */
-
- for (list = synth->loaders; list; list = fluid_list_next(list)) {
- loader = (fluid_sfloader_t*) fluid_list_get(list);
-
- sfont = fluid_sfloader_load(loader, filename);
+ fluid_sfont_t *sfont;
+ fluid_list_t *list;
+ fluid_sfloader_t *loader;
+ int sfont_id;
- if (sfont != NULL) {
- sfont_info = new_fluid_sfont_info (synth, sfont);
-
- if (!sfont_info)
- {
- delete_fluid_sfont (sfont);
- FLUID_API_RETURN(FLUID_FAILED);
- }
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(filename != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- sfont->id = sfont_id = ++synth->sfont_id;
- synth->sfont_info = fluid_list_prepend(synth->sfont_info, sfont_info); /* prepend to list */
- fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
+ sfont_id = synth->sfont_id;
- /* reset the presets for all channels if requested */
- if (reset_presets) fluid_synth_program_reset(synth);
+ if(++sfont_id != FLUID_FAILED)
+ {
+ /* MT NOTE: Loaders list should not change. */
- FLUID_API_RETURN((int)sfont_id);
- }
- }
+ for(list = synth->loaders; list; list = fluid_list_next(list))
+ {
+ loader = (fluid_sfloader_t *) fluid_list_get(list);
- FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename);
- FLUID_API_RETURN(FLUID_FAILED);
-}
+ sfont = fluid_sfloader_load(loader, filename);
-/* Create a new SoundFont info structure, free with FLUID_FREE */
-static fluid_sfont_info_t *
-new_fluid_sfont_info (fluid_synth_t *synth, fluid_sfont_t *sfont)
-{
- fluid_sfont_info_t *sfont_info;
+ if(sfont != NULL)
+ {
+ sfont->refcount++;
+ synth->sfont_id = sfont->id = sfont_id;
- sfont_info = FLUID_NEW (fluid_sfont_info_t);
+ synth->sfont = fluid_list_prepend(synth->sfont, sfont); /* prepend to list */
- if (!sfont_info)
- {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
+ /* reset the presets for all channels if requested */
+ if(reset_presets)
+ {
+ fluid_synth_program_reset(synth);
+ }
- sfont_info->sfont = sfont;
- sfont_info->synth = synth;
- sfont_info->refcount = 1; /* Start with refcount of 1 for owning synth */
- sfont_info->bankofs = 0;
+ FLUID_API_RETURN(sfont_id);
+ }
+ }
+ }
- return (sfont_info);
+ FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename);
+ FLUID_API_RETURN(FLUID_FAILED);
}
/**
* Unload a SoundFont.
- * @param synth SoundFont instance
+ * @param synth FluidSynth instance
* @param id ID of SoundFont to unload
* @param reset_presets TRUE to re-assign presets for all MIDI channels
- * @return FLUID_OK on success, FLUID_FAILED on error
+ * @return #FLUID_OK on success, #FLUID_FAILED on error
*/
int
-fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets)
+fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets)
{
- fluid_sfont_info_t *sfont_info = NULL;
- fluid_list_t *list;
+ fluid_sfont_t *sfont = NULL;
+ fluid_list_t *list;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
-
- /* remove the SoundFont from the list */
- for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
- sfont_info = (fluid_sfont_info_t*) fluid_list_get(list);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- if (fluid_sfont_get_id (sfont_info->sfont) == id)
+ /* remove the SoundFont from the list */
+ for(list = synth->sfont; list; list = fluid_list_next(list))
{
- synth->sfont_info = fluid_list_remove (synth->sfont_info, sfont_info);
- break;
+ sfont = fluid_list_get(list);
+
+ if(fluid_sfont_get_id(sfont) == id)
+ {
+ synth->sfont = fluid_list_remove(synth->sfont, sfont);
+ break;
+ }
}
- }
- if (!list) {
- FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
- FLUID_API_RETURN(FLUID_FAILED);
- }
+ if(!list)
+ {
+ FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
- /* reset the presets for all channels (SoundFont will be freed when there are no more references) */
- if (reset_presets) fluid_synth_program_reset (synth);
- else fluid_synth_update_presets (synth);
+ /* reset the presets for all channels (SoundFont will be freed when there are no more references) */
+ if(reset_presets)
+ {
+ fluid_synth_program_reset(synth);
+ }
+ else
+ {
+ fluid_synth_update_presets(synth);
+ }
- /* -- Remove synth->sfont_info list's reference to SoundFont */
- fluid_synth_sfont_unref (synth, sfont_info->sfont);
+ /* -- Remove synth->sfont list's reference to SoundFont */
+ fluid_synth_sfont_unref(synth, sfont);
- FLUID_API_RETURN(FLUID_OK);
+ FLUID_API_RETURN(FLUID_OK);
}
/* Unref a SoundFont and destroy if no more references */
void
-fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont)
+fluid_synth_sfont_unref(fluid_synth_t *synth, fluid_sfont_t *sfont)
{
- fluid_sfont_info_t *sfont_info;
- int refcount = 0;
-
- sfont_info = fluid_hashtable_lookup (synth->sfont_hash, sfont);
+ fluid_return_if_fail(sfont != NULL); /* Shouldn't happen, programming error if so */
- if (sfont_info)
- {
- sfont_info->refcount--; /* -- Remove the sfont_info list's reference */
- refcount = sfont_info->refcount;
+ sfont->refcount--; /* -- Remove the sfont list's reference */
- if (refcount == 0) /* Remove SoundFont from hash if no more references */
- fluid_hashtable_remove (synth->sfont_hash, sfont_info->sfont);
- }
-
- fluid_return_if_fail (sfont_info != NULL); /* Shouldn't happen, programming error if so */
-
- if (refcount == 0) /* No more references? - Attempt delete */
- {
- if (delete_fluid_sfont (sfont_info->sfont) == 0) /* SoundFont loader can block SoundFont unload */
+ if(sfont->refcount == 0) /* No more references? - Attempt delete */
{
- FLUID_FREE (sfont_info);
- FLUID_LOG (FLUID_DBG, "Unloaded SoundFont");
- } /* spin off a timer thread to unload the sfont later (SoundFont loader blocked unload) */
- else new_fluid_timer (100, fluid_synth_sfunload_callback, sfont_info, TRUE, TRUE, FALSE);
- }
+ if(fluid_sfont_delete_internal(sfont) == 0) /* SoundFont loader can block SoundFont unload */
+ {
+ FLUID_LOG(FLUID_DBG, "Unloaded SoundFont");
+ } /* spin off a timer thread to unload the sfont later (SoundFont loader blocked unload) */
+ else
+ {
+ new_fluid_timer(100, fluid_synth_sfunload_callback, sfont, TRUE, TRUE, FALSE);
+ }
+ }
}
/* Callback to continually attempt to unload a SoundFont,
* only if a SoundFont loader blocked the unload operation */
static int
-fluid_synth_sfunload_callback(void* data, unsigned int msec)
+fluid_synth_sfunload_callback(void *data, unsigned int msec)
{
- fluid_sfont_info_t *sfont_info = (fluid_sfont_info_t *)data;
+ fluid_sfont_t *sfont = data;
- if (delete_fluid_sfont (sfont_info->sfont) == 0)
- {
- FLUID_FREE (sfont_info);
- FLUID_LOG (FLUID_DBG, "Unloaded SoundFont");
- return FALSE;
- }
- else return TRUE;
+ if(fluid_sfont_delete_internal(sfont) == 0)
+ {
+ FLUID_LOG(FLUID_DBG, "Unloaded SoundFont");
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
}
/**
* Reload a SoundFont. The SoundFont retains its ID and index on the SoundFont stack.
- * @param synth SoundFont instance
+ * @param synth FluidSynth instance
* @param id ID of SoundFont to reload
- * @return SoundFont ID on success, FLUID_FAILED on error
+ * @return SoundFont ID on success, #FLUID_FAILED on error
*/
int
-fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id)
-{
- char filename[1024];
- fluid_sfont_info_t *sfont_info, *old_sfont_info;
- fluid_sfont_t* sfont;
- fluid_sfloader_t* loader;
- fluid_list_t *list;
- int index;
-
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
-
- /* Search for SoundFont and get its index */
- for (list = synth->sfont_info, index = 0; list; list = fluid_list_next (list), index++) {
- old_sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
- if (fluid_sfont_get_id (old_sfont_info->sfont) == id) break;
- }
-
- if (!list) {
- FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
- FLUID_API_RETURN(FLUID_FAILED);
- }
+fluid_synth_sfreload(fluid_synth_t *synth, int id)
+{
+ char *filename = NULL;
+ fluid_sfont_t *sfont;
+ fluid_sfloader_t *loader;
+ fluid_list_t *list;
+ int index, ret = FLUID_FAILED;
+
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- /* keep a copy of the SoundFont's filename */
- FLUID_STRCPY (filename, fluid_sfont_get_name (old_sfont_info->sfont));
+ /* Search for SoundFont and get its index */
+ for(list = synth->sfont, index = 0; list; list = fluid_list_next(list), index++)
+ {
+ sfont = fluid_list_get(list);
- if (fluid_synth_sfunload (synth, id, FALSE) != FLUID_OK)
- FLUID_API_RETURN(FLUID_FAILED);
+ if(fluid_sfont_get_id(sfont) == id)
+ {
+ break;
+ }
+ }
- /* MT Note: SoundFont loader list will not change */
+ if(!list)
+ {
+ FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id);
+ goto exit;
+ }
- for (list = synth->loaders; list; list = fluid_list_next(list)) {
- loader = (fluid_sfloader_t*) fluid_list_get(list);
+ /* keep a copy of the SoundFont's filename */
+ filename = FLUID_STRDUP(fluid_sfont_get_name(sfont));
- sfont = fluid_sfloader_load(loader, filename);
+ if(filename == NULL || fluid_synth_sfunload(synth, id, FALSE) != FLUID_OK)
+ {
+ goto exit;
+ }
- if (sfont != NULL) {
- sfont->id = id;
+ /* MT Note: SoundFont loader list will not change */
- sfont_info = new_fluid_sfont_info (synth, sfont);
+ for(list = synth->loaders; list; list = fluid_list_next(list))
+ {
+ loader = (fluid_sfloader_t *) fluid_list_get(list);
- if (!sfont_info)
- {
- delete_fluid_sfont (sfont);
- FLUID_API_RETURN(FLUID_FAILED);
- }
+ sfont = fluid_sfloader_load(loader, filename);
+
+ if(sfont != NULL)
+ {
+ sfont->id = id;
+ sfont->refcount++;
- synth->sfont_info = fluid_list_insert_at(synth->sfont_info, index, sfont_info); /* insert the sfont at the same index */
- fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
+ synth->sfont = fluid_list_insert_at(synth->sfont, index, sfont); /* insert the sfont at the same index */
- /* reset the presets for all channels */
- fluid_synth_update_presets(synth);
- FLUID_API_RETURN(sfont->id);
+ /* reset the presets for all channels */
+ fluid_synth_update_presets(synth);
+ ret = id;
+ goto exit;
+ }
}
- }
- FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename);
- FLUID_API_RETURN(FLUID_FAILED);
+ FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename);
+
+exit:
+ FLUID_FREE(filename);
+ FLUID_API_RETURN(ret);
}
/**
* Add a SoundFont. The SoundFont will be added to the top of the SoundFont stack.
* @param synth FluidSynth instance
* @param sfont SoundFont to add
- * @return New assigned SoundFont ID or FLUID_FAILED on error
+ * @return New assigned SoundFont ID or #FLUID_FAILED on error
*/
int
-fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
+fluid_synth_add_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont)
{
- fluid_sfont_info_t *sfont_info;
- unsigned int sfont_id;
+ int sfont_id;
+
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (sfont != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
-
- sfont_info = new_fluid_sfont_info (synth, sfont);
- if (!sfont_info)
- FLUID_API_RETURN(FLUID_FAILED);
+ sfont_id = synth->sfont_id;
- sfont->id = sfont_id = ++synth->sfont_id;
- synth->sfont_info = fluid_list_prepend (synth->sfont_info, sfont_info); /* prepend to list */
- fluid_hashtable_insert (synth->sfont_hash, sfont, sfont_info); /* Hash sfont->sfont_info */
+ if(++sfont_id != FLUID_FAILED)
+ {
+ synth->sfont_id = sfont->id = sfont_id;
+ synth->sfont = fluid_list_prepend(synth->sfont, sfont); /* prepend to list */
- /* reset the presets for all channels */
- fluid_synth_program_reset (synth);
+ /* reset the presets for all channels */
+ fluid_synth_program_reset(synth);
+ }
- FLUID_API_RETURN(sfont_id);
+ FLUID_API_RETURN(sfont_id);
}
/**
* Remove a SoundFont from the SoundFont stack without deleting it.
* @param synth FluidSynth instance
* @param sfont SoundFont to remove
+ * @return #FLUID_OK if \c sfont successfully removed, #FLUID_FAILED otherwise
*
* SoundFont is not freed and is left as the responsibility of the caller.
*
- * NOTE: The SoundFont should only be freed after there are no presets
+ * @note The SoundFont should only be freed after there are no presets
* referencing it. This can only be ensured by the SoundFont loader and
* therefore this function should not normally be used.
*/
-void
-fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
+int
+fluid_synth_remove_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont)
{
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
+ fluid_sfont_t *sfont_tmp;
+ fluid_list_t *list;
+ int ret = FLUID_FAILED;
- fluid_return_if_fail (synth != NULL);
- fluid_return_if_fail (sfont != NULL);
- fluid_synth_api_enter(synth);
-
- /* remove the SoundFont from the list */
- for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
- sfont_info = (fluid_sfont_info_t*) fluid_list_get(list);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- if (sfont_info->sfont == sfont)
+ /* remove the SoundFont from the list */
+ for(list = synth->sfont; list; list = fluid_list_next(list))
{
- synth->sfont_info = fluid_list_remove (synth->sfont_info, sfont_info);
+ sfont_tmp = fluid_list_get(list);
- /* Remove from SoundFont hash regardless of refcount (SoundFont delete is up to caller) */
- fluid_hashtable_remove (synth->sfont_hash, sfont_info->sfont);
- break;
+ if(sfont_tmp == sfont)
+ {
+ synth->sfont = fluid_list_remove(synth->sfont, sfont_tmp);
+ ret = FLUID_OK;
+ break;
+ }
}
- }
- /* reset the presets for all channels */
- fluid_synth_program_reset (synth);
- fluid_synth_api_exit(synth);
+ /* reset the presets for all channels */
+ fluid_synth_program_reset(synth);
+
+ FLUID_API_RETURN(ret);
}
/**
@@ -3424,14 +4757,14 @@ fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont)
* @return Count of loaded SoundFont files.
*/
int
-fluid_synth_sfcount(fluid_synth_t* synth)
+fluid_synth_sfcount(fluid_synth_t *synth)
{
- int count;
-
- fluid_return_val_if_fail (synth != NULL, 0);
- fluid_synth_api_enter(synth);
- count = fluid_list_size (synth->sfont_info);
- FLUID_API_RETURN(count);
+ int count;
+
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_synth_api_enter(synth);
+ count = fluid_list_size(synth->sfont);
+ FLUID_API_RETURN(count);
}
/**
@@ -3440,20 +4773,25 @@ fluid_synth_sfcount(fluid_synth_t* synth)
* @param num SoundFont index on the stack (starting from 0 for top of stack).
* @return SoundFont instance or NULL if invalid index
*
- * NOTE: Caller should be certain that SoundFont is not deleted (unloaded) for
+ * @note Caller should be certain that SoundFont is not deleted (unloaded) for
* the duration of use of the returned pointer.
*/
fluid_sfont_t *
-fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num)
+fluid_synth_get_sfont(fluid_synth_t *synth, unsigned int num)
{
- fluid_sfont_t *sfont = NULL;
- fluid_list_t *list;
+ fluid_sfont_t *sfont = NULL;
+ fluid_list_t *list;
- fluid_return_val_if_fail (synth != NULL, NULL);
- fluid_synth_api_enter(synth);
- list = fluid_list_nth (synth->sfont_info, num);
- if (list) sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
- FLUID_API_RETURN(sfont);
+ fluid_return_val_if_fail(synth != NULL, NULL);
+ fluid_synth_api_enter(synth);
+ list = fluid_list_nth(synth->sfont, num);
+
+ if(list)
+ {
+ sfont = fluid_list_get(list);
+ }
+
+ FLUID_API_RETURN(sfont);
}
/**
@@ -3462,25 +4800,29 @@ fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num)
* @param id SoundFont ID
* @return SoundFont instance or NULL if invalid ID
*
- * NOTE: Caller should be certain that SoundFont is not deleted (unloaded) for
+ * @note Caller should be certain that SoundFont is not deleted (unloaded) for
* the duration of use of the returned pointer.
*/
fluid_sfont_t *
-fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id)
+fluid_synth_get_sfont_by_id(fluid_synth_t *synth, int id)
{
- fluid_sfont_t* sfont = NULL;
- fluid_list_t* list;
+ fluid_sfont_t *sfont = NULL;
+ fluid_list_t *list;
- fluid_return_val_if_fail (synth != NULL, NULL);
- fluid_synth_api_enter(synth);
+ fluid_return_val_if_fail(synth != NULL, NULL);
+ fluid_synth_api_enter(synth);
- for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
- sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
- if (fluid_sfont_get_id (sfont) == id)
- break;
- }
+ for(list = synth->sfont; list; list = fluid_list_next(list))
+ {
+ sfont = fluid_list_get(list);
- FLUID_API_RETURN(list ? sfont : NULL);
+ if(fluid_sfont_get_id(sfont) == id)
+ {
+ break;
+ }
+ }
+
+ FLUID_API_RETURN(list ? sfont : NULL);
}
/**
@@ -3490,137 +4832,92 @@ fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id)
* @return SoundFont instance or NULL if invalid name
* @since 1.1.0
*
- * NOTE: Caller should be certain that SoundFont is not deleted (unloaded) for
+ * @note Caller should be certain that SoundFont is not deleted (unloaded) for
* the duration of use of the returned pointer.
*/
fluid_sfont_t *
-fluid_synth_get_sfont_by_name(fluid_synth_t* synth, const char *name)
+fluid_synth_get_sfont_by_name(fluid_synth_t *synth, const char *name)
{
- fluid_sfont_t* sfont = NULL;
- fluid_list_t* list;
+ fluid_sfont_t *sfont = NULL;
+ fluid_list_t *list;
- fluid_return_val_if_fail (synth != NULL, NULL);
- fluid_return_val_if_fail (name != NULL, NULL);
- fluid_synth_api_enter(synth);
+ fluid_return_val_if_fail(synth != NULL, NULL);
+ fluid_return_val_if_fail(name != NULL, NULL);
+ fluid_synth_api_enter(synth);
- for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
- sfont = ((fluid_sfont_info_t *)fluid_list_get (list))->sfont;
- if (FLUID_STRCMP(fluid_sfont_get_name(sfont), name) == 0)
- break;
- }
+ for(list = synth->sfont; list; list = fluid_list_next(list))
+ {
+ sfont = fluid_list_get(list);
- FLUID_API_RETURN(list ? sfont : NULL);
+ if(FLUID_STRCMP(fluid_sfont_get_name(sfont), name) == 0)
+ {
+ break;
+ }
+ }
+
+ FLUID_API_RETURN(list ? sfont : NULL);
}
/**
* Get active preset on a MIDI channel.
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @return Preset or NULL if no preset active on channel
- * @deprecated fluid_synth_get_channel_info() should replace most use cases.
+ * @return Preset or NULL if no preset active on \c chan
*
- * NOTE: Should only be called from within synthesis thread, which includes
- * SoundFont loader preset noteon methods. Not thread safe otherwise.
+ * @note Should only be called from within synthesis thread, which includes
+ * SoundFont loader preset noteon methods. Not thread safe otherwise.
*/
fluid_preset_t *
-fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan)
+fluid_synth_get_channel_preset(fluid_synth_t *synth, int chan)
{
- fluid_preset_t* result;
- fluid_channel_t *channel;
- FLUID_API_ENTRY_CHAN(NULL);
+ fluid_preset_t *result;
+ fluid_channel_t *channel;
+ FLUID_API_ENTRY_CHAN(NULL);
- channel = synth->channel[chan];
- result = channel->preset;
- fluid_synth_api_exit(synth);
- return result;
-}
-
-/**
- * Get information on the currently selected preset on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param info Caller supplied structure to fill with preset information
- * @return #FLUID_OK on success, #FLUID_FAILED otherwise
- * @since 1.1.1
- */
-int
-fluid_synth_get_channel_info (fluid_synth_t *synth, int chan,
- fluid_synth_channel_info_t *info)
-{
- fluid_channel_t *channel;
- fluid_preset_t *preset;
- char *name;
-
- if (info)
- {
- info->assigned = FALSE;
- info->name[0] = '\0';
- }
-
- fluid_return_val_if_fail (info != NULL, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- channel = synth->channel[chan];
- preset = channel->preset;
-
- if (preset)
- {
- info->assigned = TRUE;
- name = fluid_preset_get_name (preset);
-
- if (name)
- {
- strncpy (info->name, name, FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE);
- info->name[FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE - 1] = '\0';
- }
- else info->name[0] = '\0';
-
- info->sfont_id = preset->sfont->id;
- info->bank = fluid_preset_get_banknum (preset);
- info->program = fluid_preset_get_num (preset);
- }
- else
- {
- info->assigned = FALSE;
- fluid_channel_get_sfont_bank_prog (channel, &info->sfont_id, &info->bank, &info->program);
- info->name[0] = '\0';
- }
-
- fluid_synth_api_exit(synth);
- return FLUID_OK;
+ channel = synth->channel[chan];
+ result = channel->preset;
+ fluid_synth_api_exit(synth);
+ return result;
}
/**
- * Get list of voices.
+ * Get list of currently playing voices.
* @param synth FluidSynth instance
* @param buf Array to store voices to (NULL terminated if not filled completely)
* @param bufsize Count of indexes in buf
* @param id Voice ID to search for or < 0 to return list of all playing voices
*
- * NOTE: Should only be called from within synthesis thread, which includes
+ * @note Should only be called from within synthesis thread, which includes
* SoundFont loader preset noteon methods. Voices are only guaranteed to remain
* unchanged until next synthesis process iteration.
*/
void
-fluid_synth_get_voicelist(fluid_synth_t* synth, fluid_voice_t* buf[], int bufsize,
+fluid_synth_get_voicelist(fluid_synth_t *synth, fluid_voice_t *buf[], int bufsize,
int id)
{
- int count = 0;
- int i;
+ int count = 0;
+ int i;
- fluid_return_if_fail (synth != NULL);
- fluid_return_if_fail (buf != NULL);
- fluid_synth_api_enter(synth);
+ fluid_return_if_fail(synth != NULL);
+ fluid_return_if_fail(buf != NULL);
+ fluid_synth_api_enter(synth);
- for (i = 0; i < synth->polyphony && count < bufsize; i++) {
- fluid_voice_t* voice = synth->voice[i];
+ for(i = 0; i < synth->polyphony && count < bufsize; i++)
+ {
+ fluid_voice_t *voice = synth->voice[i];
+
+ if(fluid_voice_is_playing(voice) && (id < 0 || (int)voice->id == id))
+ {
+ buf[count++] = voice;
+ }
+ }
- if (_PLAYING(voice) && (id < 0 || (int)voice->id == id))
- buf[count++] = voice;
- }
+ if(count < bufsize)
+ {
+ buf[count] = NULL;
+ }
- if (count < bufsize) buf[count] = NULL;
- fluid_synth_api_exit(synth);
+ fluid_synth_api_exit(synth);
}
/**
@@ -3629,56 +4926,94 @@ fluid_synth_get_voicelist(fluid_synth_t* synth, fluid_voice_t* buf[], int bufsiz
* @param on TRUE to enable reverb, FALSE to disable
*/
void
-fluid_synth_set_reverb_on(fluid_synth_t* synth, int on)
+fluid_synth_set_reverb_on(fluid_synth_t *synth, int on)
{
- fluid_return_if_fail (synth != NULL);
+ fluid_return_if_fail(synth != NULL);
+
+ fluid_synth_api_enter(synth);
- fluid_atomic_int_set (&synth->with_reverb, on != 0);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_reverb_enabled,
- on != 0, 0.0f);
+ synth->with_reverb = (on != 0);
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_reverb_enabled,
+ on != 0, 0.0f);
+ fluid_synth_api_exit(synth);
}
/**
* Activate a reverb preset.
* @param synth FluidSynth instance
* @param num Reverb preset number
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
- * NOTE: Currently private to libfluidsynth.
+ * @note Currently private to libfluidsynth.
*/
int
-fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num)
+fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num)
{
- int i = 0;
- while (revmodel_preset[i].name != NULL) {
- if (i == num) {
- fluid_synth_set_reverb (synth, revmodel_preset[i].roomsize,
- revmodel_preset[i].damp, revmodel_preset[i].width,
- revmodel_preset[i].level);
- return FLUID_OK;
- }
- i++;
- }
- return FLUID_FAILED;
+ fluid_return_val_if_fail(
+ num < FLUID_N_ELEMENTS(revmodel_preset),
+ FLUID_FAILED
+ );
+
+ fluid_synth_set_reverb(synth, revmodel_preset[num].roomsize,
+ revmodel_preset[num].damp, revmodel_preset[num].width,
+ revmodel_preset[num].level);
+ return FLUID_OK;
}
/**
* Set reverb parameters.
* @param synth FluidSynth instance
- * @param roomsize Reverb room size value (0.0-1.2)
+ * @param roomsize Reverb room size value (0.0-1.0)
* @param damping Reverb damping value (0.0-1.0)
* @param width Reverb width value (0.0-100.0)
* @param level Reverb level value (0.0-1.0)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
- * NOTE: Not realtime safe and therefore should not be called from synthesis
+ * @note Not realtime safe and therefore should not be called from synthesis
* context at the risk of stalling audio output.
*/
-void
-fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double damping,
+int
+fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize, double damping,
double width, double level)
{
- fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_ALL,
- roomsize, damping, width, level);
+ return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_ALL,
+ roomsize, damping, width, level);
+}
+
+/**
+ * Set reverb roomsize. See fluid_synth_set_reverb() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize)
+{
+ return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_ROOMSIZE, roomsize, 0, 0, 0);
+}
+
+/**
+ * Set reverb damping. See fluid_synth_set_reverb() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping)
+{
+ return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_DAMPING, 0, damping, 0, 0);
+}
+
+/**
+ * Set reverb width. See fluid_synth_set_reverb() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width)
+{
+ return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_WIDTH, 0, 0, width, 0);
+}
+
+/**
+ * Set reverb level. See fluid_synth_set_reverb() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level)
+{
+ return fluid_synth_set_reverb_full(synth, FLUID_REVMODEL_SET_LEVEL, 0, 0, 0, level);
}
/**
@@ -3689,42 +5024,66 @@ fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double damping,
* @param damping Reverb damping value (0.0-1.0)
* @param width Reverb width value (0.0-100.0)
* @param level Reverb level value (0.0-1.0)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
- * NOTE: Not realtime safe and therefore should not be called from synthesis
+ * @note Not realtime safe and therefore should not be called from synthesis
* context at the risk of stalling audio output.
*/
int
-fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
+fluid_synth_set_reverb_full(fluid_synth_t *synth, int set, double roomsize,
double damping, double width, double level)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
+ int ret;
- if (!(set & FLUID_REVMODEL_SET_ALL))
- set = FLUID_REVMODEL_SET_ALL;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ /* if non of the flags is set, fail */
+ fluid_return_val_if_fail(set & FLUID_REVMODEL_SET_ALL, FLUID_FAILED);
- /* Synth shadow values are set here so that they will be returned if querried */
+ /* Synth shadow values are set here so that they will be returned if querried */
+
+ fluid_synth_api_enter(synth);
+ ret = fluid_synth_set_reverb_full_LOCAL(synth, set, roomsize, damping, width, level);
+ FLUID_API_RETURN(ret);
+}
- fluid_synth_api_enter(synth);
+static int
+fluid_synth_set_reverb_full_LOCAL(fluid_synth_t *synth, int set, double roomsize,
+ double damping, double width, double level)
+{
+ int ret;
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS];
- if (set & FLUID_REVMODEL_SET_ROOMSIZE)
- fluid_atomic_float_set (&synth->reverb_roomsize, roomsize);
+ if(set & FLUID_REVMODEL_SET_ROOMSIZE)
+ {
+ synth->reverb_roomsize = roomsize;
+ }
- if (set & FLUID_REVMODEL_SET_DAMPING)
- fluid_atomic_float_set (&synth->reverb_damping, damping);
+ if(set & FLUID_REVMODEL_SET_DAMPING)
+ {
+ synth->reverb_damping = damping;
+ }
- if (set & FLUID_REVMODEL_SET_WIDTH)
- fluid_atomic_float_set (&synth->reverb_width, width);
+ if(set & FLUID_REVMODEL_SET_WIDTH)
+ {
+ synth->reverb_width = width;
+ }
- if (set & FLUID_REVMODEL_SET_LEVEL)
- fluid_atomic_float_set (&synth->reverb_level, level);
+ if(set & FLUID_REVMODEL_SET_LEVEL)
+ {
+ synth->reverb_level = level;
+ }
- fluid_rvoice_eventhandler_push5(synth->eventhandler,
- fluid_rvoice_mixer_set_reverb_params,
- synth->eventhandler->mixer, set,
- roomsize, damping, width, level, 0.0f);
-
- FLUID_API_RETURN(FLUID_OK);
+ param[0].i = set;
+ param[1].real = roomsize;
+ param[2].real = damping;
+ param[3].real = width;
+ param[4].real = level;
+ /* finally enqueue an rvoice event to the mixer to actual update reverb */
+ ret = fluid_rvoice_eventhandler_push(synth->eventhandler,
+ fluid_rvoice_mixer_set_reverb_params,
+ synth->eventhandler->mixer,
+ param);
+ return ret;
}
/**
@@ -3733,13 +5092,13 @@ fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
* @return Reverb room size (0.0-1.2)
*/
double
-fluid_synth_get_reverb_roomsize(fluid_synth_t* synth)
+fluid_synth_get_reverb_roomsize(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
- result = fluid_atomic_float_get (&synth->reverb_roomsize);
- FLUID_API_RETURN(result);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
+ result = synth->reverb_roomsize;
+ FLUID_API_RETURN(result);
}
/**
@@ -3748,14 +5107,14 @@ fluid_synth_get_reverb_roomsize(fluid_synth_t* synth)
* @return Reverb damping value (0.0-1.0)
*/
double
-fluid_synth_get_reverb_damp(fluid_synth_t* synth)
+fluid_synth_get_reverb_damp(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_float_get (&synth->reverb_damping);
- FLUID_API_RETURN(result);
+ result = synth->reverb_damping;
+ FLUID_API_RETURN(result);
}
/**
@@ -3764,14 +5123,14 @@ fluid_synth_get_reverb_damp(fluid_synth_t* synth)
* @return Reverb level value (0.0-1.0)
*/
double
-fluid_synth_get_reverb_level(fluid_synth_t* synth)
+fluid_synth_get_reverb_level(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_float_get (&synth->reverb_level);
- FLUID_API_RETURN(result);
+ result = synth->reverb_level;
+ FLUID_API_RETURN(result);
}
/**
@@ -3780,14 +5139,14 @@ fluid_synth_get_reverb_level(fluid_synth_t* synth)
* @return Reverb width value (0.0-100.0)
*/
double
-fluid_synth_get_reverb_width(fluid_synth_t* synth)
+fluid_synth_get_reverb_width(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_float_get (&synth->reverb_width);
- FLUID_API_RETURN(result);
+ result = synth->reverb_width;
+ FLUID_API_RETURN(result);
}
/**
@@ -3795,20 +5154,21 @@ fluid_synth_get_reverb_width(fluid_synth_t* synth)
* @param synth FluidSynth instance
* @param on TRUE to enable chorus, FALSE to disable
*/
-void
-fluid_synth_set_chorus_on(fluid_synth_t* synth, int on)
+void
+fluid_synth_set_chorus_on(fluid_synth_t *synth, int on)
{
- fluid_return_if_fail (synth != NULL);
- fluid_synth_api_enter(synth);
+ fluid_return_if_fail(synth != NULL);
+ fluid_synth_api_enter(synth);
- fluid_atomic_int_set (&synth->with_chorus, on != 0);
- fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_chorus_enabled,
- on != 0, 0.0f);
- fluid_synth_api_exit(synth);
+ synth->with_chorus = (on != 0);
+ fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_chorus_enabled,
+ on != 0, 0.0f);
+ fluid_synth_api_exit(synth);
}
/**
- * Set chorus parameters.
+ * Set chorus parameters. It should be turned on with fluid_synth_set_chorus_on().
+ * Keep in mind, that the needed CPU time is proportional to 'nr'.
* @param synth FluidSynth instance
* @param nr Chorus voice count (0-99, CPU time consumption proportional to
* this value)
@@ -3817,13 +5177,58 @@ fluid_synth_set_chorus_on(fluid_synth_t* synth, int on)
* @param depth_ms Chorus depth (max value depends on synth sample rate,
* 0.0-21.0 is safe for sample rate values up to 96KHz)
* @param type Chorus waveform type (#fluid_chorus_mod)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
-void
-fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
- double speed, double depth_ms, int type)
+int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level,
+ double speed, double depth_ms, int type)
{
- fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_ALL, nr, level, speed,
- depth_ms, type);
+ return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_ALL, nr, level, speed,
+ depth_ms, type);
+}
+
+/**
+ * Set the chorus voice count. See fluid_synth_set_chorus() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr)
+{
+ return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_NR, nr, 0, 0, 0, 0);
+}
+
+/**
+ * Set the chorus level. See fluid_synth_set_chorus() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level)
+{
+ return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_LEVEL, 0, level, 0, 0, 0);
+}
+
+/**
+ * Set the chorus speed. See fluid_synth_set_chorus() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed)
+{
+ return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_SPEED, 0, 0, speed, 0, 0);
+}
+
+/**
+ * Set the chorus depth. See fluid_synth_set_chorus() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms)
+{
+ return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_DEPTH, 0, 0, 0, depth_ms, 0);
+}
+
+/**
+ * Set the chorus type. See fluid_synth_set_chorus() for further info.
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ */
+int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type)
+{
+ return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_TYPE, 0, 0, 0, 0, type);
}
/**
@@ -3837,40 +5242,70 @@ fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
* @param depth_ms Chorus depth (max value depends on synth sample rate,
* 0.0-21.0 is safe for sample rate values up to 96KHz)
* @param type Chorus waveform type (#fluid_chorus_mod)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
+fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level,
double speed, double depth_ms, int type)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
+ int ret;
- if (!(set & FLUID_CHORUS_SET_ALL))
- set = FLUID_CHORUS_SET_ALL;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ /* if non of the flags is set, fail */
+ fluid_return_val_if_fail(set & FLUID_CHORUS_SET_ALL, FLUID_FAILED);
- /* Synth shadow values are set here so that they will be returned if queried */
- fluid_synth_api_enter(synth);
+ /* Synth shadow values are set here so that they will be returned if queried */
+ fluid_synth_api_enter(synth);
- if (set & FLUID_CHORUS_SET_NR)
- fluid_atomic_int_set (&synth->chorus_nr, nr);
+ ret = fluid_synth_set_chorus_full_LOCAL(synth, set, nr, level, speed, depth_ms, type);
- if (set & FLUID_CHORUS_SET_LEVEL)
- fluid_atomic_float_set (&synth->chorus_level, level);
+ FLUID_API_RETURN(ret);
+}
- if (set & FLUID_CHORUS_SET_SPEED)
- fluid_atomic_float_set (&synth->chorus_speed, speed);
+static int
+fluid_synth_set_chorus_full_LOCAL(fluid_synth_t *synth, int set, int nr, double level,
+ double speed, double depth_ms, int type)
+{
+ int ret;
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS];
- if (set & FLUID_CHORUS_SET_DEPTH)
- fluid_atomic_float_set (&synth->chorus_depth, depth_ms);
+ if(set & FLUID_CHORUS_SET_NR)
+ {
+ synth->chorus_nr = nr;
+ }
+
+ if(set & FLUID_CHORUS_SET_LEVEL)
+ {
+ synth->chorus_level = level;
+ }
- if (set & FLUID_CHORUS_SET_TYPE)
- fluid_atomic_int_set (&synth->chorus_type, type);
-
- fluid_rvoice_eventhandler_push5(synth->eventhandler,
- fluid_rvoice_mixer_set_chorus_params,
- synth->eventhandler->mixer, set,
- nr, level, speed, depth_ms, type);
+ if(set & FLUID_CHORUS_SET_SPEED)
+ {
+ synth->chorus_speed = speed;
+ }
- FLUID_API_RETURN(FLUID_OK);
+ if(set & FLUID_CHORUS_SET_DEPTH)
+ {
+ synth->chorus_depth = depth_ms;
+ }
+
+ if(set & FLUID_CHORUS_SET_TYPE)
+ {
+ synth->chorus_type = type;
+ }
+
+ param[0].i = set;
+ param[1].i = nr;
+ param[2].real = level;
+ param[3].real = speed;
+ param[4].real = depth_ms;
+ param[5].i = type;
+ ret = fluid_rvoice_eventhandler_push(synth->eventhandler,
+ fluid_rvoice_mixer_set_chorus_params,
+ synth->eventhandler->mixer,
+ param);
+
+ return (ret);
}
/**
@@ -3879,14 +5314,14 @@ fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
* @return Chorus voice count (0-99)
*/
int
-fluid_synth_get_chorus_nr(fluid_synth_t* synth)
+fluid_synth_get_chorus_nr(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_int_get (&synth->chorus_nr);
- FLUID_API_RETURN(result);
+ result = synth->chorus_nr;
+ FLUID_API_RETURN(result);
}
/**
@@ -3895,14 +5330,14 @@ fluid_synth_get_chorus_nr(fluid_synth_t* synth)
* @return Chorus level value (0.0-10.0)
*/
double
-fluid_synth_get_chorus_level(fluid_synth_t* synth)
+fluid_synth_get_chorus_level(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_float_get (&synth->chorus_level);
- FLUID_API_RETURN(result);
+ result = synth->chorus_level;
+ FLUID_API_RETURN(result);
}
/**
@@ -3911,14 +5346,14 @@ fluid_synth_get_chorus_level(fluid_synth_t* synth)
* @return Chorus speed in Hz (0.29-5.0)
*/
double
-fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth)
+fluid_synth_get_chorus_speed(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_float_get (&synth->chorus_speed);
- FLUID_API_RETURN(result);
+ result = synth->chorus_speed;
+ FLUID_API_RETURN(result);
}
/**
@@ -3927,14 +5362,14 @@ fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth)
* @return Chorus depth
*/
double
-fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth)
+fluid_synth_get_chorus_depth(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_float_get (&synth->chorus_depth);
- FLUID_API_RETURN(result);
+ result = synth->chorus_depth;
+ FLUID_API_RETURN(result);
}
/**
@@ -3943,14 +5378,14 @@ fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth)
* @return Chorus waveform type (#fluid_chorus_mod)
*/
int
-fluid_synth_get_chorus_type(fluid_synth_t* synth)
+fluid_synth_get_chorus_type(fluid_synth_t *synth)
{
- double result;
- fluid_return_val_if_fail (synth != NULL, 0.0);
- fluid_synth_api_enter(synth);
+ double result;
+ fluid_return_val_if_fail(synth != NULL, 0.0);
+ fluid_synth_api_enter(synth);
- result = fluid_atomic_int_get (&synth->chorus_type);
- FLUID_API_RETURN(result);
+ result = synth->chorus_type;
+ FLUID_API_RETURN(result);
}
/*
@@ -3962,28 +5397,42 @@ fluid_synth_get_chorus_type(fluid_synth_t* synth)
* several voice processes, for example a stereo sample. Don't
* release those...
*/
-static void
-fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth, int chan,
- int key)
+void
+fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan,
+ int key)
{
- int i;
- fluid_voice_t* voice;
+ int i;
+ fluid_voice_t *voice;
- synth->storeid = synth->noteid++;
+ /* storeid is a parameter for fluid_voice_init() */
+ synth->storeid = synth->noteid++;
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
- if (_PLAYING(voice)
- && (voice->chan == chan)
- && (voice->key == key)
- && (fluid_voice_get_id(voice) != synth->noteid)) {
- /* Id of voices that was sustained by sostenuto */
- if(_HELD_BY_SOSTENUTO(voice))
- synth->storeid = voice->id;
- /* Force the voice into release stage (pedaling is ignored) */
- fluid_voice_release(voice);
+ /* for "monophonic playing" key is the previous sustained note
+ if it exists (0 to 127) or INVALID_NOTE otherwise */
+ if(key == INVALID_NOTE)
+ {
+ return;
+ }
+
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
+
+ if(fluid_voice_is_playing(voice)
+ && (fluid_voice_get_channel(voice) == chan)
+ && (fluid_voice_get_key(voice) == key)
+ && (fluid_voice_get_id(voice) != synth->noteid))
+ {
+ /* Id of voices that was sustained by sostenuto */
+ if(fluid_voice_is_sostenuto(voice))
+ {
+ synth->storeid = fluid_voice_get_id(voice);
+ }
+
+ /* Force the voice into release stage (pedaling is ignored) */
+ fluid_voice_release(voice);
+ }
}
- }
}
/**
@@ -3991,29 +5440,36 @@ fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth, int chan,
* @param synth FluidSynth instance
* @param chan MIDI channel to set interpolation method on or -1 for all channels
* @param interp_method Interpolation method (#fluid_interp)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method)
+fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method)
{
- int i;
-
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- if (chan < -1 || chan >= synth->midi_channels)
- FLUID_API_RETURN(FLUID_FAILED);
+ int i;
- if (synth->channel[0] == NULL) {
- FLUID_LOG (FLUID_ERR, "Channels don't exist (yet)!");
- FLUID_API_RETURN(FLUID_FAILED);
- }
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- for (i = 0; i < synth->midi_channels; i++) {
- if (chan < 0 || fluid_channel_get_num(synth->channel[i]) == chan)
- fluid_channel_set_interp_method(synth->channel[i], interp_method);
- }
+ if(chan < -1 || chan >= synth->midi_channels)
+ {
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
+
+ if(synth->channel[0] == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Channels don't exist (yet)!");
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
- FLUID_API_RETURN(FLUID_OK);
+ for(i = 0; i < synth->midi_channels; i++)
+ {
+ if(chan < 0 || fluid_channel_get_num(synth->channel[i]) == chan)
+ {
+ fluid_channel_set_interp_method(synth->channel[i], interp_method);
+ }
+ }
+
+ FLUID_API_RETURN(FLUID_OK);
};
/**
@@ -4022,14 +5478,14 @@ fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method)
* @return Count of MIDI channels
*/
int
-fluid_synth_count_midi_channels(fluid_synth_t* synth)
+fluid_synth_count_midi_channels(fluid_synth_t *synth)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, 0);
- fluid_synth_api_enter(synth);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_synth_api_enter(synth);
- result = synth->midi_channels;
- FLUID_API_RETURN(result);
+ result = synth->midi_channels;
+ FLUID_API_RETURN(result);
}
/**
@@ -4038,14 +5494,14 @@ fluid_synth_count_midi_channels(fluid_synth_t* synth)
* @return Count of audio channel stereo pairs (1 = 2 channels, 2 = 4, etc)
*/
int
-fluid_synth_count_audio_channels(fluid_synth_t* synth)
+fluid_synth_count_audio_channels(fluid_synth_t *synth)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, 0);
- fluid_synth_api_enter(synth);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_synth_api_enter(synth);
- result = synth->audio_channels;
- FLUID_API_RETURN(result);
+ result = synth->audio_channels;
+ FLUID_API_RETURN(result);
}
/**
@@ -4056,14 +5512,14 @@ fluid_synth_count_audio_channels(fluid_synth_t* synth)
* @return Count of audio group stereo pairs (1 = 2 channels, 2 = 4, etc)
*/
int
-fluid_synth_count_audio_groups(fluid_synth_t* synth)
+fluid_synth_count_audio_groups(fluid_synth_t *synth)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, 0);
- fluid_synth_api_enter(synth);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_synth_api_enter(synth);
- result = synth->audio_groups;
- FLUID_API_RETURN(result);
+ result = synth->audio_groups;
+ FLUID_API_RETURN(result);
}
/**
@@ -4072,14 +5528,30 @@ fluid_synth_count_audio_groups(fluid_synth_t* synth)
* @return Count of allocated effects channels
*/
int
-fluid_synth_count_effects_channels(fluid_synth_t* synth)
+fluid_synth_count_effects_channels(fluid_synth_t *synth)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, 0);
- fluid_synth_api_enter(synth);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_synth_api_enter(synth);
- result = synth->effects_channels;
- FLUID_API_RETURN(result);
+ result = synth->effects_channels;
+ FLUID_API_RETURN(result);
+}
+
+/**
+ * Get the total number of allocated effects units.
+ * @param synth FluidSynth instance
+ * @return Count of allocated effects units
+ */
+int
+fluid_synth_count_effects_groups(fluid_synth_t *synth)
+{
+ int result;
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_synth_api_enter(synth);
+
+ result = synth->effects_groups;
+ FLUID_API_RETURN(result);
}
/**
@@ -4088,138 +5560,139 @@ fluid_synth_count_effects_channels(fluid_synth_t* synth)
* @return Estimated CPU load value in percent (0-100)
*/
double
-fluid_synth_get_cpu_load(fluid_synth_t* synth)
+fluid_synth_get_cpu_load(fluid_synth_t *synth)
{
- fluid_return_val_if_fail (synth != NULL, 0);
- return fluid_atomic_float_get (&synth->cpu_load);
+ fluid_return_val_if_fail(synth != NULL, 0);
+ return fluid_atomic_float_get(&synth->cpu_load);
}
/* Get tuning for a given bank:program */
static fluid_tuning_t *
-fluid_synth_get_tuning(fluid_synth_t* synth, int bank, int prog)
+fluid_synth_get_tuning(fluid_synth_t *synth, int bank, int prog)
{
- if ((synth->tuning == NULL) ||
- (synth->tuning[bank] == NULL) ||
- (synth->tuning[bank][prog] == NULL))
- return NULL;
+ if((synth->tuning == NULL) ||
+ (synth->tuning[bank] == NULL) ||
+ (synth->tuning[bank][prog] == NULL))
+ {
+ return NULL;
+ }
- return synth->tuning[bank][prog];
+ return synth->tuning[bank][prog];
}
/* Replace tuning on a given bank:program (need not already exist).
* Synth mutex should already be locked by caller. */
static int
-fluid_synth_replace_tuning_LOCK (fluid_synth_t* synth, fluid_tuning_t *tuning,
- int bank, int prog, int apply)
+fluid_synth_replace_tuning_LOCK(fluid_synth_t *synth, fluid_tuning_t *tuning,
+ int bank, int prog, int apply)
{
- fluid_tuning_t *old_tuning;
-// fluid_event_queue_t *queue;
-// fluid_event_queue_elem_t *event;
+ fluid_tuning_t *old_tuning;
+
+ if(synth->tuning == NULL)
+ {
+ synth->tuning = FLUID_ARRAY(fluid_tuning_t **, 128);
+
+ if(synth->tuning == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "Out of memory");
+ return FLUID_FAILED;
+ }
- if (synth->tuning == NULL) {
- synth->tuning = FLUID_ARRAY(fluid_tuning_t**, 128);
- if (synth->tuning == NULL) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- return FLUID_FAILED;
+ FLUID_MEMSET(synth->tuning, 0, 128 * sizeof(fluid_tuning_t **));
}
- FLUID_MEMSET(synth->tuning, 0, 128 * sizeof(fluid_tuning_t**));
- }
- if (synth->tuning[bank] == NULL) {
- synth->tuning[bank] = FLUID_ARRAY(fluid_tuning_t*, 128);
- if (synth->tuning[bank] == NULL) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- return FLUID_FAILED;
+ if(synth->tuning[bank] == NULL)
+ {
+ synth->tuning[bank] = FLUID_ARRAY(fluid_tuning_t *, 128);
+
+ if(synth->tuning[bank] == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "Out of memory");
+ return FLUID_FAILED;
+ }
+
+ FLUID_MEMSET(synth->tuning[bank], 0, 128 * sizeof(fluid_tuning_t *));
}
- FLUID_MEMSET(synth->tuning[bank], 0, 128 * sizeof(fluid_tuning_t*));
- }
- old_tuning = synth->tuning[bank][prog];
- synth->tuning[bank][prog] = tuning;
+ old_tuning = synth->tuning[bank][prog];
+ synth->tuning[bank][prog] = tuning;
- if (old_tuning) {
- if (!fluid_tuning_unref (old_tuning, 1)) /* -- unref old tuning */
- { /* Replace old tuning if present */
- fluid_synth_replace_tuning_LOCAL (synth, old_tuning, tuning, apply, FALSE);
+ if(old_tuning)
+ {
+ if(!fluid_tuning_unref(old_tuning, 1)) /* -- unref old tuning */
+ {
+ /* Replace old tuning if present */
+ fluid_synth_replace_tuning_LOCAL(synth, old_tuning, tuning, apply, FALSE);
+ }
}
- }
- return FLUID_OK;
+ return FLUID_OK;
}
/* Replace a tuning with a new one in all MIDI channels. new_tuning can be
* NULL, in which case channels are reset to default equal tempered scale. */
static void
-fluid_synth_replace_tuning_LOCAL (fluid_synth_t *synth, fluid_tuning_t *old_tuning,
- fluid_tuning_t *new_tuning, int apply, int unref_new)
+fluid_synth_replace_tuning_LOCAL(fluid_synth_t *synth, fluid_tuning_t *old_tuning,
+ fluid_tuning_t *new_tuning, int apply, int unref_new)
{
-// fluid_event_queue_elem_t *event;
- fluid_channel_t *channel;
- int old_tuning_unref = 0;
- int i;
-
- for (i = 0; i < synth->midi_channels; i++)
- {
- channel = synth->channel[i];
+ fluid_channel_t *channel;
+ int old_tuning_unref = 0;
+ int i;
- if (fluid_channel_get_tuning (channel) == old_tuning)
+ for(i = 0; i < synth->midi_channels; i++)
{
- old_tuning_unref++;
- if (new_tuning) fluid_tuning_ref (new_tuning); /* ++ ref new tuning for channel */
- fluid_channel_set_tuning (channel, new_tuning);
+ channel = synth->channel[i];
+
+ if(fluid_channel_get_tuning(channel) == old_tuning)
+ {
+ old_tuning_unref++;
+
+ if(new_tuning)
+ {
+ fluid_tuning_ref(new_tuning); /* ++ ref new tuning for channel */
+ }
+
+ fluid_channel_set_tuning(channel, new_tuning);
- if (apply) fluid_synth_update_voice_tuning_LOCAL (synth, channel);
+ if(apply)
+ {
+ fluid_synth_update_voice_tuning_LOCAL(synth, channel);
+ }
+ }
}
- }
- /* Send unref old tuning event if any unrefs */
- if (old_tuning && old_tuning_unref)
- fluid_tuning_unref (old_tuning, old_tuning_unref);
- if (!unref_new || !new_tuning) return;
+ /* Send unref old tuning event if any unrefs */
+ if(old_tuning && old_tuning_unref)
+ {
+ fluid_tuning_unref(old_tuning, old_tuning_unref);
+ }
- fluid_tuning_unref (new_tuning, 1);
+ if(!unref_new || !new_tuning)
+ {
+ return;
+ }
+
+ fluid_tuning_unref(new_tuning, 1);
}
/* Update voice tunings in realtime */
static void
-fluid_synth_update_voice_tuning_LOCAL (fluid_synth_t *synth, fluid_channel_t *channel)
+fluid_synth_update_voice_tuning_LOCAL(fluid_synth_t *synth, fluid_channel_t *channel)
{
- fluid_voice_t *voice;
- int i;
-
- for (i = 0; i < synth->polyphony; i++)
- {
- voice = synth->voice[i];
+ fluid_voice_t *voice;
+ int i;
- if (_ON (voice) && (voice->channel == channel))
+ for(i = 0; i < synth->polyphony; i++)
{
- fluid_voice_calculate_gen_pitch (voice);
- fluid_voice_update_param (voice, GEN_PITCH);
- }
- }
-}
+ voice = synth->voice[i];
-/**
- * Set the tuning of the entire MIDI note scale.
- * @param synth FluidSynth instance
- * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
- * @param prog Tuning preset number (0-127), not related to MIDI instrument program
- * @param name Label name for this tuning
- * @param pitch Array of pitch values (length of 128, each value is number of
- * cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc).
- * Pass NULL to create a well-tempered (normal) scale.
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- *
- * NOTE: Tuning is not applied in realtime to existing notes of the replaced
- * tuning (if any), use fluid_synth_activate_key_tuning() instead to specify
- * this behavior.
- */
-int
-fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch)
-{
- return fluid_synth_activate_key_tuning (synth, bank, prog, name, pitch, FALSE);
+ if(fluid_voice_is_on(voice) && (voice->channel == channel))
+ {
+ fluid_voice_calculate_gen_pitch(voice);
+ fluid_voice_update_param(voice, GEN_PITCH);
+ }
+ }
}
/**
@@ -4230,58 +5703,48 @@ fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
* @param name Label name for this tuning
* @param pitch Array of pitch values (length of 128, each value is number of
* cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc).
- * Pass NULL to create a well-tempered (normal) scale.
+ * Pass NULL to create a equal tempered (normal) scale.
* @param apply TRUE to apply new tuning in realtime to existing notes which
* are using the replaced tuning (if any), FALSE otherwise
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.0
*/
int
-fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch, int apply)
+fluid_synth_activate_key_tuning(fluid_synth_t *synth, int bank, int prog,
+ const char *name, const double *pitch, int apply)
{
- fluid_tuning_t* tuning;
- int retval = FLUID_OK;
+ fluid_tuning_t *tuning;
+ int retval = FLUID_OK;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
- fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
+ fluid_synth_api_enter(synth);
- tuning = new_fluid_tuning (name, bank, prog);
+ tuning = new_fluid_tuning(name, bank, prog);
- if (tuning)
- {
- if (pitch) fluid_tuning_set_all (tuning, pitch);
- retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, apply);
- if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
- }
- else retval = FLUID_FAILED;
- FLUID_API_RETURN(retval);
-}
+ if(tuning)
+ {
+ if(pitch)
+ {
+ fluid_tuning_set_all(tuning, pitch);
+ }
-/**
- * Apply an octave tuning to every octave in the MIDI note scale.
- * @param synth FluidSynth instance
- * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
- * @param prog Tuning preset number (0-127), not related to MIDI instrument program
- * @param name Label name for this tuning
- * @param pitch Array of pitch values (length of 12 for each note of an octave
- * starting at note C, values are number of offset cents to add to the normal
- * tuning amount)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- *
- * NOTE: Tuning is not applied in realtime to existing notes of the replaced
- * tuning (if any), use fluid_synth_activate_octave_tuning() instead to specify
- * this behavior.
- */
-int
-fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch)
-{
- return fluid_synth_activate_octave_tuning (synth, bank, prog, name, pitch, FALSE);
+ retval = fluid_synth_replace_tuning_LOCK(synth, tuning, bank, prog, apply);
+
+ if(retval == FLUID_FAILED)
+ {
+ fluid_tuning_unref(tuning, 1);
+ }
+ }
+ else
+ {
+ retval = FLUID_FAILED;
+ }
+
+ FLUID_API_RETURN(retval);
}
/**
@@ -4295,34 +5758,41 @@ fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
* tuning amount)
* @param apply TRUE to apply new tuning in realtime to existing notes which
* are using the replaced tuning (if any), FALSE otherwise
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.0
*/
int
-fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
- const char* name, const double* pitch, int apply)
+fluid_synth_activate_octave_tuning(fluid_synth_t *synth, int bank, int prog,
+ const char *name, const double *pitch, int apply)
{
- fluid_tuning_t* tuning;
- int retval = FLUID_OK;
+ fluid_tuning_t *tuning;
+ int retval = FLUID_OK;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
- fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(pitch != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- tuning = new_fluid_tuning (name, bank, prog);
+ fluid_synth_api_enter(synth);
+ tuning = new_fluid_tuning(name, bank, prog);
+
+ if(tuning)
+ {
+ fluid_tuning_set_octave(tuning, pitch);
+ retval = fluid_synth_replace_tuning_LOCK(synth, tuning, bank, prog, apply);
- if (tuning)
- {
- fluid_tuning_set_octave (tuning, pitch);
- retval = fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, apply);
- if (retval == FLUID_FAILED) fluid_tuning_unref (tuning, 1);
- }
- else retval = FLUID_FAILED;
+ if(retval == FLUID_FAILED)
+ {
+ fluid_tuning_unref(tuning, 1);
+ }
+ }
+ else
+ {
+ retval = FLUID_FAILED;
+ }
- FLUID_API_RETURN(retval);
+ FLUID_API_RETURN(retval);
}
/**
@@ -4336,68 +5806,60 @@ fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
* cents from MIDI note 0)
* @param apply TRUE to apply tuning change in realtime to existing notes using
* the specified tuning, FALSE otherwise
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
- * NOTE: Prior to version 1.1.0 it was an error to specify a tuning that didn't
- * already exist. Starting with 1.1.0, the default equal tempered scale will be
+ * @note Prior to version 1.1.0 it was an error to specify a tuning that didn't
+ * already exist. Starting with 1.1.0, the default equal tempered scale will be
* used as a basis, if no tuning exists for the given bank and prog.
*/
int
-fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
- int len, const int *key, const double* pitch, int apply)
+fluid_synth_tune_notes(fluid_synth_t *synth, int bank, int prog,
+ int len, const int *key, const double *pitch, int apply)
{
- fluid_tuning_t* old_tuning, *new_tuning;
- int retval = FLUID_OK;
- int i;
+ fluid_tuning_t *old_tuning, *new_tuning;
+ int retval = FLUID_OK;
+ int i;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
- fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
- fluid_return_val_if_fail (len > 0, FLUID_FAILED);
- fluid_return_val_if_fail (key != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (pitch != NULL, FLUID_FAILED);
-
- fluid_synth_api_enter(synth);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(len > 0, FLUID_FAILED);
+ fluid_return_val_if_fail(key != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(pitch != NULL, FLUID_FAILED);
- old_tuning = fluid_synth_get_tuning (synth, bank, prog);
+ fluid_synth_api_enter(synth);
- if (old_tuning)
- new_tuning = fluid_tuning_duplicate (old_tuning);
- else new_tuning = new_fluid_tuning ("Unnamed", bank, prog);
+ old_tuning = fluid_synth_get_tuning(synth, bank, prog);
- if (new_tuning)
- {
- for (i = 0; i < len; i++)
- fluid_tuning_set_pitch (new_tuning, key[i], pitch[i]);
+ if(old_tuning)
+ {
+ new_tuning = fluid_tuning_duplicate(old_tuning);
+ }
+ else
+ {
+ new_tuning = new_fluid_tuning("Unnamed", bank, prog);
+ }
- retval = fluid_synth_replace_tuning_LOCK (synth, new_tuning, bank, prog, apply);
- if (retval == FLUID_FAILED) fluid_tuning_unref (new_tuning, 1);
- }
- else retval = FLUID_FAILED;
+ if(new_tuning)
+ {
+ for(i = 0; i < len; i++)
+ {
+ fluid_tuning_set_pitch(new_tuning, key[i], pitch[i]);
+ }
- FLUID_API_RETURN(retval);
-}
+ retval = fluid_synth_replace_tuning_LOCK(synth, new_tuning, bank, prog, apply);
-/**
- * Select a tuning scale on a MIDI channel.
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param bank Tuning bank number (0-127), not related to MIDI instrument bank
- * @param prog Tuning preset number (0-127), not related to MIDI instrument program
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- *
- * NOTE: This function does NOT activate tuning in realtime, use
- * fluid_synth_activate_tuning() instead to specify whether tuning change
- * should cause existing notes to update.
- *
- * NOTE: Prior to version 1.1.0 it was an error to select a tuning that didn't
- * already exist. Starting with 1.1.0, a default equal tempered scale will be
- * created, if no tuning exists for the given bank and prog.
- */
-int
-fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
-{
- return fluid_synth_activate_tuning (synth, chan, bank, prog, FALSE);
+ if(retval == FLUID_FAILED)
+ {
+ fluid_tuning_unref(new_tuning, 1);
+ }
+ }
+ else
+ {
+ retval = FLUID_FAILED;
+ }
+
+ FLUID_API_RETURN(retval);
}
/**
@@ -4407,90 +5869,84 @@ fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog)
* @param bank Tuning bank number (0-127), not related to MIDI instrument bank
* @param prog Tuning preset number (0-127), not related to MIDI instrument program
* @param apply TRUE to apply tuning change to active notes, FALSE otherwise
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.0
*
- * NOTE: A default equal tempered scale will be created, if no tuning exists
+ * @note A default equal tempered scale will be created, if no tuning exists
* on the given bank and prog.
*/
int
-fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
+fluid_synth_activate_tuning(fluid_synth_t *synth, int chan, int bank, int prog,
int apply)
{
- //fluid_event_queue_elem_t *event;
- //fluid_event_queue_t *queue;
- fluid_tuning_t* tuning;
- int retval = FLUID_OK;
+ fluid_tuning_t *tuning;
+ int retval = FLUID_OK;
- //fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- //fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
- fluid_return_val_if_fail (bank >= 0 && bank < 128, FLUID_FAILED);
- fluid_return_val_if_fail (prog >= 0 && prog < 128, FLUID_FAILED);
+ //fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
+ //fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED);
+ fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED);
+ fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- tuning = fluid_synth_get_tuning (synth, bank, prog);
+ tuning = fluid_synth_get_tuning(synth, bank, prog);
- /* If no tuning exists, create a new default tuning. We do this, so that
- * it can be replaced later, if any changes are made. */
- if (!tuning)
- {
- tuning = new_fluid_tuning ("Unnamed", bank, prog);
- if (tuning) fluid_synth_replace_tuning_LOCK (synth, tuning, bank, prog, FALSE);
- }
+ /* If no tuning exists, create a new default tuning. We do this, so that
+ * it can be replaced later, if any changes are made. */
+ if(!tuning)
+ {
+ tuning = new_fluid_tuning("Unnamed", bank, prog);
- if (tuning) fluid_tuning_ref (tuning); /* ++ ref for outside of lock */
+ if(tuning)
+ {
+ fluid_synth_replace_tuning_LOCK(synth, tuning, bank, prog, FALSE);
+ }
+ }
- if (!tuning)
- FLUID_API_RETURN(FLUID_FAILED);
+ if(tuning)
+ {
+ fluid_tuning_ref(tuning); /* ++ ref for outside of lock */
+ }
+
+ if(!tuning)
+ {
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
- fluid_tuning_ref (tuning); /* ++ ref new tuning for following function */
- retval = fluid_synth_set_tuning_LOCAL (synth, chan, tuning, apply);
+ fluid_tuning_ref(tuning); /* ++ ref new tuning for following function */
+ retval = fluid_synth_set_tuning_LOCAL(synth, chan, tuning, apply);
- fluid_tuning_unref (tuning, 1); /* -- unref for outside of lock */
+ fluid_tuning_unref(tuning, 1); /* -- unref for outside of lock */
- FLUID_API_RETURN(retval);
+ FLUID_API_RETURN(retval);
}
/* Local synthesis thread set tuning function (takes over tuning reference) */
static int
-fluid_synth_set_tuning_LOCAL (fluid_synth_t *synth, int chan,
- fluid_tuning_t *tuning, int apply)
+fluid_synth_set_tuning_LOCAL(fluid_synth_t *synth, int chan,
+ fluid_tuning_t *tuning, int apply)
{
- fluid_tuning_t *old_tuning;
- fluid_channel_t *channel;
-
- channel = synth->channel[chan];
+ fluid_tuning_t *old_tuning;
+ fluid_channel_t *channel;
- old_tuning = fluid_channel_get_tuning (channel);
- fluid_channel_set_tuning (channel, tuning); /* !! Takes over callers reference */
+ channel = synth->channel[chan];
- if (apply) fluid_synth_update_voice_tuning_LOCAL (synth, channel);
+ old_tuning = fluid_channel_get_tuning(channel);
+ fluid_channel_set_tuning(channel, tuning); /* !! Takes over callers reference */
- /* Send unref old tuning event */
- if (old_tuning)
- {
- fluid_tuning_unref (old_tuning, 1);
- }
+ if(apply)
+ {
+ fluid_synth_update_voice_tuning_LOCAL(synth, channel);
+ }
+ /* Send unref old tuning event */
+ if(old_tuning)
+ {
+ fluid_tuning_unref(old_tuning, 1);
+ }
- return FLUID_OK;
-}
-/**
- * Clear tuning scale on a MIDI channel (set it to the default well-tempered scale).
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- *
- * NOTE: This function does NOT activate tuning change in realtime, use
- * fluid_synth_deactivate_tuning() instead to specify whether tuning change
- * should cause existing notes to update.
- */
-int
-fluid_synth_reset_tuning(fluid_synth_t* synth, int chan)
-{
- return fluid_synth_deactivate_tuning (synth, chan, FALSE);
+ return FLUID_OK;
}
/**
@@ -4498,19 +5954,19 @@ fluid_synth_reset_tuning(fluid_synth_t* synth, int chan)
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param apply TRUE to apply tuning change to active notes, FALSE otherwise
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @since 1.1.0
*/
int
-fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply)
+fluid_synth_deactivate_tuning(fluid_synth_t *synth, int chan, int apply)
{
- int retval = FLUID_OK;
+ int retval = FLUID_OK;
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- retval = fluid_synth_set_tuning_LOCAL (synth, chan, NULL, apply);
+ retval = fluid_synth_set_tuning_LOCAL(synth, chan, NULL, apply);
- FLUID_API_RETURN(retval);
+ FLUID_API_RETURN(retval);
}
/**
@@ -4518,12 +5974,12 @@ fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply)
* @param synth FluidSynth instance
*/
void
-fluid_synth_tuning_iteration_start(fluid_synth_t* synth)
+fluid_synth_tuning_iteration_start(fluid_synth_t *synth)
{
- fluid_return_if_fail (synth != NULL);
- fluid_synth_api_enter(synth);
- fluid_private_set (synth->tuning_iter, FLUID_INT_TO_POINTER (0));
- fluid_synth_api_exit(synth);
+ fluid_return_if_fail(synth != NULL);
+ fluid_synth_api_enter(synth);
+ fluid_private_set(synth->tuning_iter, FLUID_INT_TO_POINTER(0));
+ fluid_synth_api_exit(synth);
}
/**
@@ -4534,48 +5990,59 @@ fluid_synth_tuning_iteration_start(fluid_synth_t* synth)
* @return 1 if tuning iteration advanced, 0 if no more tunings
*/
int
-fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog)
+fluid_synth_tuning_iteration_next(fluid_synth_t *synth, int *bank, int *prog)
{
- void *pval;
- int b = 0, p = 0;
-
- fluid_return_val_if_fail (synth != NULL, 0);
- fluid_return_val_if_fail (bank != NULL, 0);
- fluid_return_val_if_fail (prog != NULL, 0);
- fluid_synth_api_enter(synth);
-
- /* Current tuning iteration stored as: bank << 8 | program */
- pval = fluid_private_get (synth->tuning_iter);
- p = FLUID_POINTER_TO_INT (pval);
- b = (p >> 8) & 0xFF;
- p &= 0xFF;
+ void *pval;
+ int b = 0, p = 0;
- if (!synth->tuning)
- {
- FLUID_API_RETURN(0);
- }
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_return_val_if_fail(bank != NULL, 0);
+ fluid_return_val_if_fail(prog != NULL, 0);
+ fluid_synth_api_enter(synth);
- for (; b < 128; b++, p = 0)
- {
- if (synth->tuning[b] == NULL) continue;
+ /* Current tuning iteration stored as: bank << 8 | program */
+ pval = fluid_private_get(synth->tuning_iter);
+ p = FLUID_POINTER_TO_INT(pval);
+ b = (p >> 8) & 0xFF;
+ p &= 0xFF;
- for (; p < 128; p++)
+ if(!synth->tuning)
{
- if (synth->tuning[b][p] == NULL) continue;
-
- *bank = b;
- *prog = p;
+ FLUID_API_RETURN(0);
+ }
- if (p < 127) fluid_private_set (synth->tuning_iter,
- FLUID_INT_TO_POINTER (b << 8 | (p + 1)));
- else fluid_private_set (synth->tuning_iter,
- FLUID_INT_TO_POINTER ((b + 1) << 8));
+ for(; b < 128; b++, p = 0)
+ {
+ if(synth->tuning[b] == NULL)
+ {
+ continue;
+ }
- FLUID_API_RETURN(1);
+ for(; p < 128; p++)
+ {
+ if(synth->tuning[b][p] == NULL)
+ {
+ continue;
+ }
+
+ *bank = b;
+ *prog = p;
+
+ if(p < 127)
+ {
+ fluid_private_set(synth->tuning_iter,
+ FLUID_INT_TO_POINTER(b << 8 | (p + 1)));
+ }
+ else
+ {
+ fluid_private_set(synth->tuning_iter, FLUID_INT_TO_POINTER((b + 1) << 8));
+ }
+
+ FLUID_API_RETURN(1);
+ }
}
- }
- FLUID_API_RETURN(0);
+ FLUID_API_RETURN(0);
}
/**
@@ -4586,32 +6053,34 @@ fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog)
* @param name Location to store tuning name or NULL to ignore
* @param len Maximum number of chars to store to 'name' (including NULL byte)
* @param pitch Array to store tuning scale to or NULL to ignore (len of 128)
- * @return FLUID_OK if matching tuning was found, FLUID_FAILED otherwise
+ * @return #FLUID_OK if matching tuning was found, #FLUID_FAILED otherwise
*/
int
-fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
- char* name, int len, double* pitch)
+fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int prog,
+ char *name, int len, double *pitch)
{
- fluid_tuning_t* tuning;
+ fluid_tuning_t *tuning;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
-
- tuning = fluid_synth_get_tuning (synth, bank, prog);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
- if (tuning)
- {
- if (name)
+ tuning = fluid_synth_get_tuning(synth, bank, prog);
+
+ if(tuning)
{
- snprintf (name, len - 1, "%s", fluid_tuning_get_name (tuning));
- name[len - 1] = 0; /* make sure the string is null terminated */
- }
+ if(name)
+ {
+ FLUID_SNPRINTF(name, len - 1, "%s", fluid_tuning_get_name(tuning));
+ name[len - 1] = 0; /* make sure the string is null terminated */
+ }
- if (pitch)
- FLUID_MEMCPY (pitch, fluid_tuning_get_all (tuning), 128 * sizeof (double));
- }
+ if(pitch)
+ {
+ FLUID_MEMCPY(pitch, fluid_tuning_get_all(tuning), 128 * sizeof(double));
+ }
+ }
- FLUID_API_RETURN(tuning ? FLUID_OK : FLUID_FAILED);
+ FLUID_API_RETURN(tuning ? FLUID_OK : FLUID_FAILED);
}
/**
@@ -4620,440 +6089,940 @@ fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
* @return FluidSynth settings which are assigned to the synth
*/
fluid_settings_t *
-fluid_synth_get_settings(fluid_synth_t* synth)
+fluid_synth_get_settings(fluid_synth_t *synth)
{
- fluid_return_val_if_fail (synth != NULL, NULL);
+ fluid_return_val_if_fail(synth != NULL, NULL);
- return synth->settings;
+ return synth->settings;
}
/**
- * Convenience function to set a string setting of a synth.
+ * Set a SoundFont generator (effect) value on a MIDI channel in real-time.
* @param synth FluidSynth instance
- * @param name Name of setting parameter
- * @param str Value to assign to the setting
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @param chan MIDI channel number (0 to MIDI channel count - 1)
+ * @param param SoundFont generator ID (#fluid_gen_type)
+ * @param value Offset or absolute generator value to assign to the MIDI channel
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ *
+ * This function allows for setting all effect parameters in real time on a
+ * MIDI channel. Setting absolute to non-zero will cause the value to override
+ * any generator values set in the instruments played on the MIDI channel.
+ * See SoundFont 2.01 spec, paragraph 8.1.3, page 48 for details on SoundFont
+ * generator parameters and valid ranges.
*/
-int
-fluid_synth_setstr(fluid_synth_t* synth, const char* name, const char* str)
+int fluid_synth_set_gen(fluid_synth_t *synth, int chan, int param, float value)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
-
- return fluid_settings_setstr(synth->settings, name, str);
+ return fluid_synth_set_gen2(synth, chan, param, value, FALSE, FALSE);
}
/**
- * Convenience function to duplicate a string setting of a synth.
+ * Set a SoundFont generator (effect) value on a MIDI channel in real-time.
* @param synth FluidSynth instance
- * @param name Name of setting parameter
- * @param str Location to store a pointer to the newly allocated string value
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @param chan MIDI channel number (0 to MIDI channel count - 1)
+ * @param param SoundFont generator ID (#fluid_gen_type)
+ * @param value Offset or absolute generator value to assign to the MIDI channel
+ * @param absolute FALSE to assign a relative value, TRUE to assign an absolute value
+ * @param normalized FALSE if value is specified in the native units of the generator,
+ * TRUE to take the value as a 0.0-1.0 range and apply it to the valid
+ * generator effect range (scaled and shifted as necessary).
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
- * The returned string is owned by the caller and should be freed with free()
- * when finished with it.
+ * This function allows for setting all effect parameters in real time on a
+ * MIDI channel. Setting absolute to non-zero will cause the value to override
+ * any generator values set in the instruments played on the MIDI channel.
+ * See SoundFont 2.01 spec, paragraph 8.1.3, page 48 for details on SoundFont
+ * generator parameters and valid ranges.
*/
int
-fluid_synth_dupstr(fluid_synth_t* synth, const char* name, char** str)
+fluid_synth_set_gen2(fluid_synth_t *synth, int chan, int param,
+ float value, int absolute, int normalized)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (str != NULL, FLUID_FAILED);
+ float v;
+ fluid_return_val_if_fail(param >= 0 && param < GEN_LAST, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- return fluid_settings_dupstr(synth->settings, name, str);
+ v = normalized ? fluid_gen_scale(param, value) : value;
+
+ fluid_synth_set_gen_LOCAL(synth, chan, param, v, absolute);
+
+ FLUID_API_RETURN(FLUID_OK);
+}
+
+/* Synthesis thread local set gen function */
+static void
+fluid_synth_set_gen_LOCAL(fluid_synth_t *synth, int chan, int param, float value,
+ int absolute)
+{
+ fluid_voice_t *voice;
+ int i;
+
+ fluid_channel_set_gen(synth->channel[chan], param, value, absolute);
+
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
+
+ if(fluid_voice_get_channel(voice) == chan)
+ {
+ fluid_voice_set_param(voice, param, value, absolute);
+ }
+ }
}
/**
- * Convenience function to set a floating point setting of a synth.
+ * Get generator value assigned to a MIDI channel.
* @param synth FluidSynth instance
- * @param name Name of setting parameter
- * @param val Value to assign to the setting
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @param chan MIDI channel number (0 to MIDI channel count - 1)
+ * @param param SoundFont generator ID (#fluid_gen_type)
+ * @return Current generator value assigned to MIDI channel
+ */
+float
+fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param)
+{
+ float result;
+ fluid_return_val_if_fail(param >= 0 && param < GEN_LAST, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ result = fluid_channel_get_gen(synth->channel[chan], param);
+ FLUID_API_RETURN(result);
+}
+
+/**
+ * Handle MIDI event from MIDI router, used as a callback function.
+ * @param data FluidSynth instance
+ * @param event MIDI event to handle
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*/
int
-fluid_synth_setnum(fluid_synth_t* synth, const char* name, double val)
+fluid_synth_handle_midi_event(void *data, fluid_midi_event_t *event)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
+ fluid_synth_t *synth = (fluid_synth_t *) data;
+ int type = fluid_midi_event_get_type(event);
+ int chan = fluid_midi_event_get_channel(event);
+
+ switch(type)
+ {
+ case NOTE_ON:
+ return fluid_synth_noteon(synth, chan,
+ fluid_midi_event_get_key(event),
+ fluid_midi_event_get_velocity(event));
+
+ case NOTE_OFF:
+ return fluid_synth_noteoff(synth, chan, fluid_midi_event_get_key(event));
+
+ case CONTROL_CHANGE:
+ return fluid_synth_cc(synth, chan,
+ fluid_midi_event_get_control(event),
+ fluid_midi_event_get_value(event));
+
+ case PROGRAM_CHANGE:
+ return fluid_synth_program_change(synth, chan, fluid_midi_event_get_program(event));
- return fluid_settings_setnum(synth->settings, name, val);
+ case CHANNEL_PRESSURE:
+ return fluid_synth_channel_pressure(synth, chan, fluid_midi_event_get_program(event));
+
+ case KEY_PRESSURE:
+ return fluid_synth_key_pressure(synth, chan,
+ fluid_midi_event_get_key(event),
+ fluid_midi_event_get_value(event));
+
+ case PITCH_BEND:
+ return fluid_synth_pitch_bend(synth, chan, fluid_midi_event_get_pitch(event));
+
+ case MIDI_SYSTEM_RESET:
+ return fluid_synth_system_reset(synth);
+
+ case MIDI_SYSEX:
+ return fluid_synth_sysex(synth, event->paramptr, event->param1, NULL, NULL, NULL, FALSE);
+
+ case MIDI_TEXT:
+ case MIDI_LYRIC:
+ case MIDI_SET_TEMPO:
+ return FLUID_OK;
+ }
+
+ return FLUID_FAILED;
}
/**
- * Convenience function to get a floating point setting of a synth.
+ * Create and start voices using a preset and a MIDI note on event.
* @param synth FluidSynth instance
- * @param name Name of setting parameter
- * @param val Location to store the current value of the setting
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @param id Voice group ID to use (can be used with fluid_synth_stop()).
+ * @param preset Preset to synthesize
+ * @param audio_chan Unused currently, set to 0
+ * @param chan MIDI channel number (0 to MIDI channel count - 1)
+ * @param key MIDI note number (0-127)
+ * @param vel MIDI velocity number (1-127)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ *
+ * @note Should only be called from within synthesis thread, which includes
+ * SoundFont loader preset noteon method.
*/
int
-fluid_synth_getnum(fluid_synth_t* synth, const char* name, double* val)
+fluid_synth_start(fluid_synth_t *synth, unsigned int id, fluid_preset_t *preset,
+ int audio_chan, int chan, int key, int vel)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
-
- return fluid_settings_getnum(synth->settings, name, val);
+ int result;
+ fluid_return_val_if_fail(preset != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED);
+ fluid_return_val_if_fail(vel >= 1 && vel <= 127, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ synth->storeid = id;
+ result = fluid_preset_noteon(preset, synth, chan, key, vel);
+ FLUID_API_RETURN(result);
}
/**
- * Convenience function to set an integer setting of a synth.
+ * Stop notes for a given note event voice ID.
* @param synth FluidSynth instance
- * @param name Name of setting parameter
- * @param val Value to assign to the setting
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @param id Voice note event ID
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ *
+ * @note In FluidSynth versions prior to 1.1.0 #FLUID_FAILED would be returned
+ * if no matching voice note event ID was found. Versions after 1.1.0 only
+ * return #FLUID_FAILED if an error occurs.
*/
int
-fluid_synth_setint(fluid_synth_t* synth, const char* name, int val)
+fluid_synth_stop(fluid_synth_t *synth, unsigned int id)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
+ int result;
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+ fluid_synth_stop_LOCAL(synth, id);
+ result = FLUID_OK;
+ FLUID_API_RETURN(result);
+}
+
+/* Local synthesis thread variant of fluid_synth_stop */
+static void
+fluid_synth_stop_LOCAL(fluid_synth_t *synth, unsigned int id)
+{
+ fluid_voice_t *voice;
+ int i;
- return fluid_settings_setint(synth->settings, name, val);
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
+
+ if(fluid_voice_is_on(voice) && (fluid_voice_get_id(voice) == id))
+ {
+ fluid_voice_noteoff(voice);
+ }
+ }
}
/**
- * Convenience function to get an integer setting of a synth.
+ * Offset the bank numbers of a loaded SoundFont, i.e.\ subtract
+ * \c offset from any bank number when assigning instruments.
+ *
* @param synth FluidSynth instance
- * @param name Name of setting parameter
- * @param val Location to store the current value of the setting
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * @param sfont_id ID of a loaded SoundFont
+ * @param offset Bank offset value to apply to all instruments
+ * @return #FLUID_OK if the offset was set successfully, #FLUID_FAILED otherwise
*/
int
-fluid_synth_getint(fluid_synth_t* synth, const char* name, int* val)
+fluid_synth_set_bank_offset(fluid_synth_t *synth, int sfont_id, int offset)
{
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
+ fluid_sfont_t *sfont;
+ fluid_list_t *list;
- return fluid_settings_getint(synth->settings, name, val);
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+
+ for(list = synth->sfont; list; list = fluid_list_next(list))
+ {
+ sfont = fluid_list_get(list);
+
+ if(fluid_sfont_get_id(sfont) == sfont_id)
+ {
+ sfont->bankofs = offset;
+ break;
+ }
+ }
+
+ if(!list)
+ {
+ FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", sfont_id);
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
+
+ FLUID_API_RETURN(FLUID_OK);
}
/**
- * Set a SoundFont generator (effect) value on a MIDI channel in real-time.
+ * Get bank offset of a loaded SoundFont.
* @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param param SoundFont generator ID (#fluid_gen_type)
- * @param value Offset generator value to assign to the MIDI channel
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- *
- * Parameter numbers and ranges are described in the SoundFont 2.01
- * specification PDF, paragraph 8.1.3, page 48. See #fluid_gen_type.
+ * @param sfont_id ID of a loaded SoundFont
+ * @return SoundFont bank offset value
*/
int
-fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value)
+fluid_synth_get_bank_offset(fluid_synth_t *synth, int sfont_id)
{
- fluid_return_val_if_fail (param >= 0 && param < GEN_LAST, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ fluid_sfont_t *sfont;
+ fluid_list_t *list;
+ int offset = 0;
+
+ fluid_return_val_if_fail(synth != NULL, 0);
+ fluid_synth_api_enter(synth);
+
+ for(list = synth->sfont; list; list = fluid_list_next(list))
+ {
+ sfont = fluid_list_get(list);
+
+ if(fluid_sfont_get_id(sfont) == sfont_id)
+ {
+ offset = sfont->bankofs;
+ break;
+ }
+ }
- fluid_synth_set_gen_LOCAL (synth, chan, param, value, FALSE);
+ if(!list)
+ {
+ FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", sfont_id);
+ FLUID_API_RETURN(0);
+ }
- FLUID_API_RETURN(FLUID_OK);
+ FLUID_API_RETURN(offset);
}
-/* Synthesis thread local set gen function */
-static void
-fluid_synth_set_gen_LOCAL (fluid_synth_t* synth, int chan, int param, float value,
- int absolute)
+void
+fluid_synth_api_enter(fluid_synth_t *synth)
{
- fluid_voice_t* voice;
- int i;
+ if(synth->use_mutex)
+ {
+ fluid_rec_mutex_lock(synth->mutex);
+ }
- fluid_channel_set_gen (synth->channel[chan], param, value, absolute);
+ if(!synth->public_api_count)
+ {
+ fluid_synth_check_finished_voices(synth);
+ }
+
+ synth->public_api_count++;
+}
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+void fluid_synth_api_exit(fluid_synth_t *synth)
+{
+ synth->public_api_count--;
+
+ if(!synth->public_api_count)
+ {
+ fluid_rvoice_eventhandler_flush(synth->eventhandler);
+ }
+
+ if(synth->use_mutex)
+ {
+ fluid_rec_mutex_unlock(synth->mutex);
+ }
- if (voice->chan == chan)
- fluid_voice_set_param (voice, param, value, absolute);
- }
}
/**
- * Set a SoundFont generator (effect) value on a MIDI channel in real-time.
+ * Set midi channel type
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param param SoundFont generator ID (#fluid_gen_type)
- * @param value Offset or absolute generator value to assign to the MIDI channel
- * @param absolute 0 to assign a relative value, non-zero to assign an absolute value
- * @param normalized 0 if value is specified in the native units of the generator,
- * non-zero to take the value as a 0.0-1.0 range and apply it to the valid
- * generator effect range (scaled and shifted as necessary).
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- * @since 1.1.0
- *
- * This function allows for setting all effect parameters in real time on a
- * MIDI channel. Setting absolute to non-zero will cause the value to override
- * any generator values set in the instruments played on the MIDI channel.
- * See SoundFont 2.01 spec, paragraph 8.1.3, page 48 for details on SoundFont
- * generator parameters and valid ranges.
+ * @param type MIDI channel type (#fluid_midi_channel_type)
+ * @return #FLUID_OK on success, #FLUID_FAILED otherwise
+ * @since 1.1.4
*/
-int
-fluid_synth_set_gen2(fluid_synth_t* synth, int chan, int param,
- float value, int absolute, int normalized)
+int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
{
- float v;
- fluid_return_val_if_fail (param >= 0 && param < GEN_LAST, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- v = normalized ? fluid_gen_scale(param, value) : value;
+ fluid_return_val_if_fail((type >= CHANNEL_TYPE_MELODIC) && (type <= CHANNEL_TYPE_DRUM), FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- fluid_synth_set_gen_LOCAL (synth, chan, param, v, absolute);
+ synth->channel[chan]->channel_type = type;
- FLUID_API_RETURN(FLUID_OK);
+ FLUID_API_RETURN(FLUID_OK);
}
+#ifdef LADSPA
/**
- * Get generator value assigned to a MIDI channel.
+ * Return the LADSPA effects instance used by FluidSynth
+ *
* @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param param SoundFont generator ID (#fluid_gen_type)
- * @return Current generator value assigned to MIDI channel
+ * @return pointer to LADSPA fx or NULL if compiled without LADSPA support or LADSPA is not active
*/
-float
-fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param)
+fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
{
- float result;
- fluid_return_val_if_fail (param >= 0 && param < GEN_LAST, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ fluid_return_val_if_fail(synth != NULL, NULL);
- result = fluid_channel_get_gen(synth->channel[chan], param);
- FLUID_API_RETURN(result);
+ return synth->ladspa_fx;
}
+#endif
/**
- * Assign a MIDI router to a synth.
+ * Configure a general-purpose IIR biquad filter.
+ *
+ * This is an optional, additional filter that operates independently from the default low-pass filter required by the Soundfont2 standard.
+ * By default this filter is off (#FLUID_IIR_DISABLED).
+ *
* @param synth FluidSynth instance
- * @param router MIDI router to assign to the synth
+ * @param type Type of the IIR filter to use (see #fluid_iir_filter_type)
+ * @param flags Additional flags to customize this filter or zero to stay with the default (see #fluid_iir_filter_flags)
*
- * NOTE: This should only be done once and prior to using the synth.
+ * @return #FLUID_OK if the settings have been successfully applied, otherwise #FLUID_FAILED
*/
-void
-fluid_synth_set_midi_router(fluid_synth_t* synth, fluid_midi_router_t* router)
+int fluid_synth_set_custom_filter(fluid_synth_t *synth, int type, int flags)
{
- fluid_return_if_fail (synth != NULL);
- fluid_synth_api_enter(synth);
+ int i;
+ fluid_voice_t *voice;
- synth->midi_router = router;
- fluid_synth_api_exit(synth);
-};
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_return_val_if_fail(type >= FLUID_IIR_DISABLED && type < FLUID_IIR_LAST, FLUID_FAILED);
+
+ fluid_synth_api_enter(synth);
+
+ synth->custom_filter_type = type;
+ synth->custom_filter_flags = flags;
+
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
+
+ fluid_voice_set_custom_filter(voice, type, flags);
+ }
+
+ FLUID_API_RETURN(FLUID_OK);
+}
/**
- * Handle MIDI event from MIDI router, used as a callback function.
- * @param data FluidSynth instance
- * @param event MIDI event to handle
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * Set the important channels for voice overflow priority calculation.
+ *
+ * @param synth FluidSynth instance
+ * @param channels comma-separated list of channel numbers
+ * @return #FLUID_OK on success, otherwise #FLUID_FAILED
*/
-int
-fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event)
+static int fluid_synth_set_important_channels(fluid_synth_t *synth, const char *channels)
{
- fluid_synth_t* synth = (fluid_synth_t*) data;
- int type = fluid_midi_event_get_type(event);
- int chan = fluid_midi_event_get_channel(event);
+ int i;
+ int retval = FLUID_FAILED;
+ int *values = NULL;
+ int num_values;
+ fluid_overflow_prio_t *scores;
- switch(type) {
- case NOTE_ON:
- return fluid_synth_noteon(synth, chan,
- fluid_midi_event_get_key(event),
- fluid_midi_event_get_velocity(event));
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
- case NOTE_OFF:
- return fluid_synth_noteoff(synth, chan, fluid_midi_event_get_key(event));
+ scores = &synth->overflow;
- case CONTROL_CHANGE:
- return fluid_synth_cc(synth, chan,
- fluid_midi_event_get_control(event),
- fluid_midi_event_get_value(event));
+ if(scores->num_important_channels < synth->midi_channels)
+ {
+ scores->important_channels = FLUID_REALLOC(scores->important_channels,
+ sizeof(*scores->important_channels) * synth->midi_channels);
- case PROGRAM_CHANGE:
- return fluid_synth_program_change(synth, chan, fluid_midi_event_get_program(event));
+ if(scores->important_channels == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto exit;
+ }
+
+ scores->num_important_channels = synth->midi_channels;
+ }
- case CHANNEL_PRESSURE:
- return fluid_synth_channel_pressure(synth, chan, fluid_midi_event_get_program(event));
+ FLUID_MEMSET(scores->important_channels, FALSE,
+ sizeof(*scores->important_channels) * scores->num_important_channels);
- case PITCH_BEND:
- return fluid_synth_pitch_bend(synth, chan, fluid_midi_event_get_pitch(event));
+ if(channels != NULL)
+ {
+ values = FLUID_ARRAY(int, synth->midi_channels);
+
+ if(values == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto exit;
+ }
- case MIDI_SYSTEM_RESET:
- return fluid_synth_system_reset(synth);
- case MIDI_SYSEX:
- return fluid_synth_sysex (synth, event->paramptr, event->param1, NULL, NULL, NULL, FALSE);
- }
- return FLUID_FAILED;
+ /* Every channel given in the comma-separated list of channel numbers
+ * is set to TRUE, i.e. flagging it as "important". Channel numbers are
+ * 1-based. */
+ num_values = fluid_settings_split_csv(channels, values, synth->midi_channels);
+
+ for(i = 0; i < num_values; i++)
+ {
+ if(values[i] > 0 && values[i] <= synth->midi_channels)
+ {
+ scores->important_channels[values[i] - 1] = TRUE;
+ }
+ }
+ }
+
+ retval = FLUID_OK;
+
+exit:
+ FLUID_FREE(values);
+ return retval;
}
+/*
+ * Handler for synth.overflow.important-channels setting.
+ */
+static void fluid_synth_handle_important_channels(void *data, const char *name,
+ const char *value)
+{
+ fluid_synth_t *synth = (fluid_synth_t *)data;
+
+ fluid_synth_api_enter(synth);
+ fluid_synth_set_important_channels(synth, value);
+ fluid_synth_api_exit(synth);
+}
+
+
+/** API legato mode *********************************************************/
+
/**
- * Create and start voices using a preset and a MIDI note on event.
- * @param synth FluidSynth instance
- * @param id Voice group ID to use (can be used with fluid_synth_stop()).
- * @param preset Preset to synthesize
- * @param audio_chan Unused currently, set to 0
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param key MIDI note number (0-127)
- * @param vel MIDI velocity number (1-127)
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * Sets the legato mode of a channel.
*
- * NOTE: Should only be called from within synthesis thread, which includes
- * SoundFont loader preset noteon method.
+ * @param synth the synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param legatomode The legato mode as indicated by #fluid_channel_legato_mode.
+ *
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ * - \a legatomode is invalid.
*/
-int
-fluid_synth_start(fluid_synth_t* synth, unsigned int id, fluid_preset_t* preset,
- int audio_chan, int chan, int key, int vel)
+int fluid_synth_set_legato_mode(fluid_synth_t *synth, int chan, int legatomode)
{
- int result;
- fluid_return_val_if_fail (preset != NULL, FLUID_FAILED);
- fluid_return_val_if_fail (key >= 0 && key <= 127, FLUID_FAILED);
- fluid_return_val_if_fail (vel >= 1 && vel <= 127, FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
- synth->storeid = id;
- result = fluid_preset_noteon (preset, synth, chan, key, vel);
- FLUID_API_RETURN(result);
+ /* checks parameters first */
+ fluid_return_val_if_fail(legatomode >= 0, FLUID_FAILED);
+ fluid_return_val_if_fail(legatomode < FLUID_CHANNEL_LEGATO_MODE_LAST, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ /**/
+ synth->channel[chan]->legatomode = legatomode;
+ /**/
+ FLUID_API_RETURN(FLUID_OK);
}
/**
- * Stop notes for a given note event voice ID.
- * @param synth FluidSynth instance
- * @param id Voice note event ID
- * @return FLUID_OK on success, FLUID_FAILED otherwise
+ * Gets the legato mode of a channel.
*
- * NOTE: In FluidSynth versions prior to 1.1.0 #FLUID_FAILED would be returned
- * if no matching voice note event ID was found. Versions after 1.1.0 only
- * return #FLUID_FAILED if an error occurs.
+ * @param synth the synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param legatomode The legato mode as indicated by #fluid_channel_legato_mode.
+ *
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ * - \a legatomode is NULL.
*/
-int
-fluid_synth_stop(fluid_synth_t* synth, unsigned int id)
+int fluid_synth_get_legato_mode(fluid_synth_t *synth, int chan, int *legatomode)
{
- int result;
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
- fluid_synth_stop_LOCAL (synth, id);
- result = FLUID_OK;
- FLUID_API_RETURN(result);
+ /* checks parameters first */
+ fluid_return_val_if_fail(legatomode != NULL, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ /**/
+ * legatomode = synth->channel[chan]->legatomode;
+ /**/
+ FLUID_API_RETURN(FLUID_OK);
}
-/* Local synthesis thread variant of fluid_synth_stop */
-static void
-fluid_synth_stop_LOCAL (fluid_synth_t *synth, unsigned int id)
-{
- fluid_voice_t* voice;
- int i;
+/** API portamento mode *********************************************************/
- for (i = 0; i < synth->polyphony; i++) {
- voice = synth->voice[i];
+/**
+ * Sets the portamento mode of a channel.
+ *
+ * @param synth the synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param portamentomode The portamento mode as indicated by #fluid_channel_portamento_mode.
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ * - \a portamentomode is invalid.
+ */
+int fluid_synth_set_portamento_mode(fluid_synth_t *synth, int chan,
+ int portamentomode)
+{
+ /* checks parameters first */
+ fluid_return_val_if_fail(portamentomode >= 0, FLUID_FAILED);
+ fluid_return_val_if_fail(portamentomode < FLUID_CHANNEL_PORTAMENTO_MODE_LAST, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ /**/
+ synth->channel[chan]->portamentomode = portamentomode;
+ /**/
+ FLUID_API_RETURN(FLUID_OK);
+}
- if (_ON(voice) && (fluid_voice_get_id (voice) == id))
- fluid_voice_noteoff(voice);
- }
+/**
+ * Gets the portamento mode of a channel.
+ *
+ * @param synth the synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param portamentomode Pointer to the portamento mode as indicated by #fluid_channel_portamento_mode.
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ * - \a portamentomode is NULL.
+ */
+int fluid_synth_get_portamento_mode(fluid_synth_t *synth, int chan,
+ int *portamentomode)
+{
+ /* checks parameters first */
+ fluid_return_val_if_fail(portamentomode != NULL, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ /**/
+ * portamentomode = synth->channel[chan]->portamentomode;
+ /**/
+ FLUID_API_RETURN(FLUID_OK);
+}
+
+/** API breath mode *********************************************************/
+
+/**
+ * Sets the breath mode of a channel.
+ *
+ * @param synth the synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param breathmode The breath mode as indicated by #fluid_channel_breath_flags.
+ *
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ */
+int fluid_synth_set_breath_mode(fluid_synth_t *synth, int chan, int breathmode)
+{
+ /* checks parameters first */
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ /**/
+ fluid_channel_set_breath_info(synth->channel[chan], breathmode);
+ /**/
+ FLUID_API_RETURN(FLUID_OK);
}
/**
- * Offset the bank numbers of a loaded SoundFont.
- * @param synth FluidSynth instance
- * @param sfont_id ID of a loaded SoundFont
- * @param offset Bank offset value to apply to all instruments
+ * Gets the breath mode of a channel.
+ *
+ * @param synth the synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param breathmode Pointer to the returned breath mode as indicated by #fluid_channel_breath_flags.
+ *
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ * - \a breathmode is NULL.
*/
-int
-fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset)
+int fluid_synth_get_breath_mode(fluid_synth_t *synth, int chan, int *breathmode)
{
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
+ /* checks parameters first */
+ fluid_return_val_if_fail(breathmode != NULL, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+ /**/
+ * breathmode = fluid_channel_get_breath_info(synth->channel[chan]);
+ /**/
+ FLUID_API_RETURN(FLUID_OK);
+}
- fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
- fluid_synth_api_enter(synth);
-
- for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
+/** API Poly/mono mode ******************************************************/
- if (fluid_sfont_get_id (sfont_info->sfont) == (unsigned int)sfont_id)
+/*
+ * Resets a basic channel group of MIDI channels.
+ * @param synth the synth instance.
+ * @param chan the beginning channel of the group.
+ * @param nbr_chan the number of channel in the group.
+*/
+static void
+fluid_synth_reset_basic_channel_LOCAL(fluid_synth_t *synth, int chan, int nbr_chan)
+{
+ int i;
+
+ for(i = chan; i < chan + nbr_chan; i++)
{
- sfont_info->bankofs = offset;
- break;
+ fluid_channel_reset_basic_channel_info(synth->channel[i]);
+ synth->channel[i]->mode_val = 0;
}
- }
+}
- if (!list)
- {
- FLUID_LOG (FLUID_ERR, "No SoundFont with id = %d", sfont_id);
- FLUID_API_RETURN(FLUID_FAILED);
- }
+/**
+ * Disables and unassigns all channels from a basic channel group.
+ *
+ * @param synth The synth instance.
+ * @param chan The basic channel of the group to reset or -1 to reset all channels.
+ * @note By default (i.e. on creation after new_fluid_synth() and after fluid_synth_system_reset())
+ * a synth instance has one basic channel at channel 0 in mode #FLUID_CHANNEL_MODE_OMNION_POLY.
+ * All other channels belong to this basic channel group. Make sure to call this function before
+ * setting any custom basic channel setup.
+ *
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ * - \a chan isn't a basic channel.
+ */
+int fluid_synth_reset_basic_channel(fluid_synth_t *synth, int chan)
+{
+ int nbr_chan;
+
+ /* checks parameters first */
+ if(chan < 0)
+ {
+ fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
+ fluid_synth_api_enter(synth);
+ /* The range is all MIDI channels from 0 to MIDI channel count -1 */
+ chan = 0; /* beginning chan */
+ nbr_chan = synth->midi_channels; /* MIDI Channels number */
+ }
+ else
+ {
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /* checks if chan is a basic channel */
+ if(!(synth->channel[chan]->mode & FLUID_CHANNEL_BASIC))
+ {
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
- FLUID_API_RETURN(FLUID_OK);
+ /* The range is all MIDI channels in the group from chan */
+ nbr_chan = synth->channel[chan]->mode_val; /* nbr of channels in the group */
+ }
+
+ /* resets the range of MIDI channels */
+ fluid_synth_reset_basic_channel_LOCAL(synth, chan, nbr_chan);
+ FLUID_API_RETURN(FLUID_OK);
}
/**
- * Get bank offset of a loaded SoundFont.
- * @param synth FluidSynth instance
- * @param sfont_id ID of a loaded SoundFont
- * @return SoundFont bank offset value
+ * Checks if a new basic channel group overlaps the next basic channel group.
+ *
+ * On success the function returns the possible number of channel for this
+ * new basic channel group.
+ * The function fails if the new group overlaps the next basic channel group.
+ *
+ * @param see fluid_synth_set_basic_channel.
+ * @return
+ * - On success, the effective number of channels for this new basic channel group,
+ * #FLUID_FAILED otherwise.
+ * - #FLUID_FAILED
+ * - \a val has a number of channels overlapping next basic channel group or been
+ * above MIDI channel count.
*/
-int
-fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id)
+static int
+fluid_synth_check_next_basic_channel(fluid_synth_t *synth, int basicchan, int mode, int val)
{
- fluid_sfont_info_t *sfont_info;
- fluid_list_t *list;
- int offset = 0;
+ int i, n_chan = synth->midi_channels; /* MIDI Channels count */
+ int real_val = val; /* real number of channels in the group */
- fluid_return_val_if_fail (synth != NULL, 0);
- fluid_synth_api_enter(synth);
+ /* adjusts val range */
+ if(mode == FLUID_CHANNEL_MODE_OMNIOFF_POLY)
+ {
+ real_val = 1; /* mode poly omnioff implies a group of only one channel.*/
+ }
+ else if(val == 0)
+ {
+ /* mode poly omnion (0), mono omnion (1), mono omni off (3) */
+ /* value 0 means all possible channels from basicchan to MIDI channel count -1.*/
+ real_val = n_chan - basicchan;
+ }
+ /* checks if val range is above MIDI channel count */
+ else if(basicchan + val > n_chan)
+ {
+ return FLUID_FAILED;
+ }
- for (list = synth->sfont_info; list; list = fluid_list_next(list)) {
- sfont_info = (fluid_sfont_info_t *)fluid_list_get (list);
+ /* checks if this basic channel group overlaps next basic channel group */
+ for(i = basicchan + 1; i < basicchan + real_val; i++)
+ {
+ if(synth->channel[i]->mode & FLUID_CHANNEL_BASIC)
+ {
+ /* A value of 0 for val means all possible channels from basicchan to
+ to the next basic channel -1 (if any).
+ When i reachs the next basic channel group, real_val will be
+ limited if it is possible */
+ if(val == 0)
+ {
+ /* limitation of real_val */
+ real_val = i - basicchan;
+ break;
+ }
+
+ /* overlap with the next basic channel group */
+ return FLUID_FAILED;
+ }
+ }
- if (fluid_sfont_get_id (sfont_info->sfont) == (unsigned int)sfont_id)
+ return real_val;
+}
+
+/**
+ * Sets a new basic channel group only. The function doesn't allow to change an
+ * existing basic channel.
+ *
+ * The function fails if any channel overlaps any existing basic channel group.
+ * To make room if necessary, basic channel groups can be cleared using
+ * fluid_synth_reset_basic_channel().
+ *
+ * @param synth the synth instance.
+ * @param chan the basic Channel number (0 to MIDI channel count-1).
+ * @param mode the MIDI mode to use for chan (see #fluid_basic_channel_modes).
+ * @param val number of channels in the group.
+ * @note \a val is only relevant for mode #FLUID_CHANNEL_MODE_OMNION_POLY,
+ * #FLUID_CHANNEL_MODE_OMNION_MONO and #FLUID_CHANNEL_MODE_OMNIOFF_MONO. A value
+ * of 0 means all possible channels from \a chan to to next basic channel minus 1 (if any)
+ * or to MIDI channel count minus 1. Val is ignored for #FLUID_CHANNEL_MODE_OMNIOFF_POLY
+ * as this mode implies a group of only one channel.
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ * - \a mode is invalid.
+ * - \a val has a number of channels overlapping another basic channel group or been
+ * above MIDI channel count.
+ * - When the function fails, any existing basic channels aren't modified.
+ */
+int fluid_synth_set_basic_channel(fluid_synth_t *synth, int chan, int mode, int val)
+{
+ /* check parameters */
+ fluid_return_val_if_fail(mode >= 0, FLUID_FAILED);
+ fluid_return_val_if_fail(mode < FLUID_CHANNEL_MODE_LAST, FLUID_FAILED);
+ fluid_return_val_if_fail(val >= 0, FLUID_FAILED);
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ /**/
+ if(val > 0 && chan + val > synth->midi_channels)
{
- offset = sfont_info->bankofs;
- break;
+ FLUID_API_RETURN(FLUID_FAILED);
}
- }
- if (!list)
- {
- FLUID_LOG (FLUID_ERR, "No SoundFont with id = %d", sfont_id);
- FLUID_API_RETURN(0);
- }
+ /* Checks if there is an overlap with the next basic channel */
+ val = fluid_synth_check_next_basic_channel(synth, chan, mode, val);
- FLUID_API_RETURN(offset);
-}
+ if(val == FLUID_FAILED || synth->channel[chan]->mode & FLUID_CHANNEL_ENABLED)
+ {
+ /* overlap with the next or previous channel group */
+ FLUID_LOG(FLUID_INFO, "basic channel %d overlaps another group", chan);
+ FLUID_API_RETURN(FLUID_FAILED);
+ }
-void
-fluid_synth_api_enter(fluid_synth_t* synth)
-{
- if (synth->use_mutex) {
- fluid_rec_mutex_lock(synth->mutex);
- }
- if (!synth->public_api_count) {
- fluid_synth_check_finished_voices(synth);
- }
- synth->public_api_count++;
+ /* sets a new basic channel group */
+ fluid_synth_set_basic_channel_LOCAL(synth, chan, mode, val);
+ /**/
+ FLUID_API_RETURN(FLUID_OK);
}
-void fluid_synth_api_exit(fluid_synth_t* synth)
+/*
+ * Local version of fluid_synth_set_basic_channel(), called internally:
+ * - by fluid_synth_set_basic_channel() to set a new basic channel group.
+ * - during creation new_fluid_synth() or on CC reset to set a default basic channel group.
+ * - on CC ominoff, CC omnion, CC poly , CC mono to change an existing basic channel group.
+ *
+ * @param see fluid_synth_set_basic_channel()
+*/
+static void
+fluid_synth_set_basic_channel_LOCAL(fluid_synth_t *synth, int basicchan, int mode, int val)
{
- synth->public_api_count--;
- if (!synth->public_api_count) {
- fluid_rvoice_eventhandler_flush(synth->eventhandler);
- }
+ int i;
- if (synth->use_mutex) {
- fluid_rec_mutex_unlock(synth->mutex);
- }
-
-}
+ /* sets the basic channel group */
+ for(i = basicchan; i < basicchan + val; i++)
+ {
+ int new_mode = mode; /* OMNI_OFF/ON, MONO/POLY ,others bits are zero */
+ int new_val;
+ /* MIDI specs: when mode is changed, channel must receive ALL_NOTES_OFF */
+ fluid_synth_all_notes_off_LOCAL(synth, i);
+
+ if(i == basicchan)
+ {
+ new_mode |= FLUID_CHANNEL_BASIC; /* First channel in the group */
+ new_val = val; /* number of channels in the group */
+ }
+ else
+ {
+ new_val = 0; /* val is 0 for other channel than basic channel */
+ }
+ /* Channel is enabled */
+ new_mode |= FLUID_CHANNEL_ENABLED;
+ /* Now new_mode is OMNI OFF/ON,MONO/POLY, BASIC_CHANNEL or not and enabled */
+ fluid_channel_set_basic_channel_info(synth->channel[i], new_mode);
+ synth->channel[i]->mode_val = new_val;
+ }
+}
/**
- * Set midi channel type
- * @param synth FluidSynth instance
- * @param chan MIDI channel number (0 to MIDI channel count - 1)
- * @param type CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM
- * @return FLUID_OK on success, FLUID_FAILED otherwise
- * @since 1.1.4
+ * Searchs a previous basic channel starting from chan.
+ *
+ * @param synth the synth instance.
+ * @param chan starting index of the search (including chan).
+ * @return index of the basic channel if found , FLUID_FAILED otherwise.
*/
-int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type)
+static int fluid_synth_get_previous_basic_channel(fluid_synth_t *synth, int chan)
{
- fluid_return_val_if_fail ((type >= CHANNEL_TYPE_MELODIC) && (type <= CHANNEL_TYPE_DRUM), FLUID_FAILED);
- FLUID_API_ENTRY_CHAN(FLUID_FAILED);
-
- synth->channel[chan]->channel_type = type;
+ for(; chan >= 0; chan--)
+ {
+ /* searchs previous basic channel */
+ if(synth->channel[chan]->mode & FLUID_CHANNEL_BASIC)
+ {
+ /* chan is the previous basic channel */
+ return chan;
+ }
+ }
- FLUID_API_RETURN(FLUID_OK);
+ return FLUID_FAILED;
}
+/**
+ * Returns poly mono mode information of any MIDI channel.
+ *
+ * @param synth the synth instance
+ * @param chan MIDI channel number (0 to MIDI channel count - 1)
+ * @param basic_chan_out Buffer to store the basic channel \a chan belongs to or #FLUID_FAILED if \a chan is disabled.
+ * @param mode_out Buffer to store the mode of \a chan (see #fluid_basic_channel_modes) or #FLUID_FAILED if \a chan is disabled.
+ * @param val_out Buffer to store the total number of channels in this basic channel group or #FLUID_FAILED if \a chan is disabled.
+ * @note If any of \a basic_chan_out, \a mode_out, \a val_out pointer is NULL
+ * the corresponding information isn't returned.
+ *
+ * @return
+ * - #FLUID_OK on success.
+ * - #FLUID_FAILED
+ * - \a synth is NULL.
+ * - \a chan is outside MIDI channel count.
+ */
+int fluid_synth_get_basic_channel(fluid_synth_t *synth, int chan,
+ int *basic_chan_out,
+ int *mode_out,
+ int *val_out)
+{
+ int basic_chan = FLUID_FAILED;
+ int mode = FLUID_FAILED;
+ int val = FLUID_FAILED;
+
+ /* checks parameters first */
+ FLUID_API_ENTRY_CHAN(FLUID_FAILED);
+
+ if((synth->channel[chan]->mode & FLUID_CHANNEL_ENABLED) &&
+ /* chan is enabled , we search the basic channel chan belongs to */
+ (basic_chan = fluid_synth_get_previous_basic_channel(synth, chan)) != FLUID_FAILED)
+ {
+ mode = synth->channel[chan]->mode & FLUID_CHANNEL_MODE_MASK;
+ val = synth->channel[basic_chan]->mode_val;
+ }
+
+ /* returns the informations if they are requested */
+ if(basic_chan_out)
+ {
+ * basic_chan_out = basic_chan;
+ }
+
+ if(mode_out)
+ {
+ * mode_out = mode;
+ }
+
+ if(val_out)
+ {
+ * val_out = val;
+ }
+
+ FLUID_API_RETURN(FLUID_OK);
+}
diff --git a/libs/fluidsynth/src/fluid_synth.h b/libs/fluidsynth/src/fluid_synth.h
index 019a8e0d55..96dc545746 100644
--- a/libs/fluidsynth/src/fluid_synth.h
+++ b/libs/fluidsynth/src/fluid_synth.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -28,18 +28,11 @@
* INCLUDES
*/
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "fluidsynth_priv.h"
-#include "fluid_event_queue.h"
+#include "fluid_sys.h"
#include "fluid_list.h"
#include "fluid_rev.h"
#include "fluid_voice.h"
#include "fluid_chorus.h"
-//#include "fluid_ladspa.h"
-//#include "fluid_midi_router.h"
-#include "fluid_sys.h"
#include "fluid_rvoice_event.h"
/***************************************************************
@@ -51,23 +44,21 @@
#define FLUID_UNSET_PROGRAM 128 /* Program number used to unset a preset */
-#if defined(WITH_FLOAT)
-#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_FLOAT
-#else
-#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_DOUBLE
-#endif
+#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f /**< Default reverb room size */
+#define FLUID_REVERB_DEFAULT_DAMP 0.0f /**< Default reverb damping */
+#define FLUID_REVERB_DEFAULT_WIDTH 0.5f /**< Default reverb width */
+#define FLUID_REVERB_DEFAULT_LEVEL 0.9f /**< Default reverb level */
+#define FLUID_CHORUS_DEFAULT_N 3 /**< Default chorus voice count */
+#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f /**< Default chorus level */
+#define FLUID_CHORUS_DEFAULT_SPEED 0.3f /**< Default chorus speed */
+#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f /**< Default chorus depth */
+#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE /**< Default chorus waveform type */
/***************************************************************
*
* ENUM
*/
-/*enum fluid_loop {
- FLUID_UNLOOPED = 0,
- FLUID_LOOP_DURING_RELEASE = 1,
- FLUID_NOTUSED = 2,
- FLUID_LOOP_UNTIL_RELEASE = 3
-};*/
/**
* Bank Select MIDI message styles. Default style is GS.
@@ -82,26 +73,15 @@ enum fluid_midi_bank_select
enum fluid_synth_status
{
- FLUID_SYNTH_CLEAN,
- FLUID_SYNTH_PLAYING,
- FLUID_SYNTH_QUIET,
- FLUID_SYNTH_STOPPED
+ FLUID_SYNTH_CLEAN,
+ FLUID_SYNTH_PLAYING,
+ FLUID_SYNTH_QUIET,
+ FLUID_SYNTH_STOPPED
};
#define SYNTH_REVERB_CHANNEL 0
#define SYNTH_CHORUS_CHANNEL 1
-/**
- * Structure used for sfont_info field in #fluid_synth_t for each loaded
- * SoundFont with the SoundFont instance and additional fields.
- */
-typedef struct _fluid_sfont_info_t {
- fluid_sfont_t *sfont; /**< Loaded SoundFont */
- fluid_synth_t *synth; /**< Parent synth */
- int refcount; /**< SoundFont reference count (0 if no presets referencing it) */
- int bankofs; /**< Bank offset */
-} fluid_sfont_info_t;
-
/*
* fluid_synth_t
*
@@ -113,125 +93,141 @@ typedef struct _fluid_sfont_info_t {
* ticks_since_start - atomic, set by rendering thread only
* cpu_load - atomic, set by rendering thread only
* cur, curmax, dither_index - used by rendering thread only
- * LADSPA_FxUnit - same instance copied in rendering thread. Synchronising handled internally (I think...?).
+ * ladspa_fx - same instance copied in rendering thread. Synchronising handled internally.
*
*/
struct _fluid_synth_t
{
- fluid_rec_mutex_t mutex; /**< Lock for public API */
- int use_mutex; /**< Use mutex for all public API functions? */
- int public_api_count; /**< How many times the mutex is currently locked */
-
- fluid_settings_t* settings; /**< the synthesizer settings */
- int device_id; /**< Device ID used for SYSEX messages */
- int polyphony; /**< Maximum polyphony */
- int with_reverb; /**< Should the synth use the built-in reverb unit? */
- int with_chorus; /**< Should the synth use the built-in chorus unit? */
- int verbose; /**< Turn verbose mode on? */
- int dump; /**< Dump events to stdout to hook up a user interface? */
- double sample_rate; /**< The sample rate */
- int midi_channels; /**< the number of MIDI channels (>= 16) */
- int bank_select; /**< the style of Bank Select MIDI messages */
- int audio_channels; /**< the number of audio channels (1 channel=left+right) */
- int audio_groups; /**< the number of (stereo) 'sub'groups from the synth.
+ fluid_rec_mutex_t mutex; /**< Lock for public API */
+ int use_mutex; /**< Use mutex for all public API functions? */
+ int public_api_count; /**< How many times the mutex is currently locked */
+
+ fluid_settings_t *settings; /**< the synthesizer settings */
+ int device_id; /**< Device ID used for SYSEX messages */
+ int polyphony; /**< Maximum polyphony */
+ int with_reverb; /**< Should the synth use the built-in reverb unit? */
+ int with_chorus; /**< Should the synth use the built-in chorus unit? */
+ int verbose; /**< Turn verbose mode on? */
+ double sample_rate; /**< The sample rate */
+ int midi_channels; /**< the number of MIDI channels (>= 16) */
+ int bank_select; /**< the style of Bank Select MIDI messages */
+ int audio_channels; /**< the number of audio channels (1 channel=left+right) */
+ int audio_groups; /**< the number of (stereo) 'sub'groups from the synth.
Typically equal to audio_channels. */
- int effects_channels; /**< the number of effects channels (>= 2) */
- int state; /**< the synthesizer state */
- unsigned int ticks_since_start; /**< the number of audio samples since the start */
- unsigned int start; /**< the start in msec, as returned by system clock */
- fluid_overflow_prio_t overflow; /**< parameters for overflow priority (aka voice-stealing) */
-
- fluid_list_t *loaders; /**< the SoundFont loaders */
- fluid_list_t *sfont_info; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
- fluid_hashtable_t *sfont_hash; /**< Hash of fluid_sfont_t->fluid_sfont_info_t (remains until SoundFont is deleted) */
- unsigned int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
-
- float gain; /**< master gain */
- fluid_channel_t** channel; /**< the channels */
- int nvoice; /**< the length of the synthesis process array (max polyphony allowed) */
- fluid_voice_t** voice; /**< the synthesis voices */
- int active_voice_count; /**< count of active voices */
- unsigned int noteid; /**< the id is incremented for every new note. it's used for noteoff's */
- unsigned int storeid;
- fluid_rvoice_eventhandler_t* eventhandler;
-
- float reverb_roomsize; /**< Shadow of reverb roomsize */
- float reverb_damping; /**< Shadow of reverb damping */
- float reverb_width; /**< Shadow of reverb width */
- float reverb_level; /**< Shadow of reverb level */
-
- int chorus_nr; /**< Shadow of chorus number */
- float chorus_level; /**< Shadow of chorus level */
- float chorus_speed; /**< Shadow of chorus speed */
- float chorus_depth; /**< Shadow of chorus depth */
- int chorus_type; /**< Shadow of chorus type */
-
- int cur; /**< the current sample in the audio buffers to be output */
- int curmax; /**< current amount of samples present in the audio buffers */
- int dither_index; /**< current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
-
- char outbuf[256]; /**< buffer for message output */
- float cpu_load; /**< CPU load in percent (CPU time required / audio synthesized time * 100) */
-
- fluid_tuning_t*** tuning; /**< 128 banks of 128 programs for the tunings */
- fluid_private_t tuning_iter; /**< Tuning iterators per each thread */
-
- fluid_midi_router_t* midi_router; /**< The midi router. Could be done nicer. */
- fluid_sample_timer_t* sample_timers; /**< List of timers triggered before a block is processed */
- unsigned int min_note_length_ticks; /**< If note-offs are triggered just after a note-on, they will be delayed */
-
- int cores; /**< Number of CPU cores (1 by default) */
+ int effects_channels; /**< the number of effects channels (>= 2) */
+ int effects_groups; /**< the number of effects units (>= 1) */
+ int state; /**< the synthesizer state */
+ fluid_atomic_uint_t ticks_since_start; /**< the number of audio samples since the start */
+ unsigned int start; /**< the start in msec, as returned by system clock */
+ fluid_overflow_prio_t overflow; /**< parameters for overflow priority (aka voice-stealing) */
+
+ fluid_list_t *loaders; /**< the SoundFont loaders */
+ fluid_list_t *sfont; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
+ int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
+
+ float gain; /**< master gain */
+ fluid_channel_t **channel; /**< the channels */
+ int nvoice; /**< the length of the synthesis process array (max polyphony allowed) */
+ fluid_voice_t **voice; /**< the synthesis voices */
+ int active_voice_count; /**< count of active voices */
+ unsigned int noteid; /**< the id is incremented for every new note. it's used for noteoff's */
+ unsigned int storeid;
+ int fromkey_portamento; /**< fromkey portamento */
+ fluid_rvoice_eventhandler_t *eventhandler;
+
+ double reverb_roomsize; /**< Shadow of reverb roomsize */
+ double reverb_damping; /**< Shadow of reverb damping */
+ double reverb_width; /**< Shadow of reverb width */
+ double reverb_level; /**< Shadow of reverb level */
+
+ int chorus_nr; /**< Shadow of chorus number */
+ double chorus_level; /**< Shadow of chorus level */
+ double chorus_speed; /**< Shadow of chorus speed */
+ double chorus_depth; /**< Shadow of chorus depth */
+ int chorus_type; /**< Shadow of chorus type */
+
+ int cur; /**< the current sample in the audio buffers to be output */
+ int curmax; /**< current amount of samples present in the audio buffers */
+ int dither_index; /**< current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
+
+ fluid_atomic_float_t cpu_load; /**< CPU load in percent (CPU time required / audio synthesized time * 100) */
+
+ fluid_tuning_t ***tuning; /**< 128 banks of 128 programs for the tunings */
+ fluid_private_t tuning_iter; /**< Tuning iterators per each thread */
+
+ fluid_sample_timer_t *sample_timers; /**< List of timers triggered before a block is processed */
+ unsigned int min_note_length_ticks; /**< If note-offs are triggered just after a note-on, they will be delayed */
+
+ int cores; /**< Number of CPU cores (1 by default) */
+
+ fluid_mod_t *default_mod; /**< the (dynamic) list of default modulators */
#ifdef LADSPA
- fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Effects unit for LADSPA support */
+ fluid_ladspa_fx_t *ladspa_fx; /**< Effects unit for LADSPA support */
#endif
+ enum fluid_iir_filter_type custom_filter_type; /**< filter type of the user-defined filter currently used for all voices */
+ enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */
};
-int fluid_synth_setstr(fluid_synth_t* synth, const char* name, const char* str);
-int fluid_synth_dupstr(fluid_synth_t* synth, const char* name, char** str);
-int fluid_synth_setnum(fluid_synth_t* synth, const char* name, double val);
-int fluid_synth_getnum(fluid_synth_t* synth, const char* name, double* val);
-int fluid_synth_setint(fluid_synth_t* synth, const char* name, int val);
-int fluid_synth_getint(fluid_synth_t* synth, const char* name, int* val);
-
-fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
- unsigned int banknum,
- unsigned int prognum);
-void fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont);
-
-
-int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan);
-int fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan);
-int fluid_synth_kill_voice(fluid_synth_t* synth, fluid_voice_t * voice);
-
-void fluid_synth_print_voice(fluid_synth_t* synth);
-
-void fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
- void* lout, int loff, int lincr,
- void* rout, int roff, int rincr);
-
-int fluid_synth_reset_reverb(fluid_synth_t* synth);
-int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num);
-int fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
+/**
+ * Type definition of the synthesizer's audio callback function.
+ * @param synth FluidSynth instance
+ * @param len Count of audio frames to synthesize
+ * @param out1 Array to store left channel of audio to
+ * @param loff Offset index in 'out1' for first sample
+ * @param lincr Increment between samples stored to 'out1'
+ * @param out2 Array to store right channel of audio to
+ * @param roff Offset index in 'out2' for first sample
+ * @param rincr Increment between samples stored to 'out2'
+ */
+typedef int (*fluid_audio_callback_t)(fluid_synth_t *synth, int len,
+ void *out1, int loff, int lincr,
+ void *out2, int roff, int rincr);
+
+fluid_preset_t *fluid_synth_find_preset(fluid_synth_t *synth,
+ int banknum,
+ int prognum);
+void fluid_synth_sfont_unref(fluid_synth_t *synth, fluid_sfont_t *sfont);
+
+void fluid_synth_dither_s16(int *dither_index, int len, float *lin, float *rin,
+ void *lout, int loff, int lincr,
+ void *rout, int roff, int rincr);
+
+int fluid_synth_reset_reverb(fluid_synth_t *synth);
+int fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num);
+int fluid_synth_set_reverb_full(fluid_synth_t *synth, int set, double roomsize,
double damping, double width, double level);
-int fluid_synth_reset_chorus(fluid_synth_t* synth);
-int fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
+int fluid_synth_reset_chorus(fluid_synth_t *synth);
+int fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level,
double speed, double depth_ms, int type);
-fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data);
-int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer);
+fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data);
+void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer);
-void fluid_synth_api_enter(fluid_synth_t* synth);
-void fluid_synth_api_exit(fluid_synth_t* synth);
-void fluid_synth_process_event_queue(fluid_synth_t* synth);
+void fluid_synth_process_event_queue(fluid_synth_t *synth);
+int fluid_synth_set_gen2(fluid_synth_t *synth, int chan,
+ int param, float value,
+ int absolute, int normalized);
/*
* misc
*/
+void fluid_synth_settings(fluid_settings_t *settings);
+
+
+/* extern declared in fluid_synth_monopoly.c */
+
+int fluid_synth_noteon_mono_staccato(fluid_synth_t *synth, int chan, int key, int vel);
+int fluid_synth_noteon_mono_LOCAL(fluid_synth_t *synth, int chan, int key, int vel);
+int fluid_synth_noteoff_mono_LOCAL(fluid_synth_t *synth, int chan, int key);
+int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan, int fromkey, int tokey, int vel);
+int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key, char Mono);
-void fluid_synth_settings(fluid_settings_t* settings);
+fluid_voice_t *
+fluid_synth_alloc_voice_LOCAL(fluid_synth_t *synth, fluid_sample_t *sample, int chan, int key, int vel, fluid_zone_range_t *zone_range);
+void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan, int key);
#endif /* _FLUID_SYNTH_H */
diff --git a/libs/fluidsynth/src/fluid_synth_monopoly.c b/libs/fluidsynth/src/fluid_synth_monopoly.c
new file mode 100644
index 0000000000..b7828af5b7
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_synth_monopoly.c
@@ -0,0 +1,727 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include "fluid_synth.h"
+#include "fluid_chan.h"
+#include "fluid_defsfont.h"
+
+
+/******************************************************************************
+ The legato detector is composed as this,
+ variables:
+ - monolist: monophonic list variable.
+ - prev_note: to store the most recent note before adding on noteon or before
+ removing on noteoff.
+ - FLUID_CHANNEL_LEGATO_PLAYING: legato/staccato state bit that informs on
+ legato or staccato playing.
+ functions:
+ - fluid_channel_add_monolist(), for inserting a new note.
+ - fluid_channel_search_monolist(), for searching the position of a note
+ into the list.
+ - fluid_channel_remove_monolist(), for removing a note from the list.
+
+ The monophonic list
+ +------------------------------------------------+
+ | +----+ +----+ +----+ +----+ |
+ | |note| |note| |note| |note| |
+ +--->|vel |-->|vel |-->....-->|vel |-->|vel |----+
+ +----+ +----+ +----+ +----+
+ /|\ /|\
+ | |
+ i_first i_last
+
+ The list allows an easy automatic detection of a legato passage when it is
+ played on a MIDI keyboard input device.
+ It is useful also when the input device is an ewi (electronic wind instrument)
+ or evi (electronic valve instrument) and these instruments are unable to send
+ MIDI CC legato on/off.
+
+ The list memorizes the notes in playing order.
+ - (a) On noteOn n2, if a previous note n1 exists, there is a legato
+ detection with n1 (with or without portamento from n1 to n2 See note below).
+ - (b) On noteOff of the running note n2, if a previous note n1 exists,
+ there is a legato detection from n2 to n1, allowing fast trills playing
+ (with or without portamento from n2 to n1. See note below).
+
+ Notes in the list are inserted to the end of the list that works like a
+ circular buffer.The features are:
+
+ 1) It is always possible to play an infinite legato passage in
+ direct order (n1_On,n2_On,n3_On,....).
+
+ 2) Playing legato in the reverse order (n10_Off, n9_Off,,...) helps in
+ fast trills playing as the list memorizes 10 most recent notes.
+
+ 3) Playing an infinite lagato passage in ascendant or descendant order,
+ without playing trills is always possible using the usual way like this:
+ First we begin with an ascendant passage,
+ n1On, (n2On,n1Off), (n3On,n2Off) , (n4On,n3Off), then
+ we continue with a descendant passage
+ (n3On,n4off), (n2On,n3off), (n1On,n2off), n1Off...and so on
+
+ Each MIDI channel have a legato detector.
+
+ Note:
+ Portamento is a feature independant of the legato detector. So
+ portamento isn't part of the lagato detector. However portamento
+ (when enabled) is triggered at noteOn (like legato). Like in legato
+ situation it is usual to have a portamento from a note 'fromkey' to another
+ note 'tokey'. Portamento fromkey note choice is determined at noteOn by
+ fluid_synth_get_fromkey_portamento_legato() (see below).
+
+ More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
+******************************************************************************/
+
+
+/*****************************************************************************
+ Portamento related functions in Poly or Mono mode
+******************************************************************************/
+
+/**
+ * fluid_synth_get_fromkey_portamento_legato returns two informations:
+ * - fromkey note for portamento.
+ * - fromkey note for legato.
+ * +-----> fromkey_portamento
+ * ______|________
+ * portamento modes >------->| |
+ * | get_fromkey |
+ * Porta.on/off >------------------------->|_______________|
+ * (PTC) |
+ * +-----> fromkey_legato
+ *
+ * The functions is intended to be call on noteOn mono
+ * see fluid_synth_noteon_mono_staccato(), fluid_synth_noteon_monopoly_legato()
+ * -------
+ * 1)The function determines if a portamento must occur on next noteOn.
+ * The value returned is 'fromkey portamento' which is the pitchstart key
+ * of a portamento, as function of PTC or (default_fromkey, prev_note) both
+ * if Portamento On. By order of precedence the result is:
+ * 1.1) PTC have precedence over Portamento On.
+ * If CC PTC has been received, its value supersedes and any
+ * portamento pedal On, default_fromkey,prev_note or portamento mode.
+ * 1.2) Otherwise ,when Portamento On the function takes the following value:
+ * - default_fromkey if valid
+ * - otherwise prev_note(prev_note is the note prior the most recent
+ * note played).
+ * Then portamento mode is applied to validate the value choosen.
+ * Where portamento mode is:
+ * - each note, a portamento occurs on each note.
+ * - legato only, portamento only on notes played legato.
+ * - staccato only, portamento only on notes played staccato.
+ * 1.3) Otherwise, portamento is off,INVALID_NOTE is returned (portamento is disabled).
+ * ------
+ * 2)The function determines if a legato playing must occur on next noteOn.
+ * 'fromkey legato note' is returned as a function of default_fromkey, PTC,
+ * current mono/poly mode,actual 'staccato/legato' playing state and prev_note.
+ * By order of precedence the result is:
+ * 2.1) If valid, default_fromkey have precedence over any others values.
+ * 2.2) Otherwise if CC PTC has been received its value is returned.
+ * 2.3) Otherwise fromkey legato is determined from the mono/poly mode,
+ * the actual 'staccato/legato' playing state (FLUID_CHANNEL_LEGATO_PLAYING) and prev_note
+ * as this:
+ * - in (poly/Mono) staccato , INVALID_NOTE is returned.
+ * - in poly legato , actually we don't want playing legato. So
+ * INVALID_NOTE is returned.
+ * - in mono legato , prev_note is returned.
+ *
+ * On input
+ * @param chan fluid_channel_t.
+ * @param defaultFromkey, the defaut 'fromkey portamento' note or 'fromkey legato'
+ * note (see description above).
+ *
+ * @return
+ * 1)'fromkey portamento' is returned in fluid_synth_t.fromkey_portamento.
+ * If valid,it means that portamento is enabled .
+ *
+ * 2)The 'fromkey legato' note is returned.
+ *
+ * Notes about usage:
+ * The function is intended to be called when the following event occurs:
+ * - On noteOn (Poly or Mono) after insertion in the monophonic list.
+ * - On noteOff(mono legato playing). In this case, default_fromkey must be valid.
+ *
+ * Typical calling usage:
+ * - In poly, default_fromkey must be INVALID_NOTE.
+ * - In mono staccato playing,default_fromkey must be INVALID_NOTE.
+ * - In mono legato playing,default_fromkey must be valid.
+ */
+static char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t *chan,
+ int default_fromkey)
+{
+ unsigned char ptc = fluid_channel_get_cc(chan, PORTAMENTO_CTRL);
+
+ if(fluid_channel_is_valid_note(ptc))
+ {
+ /* CC PTC has been received */
+ fluid_channel_clear_portamento(chan); /* clears the CC PTC receive */
+ chan->synth->fromkey_portamento = ptc;/* returns fromkey portamento */
+
+ /* returns fromkey legato */
+ if(!fluid_channel_is_valid_note(default_fromkey))
+ {
+ default_fromkey = ptc;
+ }
+ }
+ else
+ {
+ /* determines and returns fromkey portamento */
+ unsigned char fromkey_portamento = INVALID_NOTE;
+
+ if(fluid_channel_portamento(chan))
+ {
+ /* Portamento when Portamento pedal is On */
+ /* 'fromkey portamento'is determined from the portamento mode
+ and the most recent note played (prev_note)*/
+ enum fluid_channel_portamento_mode portamentomode = chan->portamentomode;
+
+ if(fluid_channel_is_valid_note(default_fromkey))
+ {
+ fromkey_portamento = default_fromkey; /* on each note */
+ }
+ else
+ {
+ fromkey_portamento = fluid_channel_prev_note(chan); /* on each note */
+ }
+
+ if(portamentomode == FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY)
+ {
+ /* Mode portamento:legato only */
+ if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))
+ {
+ fromkey_portamento = INVALID_NOTE;
+ }
+ }
+ else if(portamentomode == FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY)
+ {
+ /* Mode portamento:staccato only */
+ if(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING)
+ {
+ fromkey_portamento = INVALID_NOTE;
+ }
+ }
+
+ /* else Mode portamento: on each note (staccato/legato) */
+ }
+
+ /* Returns fromkey portamento */
+ chan->synth->fromkey_portamento = fromkey_portamento;
+
+ /* Determines and returns fromkey legato */
+ if(!fluid_channel_is_valid_note(default_fromkey))
+ {
+ /* in staccato (poly/Mono) returns INVALID_NOTE */
+ /* In mono mode legato playing returns the note prior most
+ recent note played */
+ if(fluid_channel_is_playing_mono(chan) && (chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))
+ {
+ default_fromkey = fluid_channel_prev_note(chan); /* note prior last note */
+ }
+
+ /* In poly mode legato playing, actually we don't want playing legato.
+ So returns INVALID_NOTE */
+ }
+ }
+
+ return default_fromkey; /* Returns legato fromkey */
+}
+
+/*****************************************************************************
+ noteon - noteoff functions in Mono mode
+******************************************************************************/
+/*
+ * noteon - noteoff on a channel in "monophonic playing".
+ *
+ * A channel needs to be played monophonic if this channel has been set in
+ * monophonic mode by basic channel API.(see fluid_synth_polymono.c).
+ * A channel needs also to be played monophonic if it has been set in
+ * polyphonic mode and legato pedal is On during the playing.
+ * When a channel is in "monophonic playing" state, only one note at a time can be
+ * played in a staccato or legato manner (with or without portamento).
+ * More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
+ * _______________
+ * ________________ | noteon |
+ * | legato detector| O-->| mono_staccato |--*-> preset_noteon
+ * noteon_mono ->| (add_monolist) |--O-- |_______________| | (with or without)
+ * LOCAL |________________| O /|\ | (portamento)
+ * /|\ set_onenote | | fromkey |
+ * | | | portamento|
+ * noteOn poly >---*------------------* | |
+ * | | |
+ * | _____ |________ |
+ * portamento modes >--- | ->| | |
+ * | | get_fromkey | |
+ * Porta.on/off >--------------------- | ->|_______________| |
+ * (PTC) | | |
+ * | fromkey | fromkey |
+ * | legato | portamento|
+ * | _____\|/_______ |
+ * *-->| noteon |--/
+ * | | monopoly |
+ * | | legato |----> voices
+ * legato modes >------- | ->|_______________| triggering
+ * | (with or without)
+ * | (portamento)
+ * |
+ * |
+ * noteOff poly >---*----------------- | ---------+
+ * | clear | |
+ * _\|/_____________ | |
+ * | legato detector | O |
+ * noteoff_mono->|(search_monolist)|-O-- _____\|/_______
+ * LOCAL |(remove_monolist)| O-->| noteoff |
+ * |_________________| | monopoly |----> noteoff
+ * Sust.on/off >------------------------->|_______________|
+ * Sost.on/off
+------------------------------------------------------------------------------*/
+int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key,
+ char Mono);
+
+int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan,
+ int fromkey, int tokey, int vel);
+
+/**
+ * Plays a noteon event for a Synth instance in "monophonic playing" state.
+ * Please see the description above about "monophonic playing".
+ * _______________
+ * ________________ | noteon |
+ * | legato detector| O-->| mono_staccato |--->preset_noteon
+ * noteon_mono ->| (add_monolist) |--O-- |_______________|
+ * LOCAL |________________| O
+ * |
+ * |
+ * |
+ * |
+ * |
+ * |
+ * |
+ * |
+ * |
+ * | _______________
+ * | | noteon |
+ * +-->| monopoly |
+ * | legato |---> voices
+ * |_______________| triggering
+ *
+ * The function uses the legato detector (see above) to determine if the note must
+ * be played staccato or legato.
+ *
+ * @param synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param key MIDI note number (0-127).
+ * @param vel MIDI velocity (0-127).
+ * @return FLUID_OK on success, FLUID_FAILED otherwise.
+ */
+int fluid_synth_noteon_mono_LOCAL(fluid_synth_t *synth, int chan,
+ int key, int vel)
+{
+ fluid_channel_t *channel = synth->channel[chan];
+
+ /* Adds the note into the monophonic list */
+ fluid_channel_add_monolist(channel, key, vel, 0);
+
+ /* in Breath Sync mode, the noteon triggering is postponed
+ until the musician starts blowing in the breath controller */
+ if(!(channel->mode & FLUID_CHANNEL_BREATH_SYNC) ||
+ fluid_channel_breath_msb(channel))
+ {
+ /* legato/staccato playing detection */
+ if(channel->mode & FLUID_CHANNEL_LEGATO_PLAYING)
+ {
+ /* legato playing */
+ /* legato from prev_note to key */
+ /* the voices from prev_note key number are to be used to play key number */
+ /* fromkey must be valid */
+ return fluid_synth_noteon_monopoly_legato(synth, chan,
+ fluid_channel_prev_note(channel), key, vel);
+ }
+ else
+ {
+ /* staccato playing */
+ return fluid_synth_noteon_mono_staccato(synth, chan, key, vel);
+ }
+ }
+ else
+ {
+ return FLUID_OK;
+ }
+}
+
+/**
+ * Plays a noteoff event for a Synth instance in "monophonic playing" state.
+ * Please see the description above about "monophonic playing"
+ *
+ * _______________
+ * | noteon |
+ * +-->| monopoly |
+ * | | legato |----> voices
+ * | |_______________| triggering
+ * | (with or without)
+ * | (portamento)
+ * |
+ * |
+ * |
+ * |
+ * |
+ * |
+ * _________________ |
+ * | legato detector | O
+ * noteoff_mono->|(search_monolist)|-O-- _______________
+ * LOCAL |(remove_monolist)| O-->| noteoff |
+ * |_________________| | monopoly |----> noteoff
+ * |_______________|
+ *
+ * The function uses the legato detector (see above) to determine if the noteoff must
+ * be played staccato or legato.
+ *
+ * @param synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param key MIDI note number (0-127).
+ * @return FLUID_OK on success, FLUID_FAILED otherwise.
+ */
+int fluid_synth_noteoff_mono_LOCAL(fluid_synth_t *synth, int chan, int key)
+{
+ int status;
+ int i, i_prev;
+ fluid_channel_t *channel = synth->channel[chan];
+ /* searching the note in the monophonic list */
+ i = fluid_channel_search_monolist(channel, key, &i_prev);
+
+ if(i >= 0)
+ {
+ /* the note is in the monophonic list */
+ /* Removes the note from the monophonic list */
+ fluid_channel_remove_monolist(channel, i, &i_prev);
+
+ /* in Breath Sync mode, the noteoff triggering is done
+ if the musician is blowing in the breath controller */
+ if(!(channel->mode & FLUID_CHANNEL_BREATH_SYNC) ||
+ fluid_channel_breath_msb(channel))
+ {
+ /* legato playing detection */
+ if(channel->mode & FLUID_CHANNEL_LEGATO_PLAYING)
+ {
+ /* the list contains others notes */
+ if(i_prev >= 0)
+ {
+ /* legato playing detection on noteoff */
+ /* legato from key to i_prev key */
+ /* the voices from key number are to be used to
+ play i_prev key number. */
+ status = fluid_synth_noteon_monopoly_legato(synth, chan,
+ key, channel->monolist[i_prev].note,
+ channel->monolist[i_prev].vel);
+ }
+ /* else the note doesn't need to be played off */
+ else
+ {
+ status = FLUID_OK;
+ }
+ }
+ else
+ {
+ /* the monophonic list is empty */
+ /* plays the monophonic note noteoff and eventually held
+ by sustain/sostenuto */
+ status = fluid_synth_noteoff_monopoly(synth, chan, key, 1);
+ }
+ }
+ else
+ {
+ status = FLUID_OK;
+ }
+ }
+ else
+ {
+ /* the note is not found in the list so the note was
+ played On when the channel was in polyphonic playing */
+ /* plays the noteoff as for polyphonic */
+ status = fluid_synth_noteoff_monopoly(synth, chan, key, 0);
+ }
+
+ return status;
+}
+
+/*----------------------------------------------------------------------------
+ staccato playing
+-----------------------------------------------------------------------------*/
+/**
+ * Plays noteon for a monophonic note in staccato manner.
+ * Please see the description above about "monophonic playing".
+ * _______________
+ * | noteon |
+ * noteon_mono >------------------------>| mono_staccato |----> preset_noteon
+ * |_______________| (with or without)
+ * LOCAL /|\ (portamento)
+ * | fromkey
+ * | portamento
+ * |
+ * |
+ * ______|________
+ * portamento modes >----->| |
+ * | get_fromkey |
+ * Porta.on/off >----------------------->|_______________|
+ * Portamento
+ * (PTC)
+ *
+ * We are in staccato situation (where no previous note have been depressed).
+ * Before the note been passed to fluid_preset_noteon(), the function must determine
+ * the from_key_portamento parameter used by fluid_preset_noteon().
+ *
+ * from_key_portamento is returned by fluid_synth_get_fromkey_portamento_legato() function.
+ * fromkey_portamento is set to valid/invalid key value depending of the portamento
+ * modes (see portamento mode API) , CC portamento On/Off , and CC portamento control
+ * (PTC).
+ *
+ * @param synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param key MIDI note number (0-127).
+ * @param vel MIDI velocity (0-127).
+ * @return FLUID_OK on success, FLUID_FAILED otherwise.
+ */
+int
+fluid_synth_noteon_mono_staccato(fluid_synth_t *synth, int chan, int key, int vel)
+{
+ fluid_channel_t *channel = synth->channel[chan];
+
+ /* Before playing a new note, if a previous monophonic note is currently
+ sustained it needs to be released */
+ fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, channel->key_mono_sustained);
+ /* Get possible 'fromkey portamento' */
+ fluid_synth_get_fromkey_portamento_legato(channel, INVALID_NOTE);
+ /* The note needs to be played by voices allocation */
+ return fluid_preset_noteon(channel->preset, synth, chan, key, vel);
+}
+
+/**
+ * Plays noteoff for a polyphonic or monophonic note
+ * Please see the description above about "monophonic playing".
+ *
+ *
+ * noteOff poly >---------------------------------+
+ * |
+ * |
+ * |
+ * noteoff_mono _____\|/_______
+ * LOCAL >------------------------->| noteoff |
+ * | monopoly |----> noteoff
+ * Sust.on/off >------------------------->|_______________|
+ * Sost.on/off
+ *
+ * The function has the same behaviour when the noteoff is poly of mono, except
+ * that for mono noteoff, if any pedal (sustain or sostenuto ) is depressed, the
+ * key is memorized. This is neccessary when the next mono note will be played
+ * staccato, as any current mono note currently sustained will need to be released
+ * (see fluid_synth_noteon_mono_staccato()).
+ * Note also that for a monophonic legato passage, the function is called only when
+ * the last noteoff of the passage occurs. That means that if sustain or sostenuto
+ * is depressed, only the last note of a legato passage will be sustained.
+ *
+ * @param synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param key MIDI note number (0-127).
+ * @param Mono, 1 noteoff on monophonic note.
+ * 0 noteoff on polyphonic note.
+ * @return FLUID_OK on success, FLUID_FAILED otherwise.
+ *
+ * Note: On return, on monophonic, possible sustained note is memorized in
+ * key_mono_sustained. Memorization is done here on noteOff.
+ */
+int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key,
+ char Mono)
+{
+ int status = FLUID_FAILED;
+ fluid_voice_t *voice;
+ int i;
+ fluid_channel_t *channel = synth->channel[chan];
+
+ /* Key_sustained is prepared to return no note sustained (INVALID_NOTE) */
+ if(Mono)
+ {
+ channel->key_mono_sustained = INVALID_NOTE; /* no mono note sustained */
+ }
+
+ /* noteoff for all voices with same chan and same key */
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ voice = synth->voice[i];
+
+ if(fluid_voice_is_on(voice) &&
+ fluid_voice_get_channel(voice) == chan &&
+ fluid_voice_get_key(voice) == key)
+ {
+ if(synth->verbose)
+ {
+ int used_voices = 0;
+ int k;
+
+ for(k = 0; k < synth->polyphony; k++)
+ {
+ if(!_AVAILABLE(synth->voice[k]))
+ {
+ used_voices++;
+ }
+ }
+
+ FLUID_LOG(FLUID_INFO, "noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%d",
+ fluid_voice_get_channel(voice), fluid_voice_get_key(voice), 0,
+ fluid_voice_get_id(voice),
+ (fluid_curtime() - synth->start) / 1000.0f,
+ used_voices);
+ } /* if verbose */
+
+ fluid_voice_noteoff(voice);
+
+ /* noteoff on monophonic note */
+ /* Key memorization if the note is sustained */
+ if(Mono &&
+ (fluid_voice_is_sustained(voice) || fluid_voice_is_sostenuto(voice)))
+ {
+ channel->key_mono_sustained = key;
+ }
+
+ status = FLUID_OK;
+ } /* if voice on */
+ } /* for all voices */
+
+ return status;
+}
+
+/*----------------------------------------------------------------------------
+ legato playing
+-----------------------------------------------------------------------------*/
+/**
+ * Plays noteon for a monophonic note played legato.
+ * Please see the description above about "monophonic playing".
+ *
+ *
+ * _______________
+ * portamento modes >----->| |
+ * | get_fromkey |
+ * Porta.on/off >----------------------->|_______________|
+ * Portamento |
+ * (PTC) | +-->preset_noteon
+ * fromkey | fromkey | (with or without)
+ * legato | portamento| (portamento)
+ * _____\|/_______ |
+ * | noteon |--+
+ * noteon_mono >------------------------>| monopoly |
+ * LOCAL | legato |----->voices
+ * |_______________| triggering
+ * /|\ (with or without)
+ * | (portamento)
+ * legato modes >-----------------+
+ *
+ * We are in legato situation (where a previous note has been depressed).
+ * The function must determine the from_key_portamento and from_key_legato parameters
+ * used respectively by fluid_preset_noteon() function and voices triggering functions.
+ *
+ * from_key_portamento and from_key_legato are returned by
+ * fluid_synth_get_fromkey_portamento_legato() function.
+ * fromkey_portamento is set to valid/invalid key value depending of the portamento
+ * modes (see portamento mode API), CC portamento On/Off, and CC portamento control
+ * (PTC).
+ * Then, depending of the legato modes (see legato mode API), the function will call
+ * the appropriate triggering functions.
+ * @param synth instance.
+ * @param chan MIDI channel number (0 to MIDI channel count - 1).
+ * @param fromkey MIDI note number (0-127).
+ * @param tokey MIDI note number (0-127).
+ * @param vel MIDI velocity (0-127).
+ * @return FLUID_OK on success, FLUID_FAILED otherwise.
+ *
+ * Note: The voices with key 'fromkey' are to be used to play key 'tokey'.
+ * The function is able to play legato through Preset Zone(s) (PZ) and
+ * Instrument Zone(s) (IZ) as far as possible.
+ * When key tokey is outside the current Instrument Zone, Preset Zone,
+ * current 'fromkey' voices are released. If necessary new voices
+ * are restarted when tokey enters inside new Instrument(s) Zones,Preset Zone(s).
+ * More informations in FluidPolyMono-0004.pdf chapter 4.7 (Appendices).
+ */
+int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan,
+ int fromkey, int tokey, int vel)
+{
+ fluid_channel_t *channel = synth->channel[chan];
+ enum fluid_channel_legato_mode legatomode = channel->legatomode;
+ fluid_voice_t *voice;
+ int i ;
+ /* Gets possible 'fromkey portamento' and possible 'fromkey legato' note */
+ fromkey = fluid_synth_get_fromkey_portamento_legato(channel, fromkey);
+
+ if(fluid_channel_is_valid_note(fromkey))
+ {
+ for(i = 0; i < synth->polyphony; i++)
+ {
+ /* searching fromkey voices: only those who don't have 'note off' */
+ voice = synth->voice[i];
+
+ if(fluid_voice_is_on(voice) &&
+ fluid_voice_get_channel(voice) == chan &&
+ fluid_voice_get_key(voice) == fromkey)
+ {
+ fluid_zone_range_t *zone_range = voice->zone_range;
+
+ /* Ignores voice when there is no instrument zone (i.e no zone_range). Otherwise
+ checks if tokey is inside the range of the running voice */
+ if(zone_range && fluid_zone_inside_range(zone_range, tokey, vel))
+ {
+ switch(legatomode)
+ {
+ case FLUID_CHANNEL_LEGATO_MODE_RETRIGGER: /* mode 0 */
+ fluid_voice_release(voice); /* normal release */
+ break;
+
+ case FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER: /* mode 1 */
+ /* Skip in attack section */
+ fluid_voice_update_multi_retrigger_attack(voice, tokey, vel);
+
+ /* Starts portamento if enabled */
+ if(fluid_channel_is_valid_note(synth->fromkey_portamento))
+ {
+ /* Sends portamento parameters to the voice dsp */
+ fluid_voice_update_portamento(voice,
+ synth->fromkey_portamento,
+ tokey);
+ }
+
+ /* The voice is now used to play tokey in legato manner */
+ /* Marks this Instrument Zone to be ignored during next
+ fluid_preset_noteon() */
+ zone_range->ignore = TRUE;
+ break;
+
+ default: /* Invalid mode: this should never happen */
+ FLUID_LOG(FLUID_WARN, "Failed to execute legato mode: %d",
+ legatomode);
+ return FLUID_FAILED;
+ }
+ }
+ else
+ {
+ /* tokey note is outside the voice range, so the voice is released */
+ fluid_voice_release(voice);
+ }
+ }
+ }
+ }
+
+ /* May be,tokey will enter in new others Insrument Zone(s),Preset Zone(s), in
+ this case it needs to be played by voices allocation */
+ return fluid_preset_noteon(channel->preset, synth, chan, tokey, vel);
+}
diff --git a/libs/fluidsynth/src/fluid_sys.c b/libs/fluidsynth/src/fluid_sys.c
index 328f2556d6..c9662f7787 100644
--- a/libs/fluidsynth/src/fluid_sys.c
+++ b/libs/fluidsynth/src/fluid_sys.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -32,7 +32,13 @@
/* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
* Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
-#define WIN32_SOCKET_FLAG 0x40000000
+#ifdef _WIN32
+#define FLUID_SOCKET_FLAG 0x40000000
+#else
+#define FLUID_SOCKET_FLAG 0x00000000
+#define SOCKET_ERROR -1
+#define INVALID_SOCKET -1
+#endif
/* SCHED_FIFO priority for high priority timer threads */
#define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10
@@ -40,73 +46,47 @@
typedef struct
{
- fluid_thread_func_t func;
- void *data;
- int prio_level;
+ fluid_thread_func_t func;
+ void *data;
+ int prio_level;
} fluid_thread_info_t;
struct _fluid_timer_t
{
- long msec;
- fluid_timer_callback_t callback;
- void *data;
- fluid_thread_t *thread;
- int cont;
- int auto_destroy;
+ long msec;
+ fluid_timer_callback_t callback;
+ void *data;
+ fluid_thread_t *thread;
+ int cont;
+ int auto_destroy;
};
struct _fluid_server_socket_t
{
- fluid_socket_t socket;
- fluid_thread_t *thread;
- int cont;
- fluid_server_func_t func;
- void *data;
+ fluid_socket_t socket;
+ fluid_thread_t *thread;
+ int cont;
+ fluid_server_func_t func;
+ void *data;
};
-static int fluid_istream_gets(fluid_istream_t in, char* buf, int len);
+static int fluid_istream_gets(fluid_istream_t in, char *buf, int len);
static char fluid_errbuf[512]; /* buffer for error message */
-static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL];
-static void* fluid_log_user_data[LAST_LOG_LEVEL];
-static int fluid_log_initialized = 0;
-
-static char* fluid_libname = "fluidsynth";
-
-
-void fluid_sys_config()
-{
- fluid_log_config();
-}
-
-
-unsigned int fluid_debug_flags = 0;
-
-#if DEBUG
-/*
- * fluid_debug
- */
-int fluid_debug(int level, char * fmt, ...)
+static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] =
{
- if (fluid_debug_flags & level) {
- fluid_log_function_t fun;
- va_list args;
-
- va_start (args, fmt);
- vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
- va_end (args);
+ fluid_default_log_function,
+ fluid_default_log_function,
+ fluid_default_log_function,
+ fluid_default_log_function,
+ fluid_default_log_function
+};
+static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL };
- fun = fluid_log_function[FLUID_DBG];
- if (fun != NULL) {
- (*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]);
- }
- }
- return 0;
-}
-#endif
+static const char fluid_libname[] = "fluidsynth";
/**
* Installs a new log function for a specified log level.
@@ -116,16 +96,18 @@ int fluid_debug(int level, char * fmt, ...)
* @return The previously installed function.
*/
fluid_log_function_t
-fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
+fluid_set_log_function(int level, fluid_log_function_t fun, void *data)
{
- fluid_log_function_t old = NULL;
-
- if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
- old = fluid_log_function[level];
- fluid_log_function[level] = fun;
- fluid_log_user_data[level] = data;
- }
- return old;
+ fluid_log_function_t old = NULL;
+
+ if((level >= 0) && (level < LAST_LOG_LEVEL))
+ {
+ old = fluid_log_function[level];
+ fluid_log_function[level] = fun;
+ fluid_log_user_data[level] = data;
+ }
+
+ return old;
}
/**
@@ -135,75 +117,46 @@ fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
* @param data User supplied data (not used)
*/
void
-fluid_default_log_function(int level, char* message, void* data)
+fluid_default_log_function(int level, const char *message, void *data)
{
- FILE* out;
+ FILE *out;
#if defined(WIN32)
- out = stdout;
+ out = stdout;
#else
- out = stderr;
-#endif
-
- if (fluid_log_initialized == 0) {
- fluid_log_config();
- }
-
- switch (level) {
- case FLUID_PANIC:
- FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
- break;
- case FLUID_ERR:
- FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
- break;
- case FLUID_WARN:
- FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
- break;
- case FLUID_INFO:
- FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
- break;
- case FLUID_DBG:
-#if DEBUG
- FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
+ out = stderr;
#endif
- break;
- default:
- FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
- break;
- }
- fflush(out);
-}
-/*
- * fluid_init_log
- */
-void
-fluid_log_config(void)
-{
- if (fluid_log_initialized == 0) {
+ switch(level)
+ {
+ case FLUID_PANIC:
+ FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
+ break;
- fluid_log_initialized = 1;
+ case FLUID_ERR:
+ FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
+ break;
- if (fluid_log_function[FLUID_PANIC] == NULL) {
- fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL);
- }
+ case FLUID_WARN:
+ FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
+ break;
- if (fluid_log_function[FLUID_ERR] == NULL) {
- fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL);
- }
+ case FLUID_INFO:
+ FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
+ break;
- if (fluid_log_function[FLUID_WARN] == NULL) {
- fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL);
- }
+ case FLUID_DBG:
+#if DEBUG
+ FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
+#endif
+ break;
- if (fluid_log_function[FLUID_INFO] == NULL) {
- fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL);
+ default:
+ FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
+ break;
}
- if (fluid_log_function[FLUID_DBG] == NULL) {
- fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL);
- }
- }
+ fflush(out);
}
/**
@@ -214,22 +167,26 @@ fluid_log_config(void)
* @return Always returns #FLUID_FAILED
*/
int
-fluid_log(int level, const char* fmt, ...)
+fluid_log(int level, const char *fmt, ...)
{
- fluid_log_function_t fun = NULL;
+ fluid_log_function_t fun = NULL;
- va_list args;
- va_start (args, fmt);
- vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
- va_end (args);
+ va_list args;
+ va_start(args, fmt);
+ FLUID_VSNPRINTF(fluid_errbuf, sizeof(fluid_errbuf), fmt, args);
+ va_end(args);
- if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
- fun = fluid_log_function[level];
- if (fun != NULL) {
- (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
+ if((level >= 0) && (level < LAST_LOG_LEVEL))
+ {
+ fun = fluid_log_function[level];
+
+ if(fun != NULL)
+ {
+ (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
+ }
}
- }
- return FLUID_FAILED;
+
+ return FLUID_FAILED;
}
/**
@@ -245,70 +202,77 @@ fluid_log(int level, const char* fmt, ...)
* @param delim String of delimiter chars.
* @return Pointer to the next token or NULL if no more tokens.
*/
-char *fluid_strtok (char **str, char *delim)
+char *fluid_strtok(char **str, const char *delim)
{
- char *s, *d, *token;
- char c;
+ char *s, *token;
+ const char *d;
+ char c;
- if (str == NULL || delim == NULL || !*delim)
- {
- FLUID_LOG(FLUID_ERR, "Null pointer");
- return NULL;
- }
+ if(str == NULL || delim == NULL || !*delim)
+ {
+ FLUID_LOG(FLUID_ERR, "Null pointer");
+ return NULL;
+ }
- s = *str;
- if (!s) return NULL; /* str points to a NULL pointer? (tokenize already ended) */
+ s = *str;
- /* skip delimiter chars at beginning of token */
- do
- {
- c = *s;
- if (!c) /* end of source string? */
+ if(!s)
{
- *str = NULL;
- return NULL;
+ return NULL; /* str points to a NULL pointer? (tokenize already ended) */
}
- for (d = delim; *d; d++) /* is source char a token char? */
+ /* skip delimiter chars at beginning of token */
+ do
{
- if (c == *d) /* token char match? */
- {
- s++; /* advance to next source char */
- break;
- }
+ c = *s;
+
+ if(!c) /* end of source string? */
+ {
+ *str = NULL;
+ return NULL;
+ }
+
+ for(d = delim; *d; d++) /* is source char a token char? */
+ {
+ if(c == *d) /* token char match? */
+ {
+ s++; /* advance to next source char */
+ break;
+ }
+ }
}
- } while (*d); /* while token char match */
+ while(*d); /* while token char match */
- token = s; /* start of token found */
+ token = s; /* start of token found */
- /* search for next token char or end of source string */
- for (s = s+1; *s; s++)
- {
- c = *s;
-
- for (d = delim; *d; d++) /* is source char a token char? */
+ /* search for next token char or end of source string */
+ for(s = s + 1; *s; s++)
{
- if (c == *d) /* token char match? */
- {
- *s = '\0'; /* overwrite token char with zero byte to terminate token */
- *str = s+1; /* update str to point to beginning of next token */
- return token;
- }
+ c = *s;
+
+ for(d = delim; *d; d++) /* is source char a token char? */
+ {
+ if(c == *d) /* token char match? */
+ {
+ *s = '\0'; /* overwrite token char with zero byte to terminate token */
+ *str = s + 1; /* update str to point to beginning of next token */
+ return token;
+ }
+ }
}
- }
- /* we get here only if source string ended */
- *str = NULL;
- return token;
+ /* we get here only if source string ended */
+ *str = NULL;
+ return token;
}
/*
* fluid_error
*/
-char*
+char *
fluid_error()
{
- return fluid_errbuf;
+ return fluid_errbuf;
}
/**
@@ -322,19 +286,23 @@ fluid_error()
int
fluid_is_midifile(const char *filename)
{
- FILE* fp = fopen(filename, "rb");
- char id[4];
+ FILE *fp = fopen(filename, "rb");
+ char id[4];
+
+ if(fp == NULL)
+ {
+ return 0;
+ }
+
+ if(fread((void *) id, 1, 4, fp) != 4)
+ {
+ fclose(fp);
+ return 0;
+ }
- if (fp == NULL) {
- return 0;
- }
- if (fread((void*) id, 1, 4, fp) != 4) {
fclose(fp);
- return 0;
- }
- fclose(fp);
- return strncmp(id, "MThd", 4) == 0;
+ return FLUID_STRNCMP(id, "MThd", 4) == 0;
}
/**
@@ -342,25 +310,43 @@ fluid_is_midifile(const char *filename)
* @param filename Path to the file to check
* @return TRUE if it could be a SoundFont, FALSE otherwise
*
- * The current implementation only checks for the "RIFF" header in the file.
- * It is useful only to distinguish between SoundFont and MIDI files.
+ * @note The current implementation only checks for the "RIFF" and "sfbk" headers in
+ * the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
*/
int
fluid_is_soundfont(const char *filename)
{
- FILE* fp = fopen(filename, "rb");
- char id[4];
+ FILE *fp = fopen(filename, "rb");
+ char riff_id[4], sfbk_id[4];
+
+ if(fp == NULL)
+ {
+ return 0;
+ }
+
+ if((fread((void *) riff_id, 1, sizeof(riff_id), fp) != sizeof(riff_id)) ||
+ (fseek(fp, 4, SEEK_CUR) != 0) ||
+ (fread((void *) sfbk_id, 1, sizeof(sfbk_id), fp) != sizeof(sfbk_id)))
+ {
+ goto error_rec;
+ }
- if (fp == NULL) {
- return 0;
- }
- if (fread((void*) id, 1, 4, fp) != 4) {
+ fclose(fp);
+ return (FLUID_STRNCMP(riff_id, "RIFF", sizeof(riff_id)) == 0) &&
+ (FLUID_STRNCMP(sfbk_id, "sfbk", sizeof(sfbk_id)) == 0);
+
+error_rec:
fclose(fp);
return 0;
- }
- fclose(fp);
+}
- return strncmp(id, "RIFF", 4) == 0;
+/**
+ * Suspend the execution of the current thread for the specified amount of time.
+ * @param milliseconds to wait.
+ */
+void fluid_msleep(unsigned int msecs)
+{
+ g_usleep(msecs * 1000);
}
/**
@@ -369,78 +355,121 @@ fluid_is_soundfont(const char *filename)
*/
unsigned int fluid_curtime(void)
{
- static glong initial_seconds = 0;
- GTimeVal timeval;
+ static glong initial_seconds = 0;
+ GTimeVal timeval;
- if (initial_seconds == 0) {
- g_get_current_time (&timeval);
- initial_seconds = timeval.tv_sec;
- }
+ if(initial_seconds == 0)
+ {
+ g_get_current_time(&timeval);
+ initial_seconds = timeval.tv_sec;
+ }
- g_get_current_time (&timeval);
+ g_get_current_time(&timeval);
- return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
+ return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
}
/**
* Get time in microseconds to be used in relative timing operations.
- * @return Unix time in microseconds.
+ * @return time in microseconds.
+ * Note: When used for profiling we need high precision clock given
+ * by g_get_monotonic_time()if available (glib version >= 2.53.3).
+ * If glib version is too old and in the case of Windows the function
+ * uses high precision performance counter instead of g_getmonotic_time().
*/
double
-fluid_utime (void)
+fluid_utime(void)
{
- GTimeVal timeval;
+ double utime;
+
+#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 28
+ /* use high precision monotonic clock if available (g_monotonic_time().
+ * For Winfdows, if this clock is actually implemented as low prec. clock
+ * (i.e. in case glib is too old), high precision performance counter are
+ * used instead.
+ * see: https://bugzilla.gnome.org/show_bug.cgi?id=783340
+ */
+#if defined(WITH_PROFILING) && defined(WIN32) &&\
+ /* glib < 2.53.3 */\
+ (GLIB_MINOR_VERSION <= 53 && (GLIB_MINOR_VERSION < 53 || GLIB_MICRO_VERSION < 3))
+ /* use high precision performance counter. */
+ static LARGE_INTEGER freq_cache = {0, 0}; /* Performance Frequency */
+ LARGE_INTEGER perf_cpt;
+
+ if(! freq_cache.QuadPart)
+ {
+ QueryPerformanceFrequency(&freq_cache); /* Frequency value */
+ }
- g_get_current_time (&timeval);
+ QueryPerformanceCounter(&perf_cpt); /* Counter value */
+ utime = perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */
+#else
+ utime = g_get_monotonic_time();
+#endif
+#else
+ /* fallback to less precise clock */
+ GTimeVal timeval;
+ g_get_current_time(&timeval);
+ utime = (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
+#endif
- return (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
+ return utime;
}
+
#if defined(WIN32) /* Windoze specific stuff */
void
-fluid_thread_self_set_prio (int prio_level)
+fluid_thread_self_set_prio(int prio_level)
{
- if (prio_level > 0)
- SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+ if(prio_level > 0)
+ {
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+ }
}
#elif defined(__OS2__) /* OS/2 specific stuff */
void
-fluid_thread_self_set_prio (int prio_level)
+fluid_thread_self_set_prio(int prio_level)
{
- if (prio_level > 0)
- DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
+ if(prio_level > 0)
+ {
+ DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
+ }
}
#else /* POSIX stuff.. Nice POSIX.. Good POSIX. */
void
-fluid_thread_self_set_prio (int prio_level)
+fluid_thread_self_set_prio(int prio_level)
{
- struct sched_param priority;
+ struct sched_param priority;
- if (prio_level > 0)
- {
+ if(prio_level > 0)
+ {
- memset(&priority, 0, sizeof(priority));
- priority.sched_priority = prio_level;
+ memset(&priority, 0, sizeof(priority));
+ priority.sched_priority = prio_level;
+
+ if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority) == 0)
+ {
+ return;
+ }
- if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &priority) == 0) {
- return;
- }
#ifdef DBUS_SUPPORT
-/* Try to gain high priority via rtkit */
-
- if (fluid_rtkit_make_realtime(0, prio_level) == 0) {
- return;
- }
+ /* Try to gain high priority via rtkit */
+
+ if(fluid_rtkit_make_realtime(0, prio_level) == 0)
+ {
+ return;
+ }
+
#endif
- FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
- }
+ FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
+ }
}
#ifdef FPE_CHECK
@@ -480,34 +509,34 @@ fluid_thread_self_set_prio (int prio_level)
* Checks, if the floating point unit has produced an exception, print a message
* if so and clear the exception.
*/
-unsigned int fluid_check_fpe_i386(char* explanation)
+unsigned int fluid_check_fpe_i386(char *explanation)
{
- unsigned int s;
+ unsigned int s;
- _FPU_GET_SW(s);
- _FPU_CLR_SW();
+ _FPU_GET_SW(s);
+ _FPU_CLR_SW();
- s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
+ s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
- if (s)
- {
- FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
- (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
- (s & _FPU_STATUS_DE) ? "Denormal number " : "",
- (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
- (s & _FPU_STATUS_OE) ? "Overflow " : "",
- (s & _FPU_STATUS_UE) ? "Underflow " : "");
- }
+ if(s)
+ {
+ FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
+ (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
+ (s & _FPU_STATUS_DE) ? "Denormal number " : "",
+ (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
+ (s & _FPU_STATUS_OE) ? "Overflow " : "",
+ (s & _FPU_STATUS_UE) ? "Underflow " : "");
+ }
- return s;
+ return s;
}
/* Purpose:
* Clear floating point exception.
*/
-void fluid_clear_fpe_i386 (void)
+void fluid_clear_fpe_i386(void)
{
- _FPU_CLR_SW();
+ _FPU_CLR_SW();
}
#endif // ifdef FPE_CHECK
@@ -523,47 +552,409 @@ void fluid_clear_fpe_i386 (void)
*/
#if WITH_PROFILING
+/* Profiling interface beetween profiling command shell and audio rendering API
+ (FluidProfile_0004.pdf- 3.2.2).
+ Macros are in defined in fluid_sys.h.
+*/
-fluid_profile_data_t fluid_profile_data[] =
+/*
+ -----------------------------------------------------------------------------
+ Shell task side | Profiling interface | Audio task side
+ -----------------------------------------------------------------------------
+ profiling | Internal | | | Audio
+ command <---> |<-- profling -->| Data |<--macros -->| <--> rendering
+ shell | API | | | API
+
+*/
+/* default parameters for shell command "prof_start" in fluid_sys.c */
+unsigned short fluid_profile_notes = 0; /* number of generated notes */
+/* preset bank:0 prog:16 (organ) */
+unsigned char fluid_profile_bank = FLUID_PROFILE_DEFAULT_BANK;
+unsigned char fluid_profile_prog = FLUID_PROFILE_DEFAULT_PROG;
+
+/* print mode */
+unsigned char fluid_profile_print = FLUID_PROFILE_DEFAULT_PRINT;
+/* number of measures */
+unsigned short fluid_profile_n_prof = FLUID_PROFILE_DEFAULT_N_PROF;
+/* measure duration in ms */
+unsigned short fluid_profile_dur = FLUID_PROFILE_DEFAULT_DURATION;
+/* lock between multiple-shell */
+fluid_atomic_int_t fluid_profile_lock = 0;
+/**/
+
+/*----------------------------------------------
+ Profiling Data
+-----------------------------------------------*/
+unsigned char fluid_profile_status = PROFILE_STOP; /* command and status */
+unsigned int fluid_profile_end_ticks = 0; /* ending position (in ticks) */
+fluid_profile_data_t fluid_profile_data[] = /* Data duration */
{
- { FLUID_PROF_WRITE, "fluid_synth_write_* ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK, "fluid_synth_one_block ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_CLEAR, "fluid_synth_one_block:clear ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_VOICE, "fluid_synth_one_block:one voice ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_VOICES, "fluid_synth_one_block:all voices", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_REVERB, "fluid_synth_one_block:reverb ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_ONE_BLOCK_CHORUS, "fluid_synth_one_block:chorus ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_VOICE_NOTE, "fluid_voice:note ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_VOICE_RELEASE, "fluid_voice:release ", 1e10, 0.0, 0.0, 0},
- { FLUID_PROF_LAST, "last", 1e100, 0.0, 0.0, 0}
+ {"synth_write_* ------------>", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block ---------->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:clear ---->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:one voice->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:all voices>", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:reverb --->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"synth_one_block:chorus --->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"voice:note --------------->", 1e10, 0.0, 0.0, 0, 0, 0},
+ {"voice:release ------------>", 1e10, 0.0, 0.0, 0, 0, 0}
};
+/*----------------------------------------------
+ Internal profiling API
+-----------------------------------------------*/
+/* logging profiling data (used on synthesizer instance deletion) */
void fluid_profiling_print(void)
{
- int i;
+ int i;
- printf("fluid_profiling_print\n");
+ printf("fluid_profiling_print\n");
- FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
+ FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
- for (i = 0; i < FLUID_PROF_LAST; i++) {
- if (fluid_profile_data[i].count > 0) {
- FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
- fluid_profile_data[i].description,
- fluid_profile_data[i].min,
- fluid_profile_data[i].total / fluid_profile_data[i].count,
- fluid_profile_data[i].max);
- } else {
- FLUID_LOG(FLUID_DBG, "%s: no profiling available", fluid_profile_data[i].description);
+ for(i = 0; i < FLUID_PROFILE_NBR; i++)
+ {
+ if(fluid_profile_data[i].count > 0)
+ {
+ FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
+ fluid_profile_data[i].description,
+ fluid_profile_data[i].min,
+ fluid_profile_data[i].total / fluid_profile_data[i].count,
+ fluid_profile_data[i].max);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_DBG, "%s: no profiling available",
+ fluid_profile_data[i].description);
+ }
}
- }
}
+/* Macro that returns cpu load in percent (%)
+ * @dur: duration (micro second).
+ * @sample_rate: sample_rate used in audio driver (Hz).
+ * @n_amples: number of samples collected during 'dur' duration.
+*/
+#define fluid_profile_load(dur,sample_rate,n_samples) \
+ (dur * sample_rate / n_samples / 10000.0)
+
+
+/* prints cpu loads only
+*
+* @param sample_rate the sample rate of audio output.
+* @param out output stream device.
+*
+* ------------------------------------------------------------------------------
+* Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
+* ------------------------------------------------------------------------------
+* nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
+* -------|---------|---------|----------|---------|---------|-------------------
+* 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
+*/
+static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out)
+{
+ unsigned int n_voices; /* voices number */
+ static const char max_voices_not_available[] = " not available";
+ const char *pmax_voices;
+ char max_voices_available[20];
+
+ /* First computes data to be printed */
+ double total, voices, reverb, chorus, all_voices, voice;
+ /* voices number */
+ n_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_voices /
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count : 0;
+
+ /* total load (%) */
+ total = fluid_profile_data[FLUID_PROF_WRITE].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_WRITE].total, sample_rate,
+ fluid_profile_data[FLUID_PROF_WRITE].n_samples) : 0;
+
+ /* reverb load (%) */
+ reverb = fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].total,
+ sample_rate,
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].n_samples) : 0;
+
+ /* chorus load (%) */
+ chorus = fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].total,
+ sample_rate,
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].n_samples) : 0;
+
+ /* total voices load: total - reverb - chorus (%) */
+ voices = total - reverb - chorus;
+
+ /* One voice load (%): all_voices / n_voices. */
+ all_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
+ fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].total,
+ sample_rate,
+ fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_samples) : 0;
+
+ voice = n_voices ? all_voices / n_voices : 0;
+
+ /* estimated maximum voices number */
+ if(voice > 0)
+ {
+ FLUID_SNPRINTF(max_voices_available, sizeof(max_voices_available),
+ "%17d", (unsigned int)((100.0 - reverb - chorus) / voice));
+ pmax_voices = max_voices_available;
+ }
+ else
+ {
+ pmax_voices = max_voices_not_available;
+ }
-#endif /* WITH_PROFILING */
+ /* Now prints data */
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " Cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond) and maximum voices\n",
+ sample_rate, 1000000.0 / sample_rate);
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " nVoices| total(%%)|voices(%%)| reverb(%%)|chorus(%%)| voice(%%)|estimated maxVoices\n");
+ fluid_ostream_printf(out,
+ " -------|---------|---------|----------|---------|---------|-------------------\n");
+ fluid_ostream_printf(out,
+ "%8d|%9.3f|%9.3f|%10.3f|%9.3f|%9.3f|%s\n", n_voices, total, voices,
+ reverb, chorus, voice, pmax_voices);
+}
+
+/*
+* prints profiling data (used by profile shell command: prof_start).
+* The function is an internal profiling API between the "profile" command
+* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
+*
+* @param sample_rate the sample rate of audio output.
+* @param out output stream device.
+*
+* When print mode is 1, the function prints all the informations (see below).
+* When print mode is 0, the fonction prints only the cpu loads.
+*
+* ------------------------------------------------------------------------------
+* Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond)
+* ------------------------------------------------------------------------------
+* Code under profiling |Voices| Duration (microsecond) | Load(%)
+* | nbr| min| avg| max|
+* ---------------------------|------|--------------------------------|----------
+* synth_write_* ------------>| 250| 3.91| 2188.82| 3275.00| 41.544
+* synth_one_block ---------->| 250| 1150.70| 2273.56| 3241.47| 41.100
+* synth_one_block:clear ---->| 250| 3.07| 4.62| 61.18| 0.084
+* synth_one_block:one voice->| 1| 4.19| 9.02| 1044.27| 0.163
+* synth_one_block:all voices>| 250| 1138.41| 2259.11| 3217.73| 40.839
+* synth_one_block:reverb --->| no profiling available
+* synth_one_block:chorus --->| no profiling available
+* voice:note --------------->| no profiling available
+* voice:release ------------>| no profiling available
+* ------------------------------------------------------------------------------
+* Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
+* ------------------------------------------------------------------------------
+* nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
+* -------|---------|---------|----------|---------|---------|-------------------
+* 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612
+*/
+void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out)
+{
+ int i;
+
+ if(fluid_profile_print)
+ {
+ /* print all details: Duration(microsecond) and cpu loads(%) */
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " Duration(microsecond) and cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond)\n",
+ sample_rate, 1000000.0 / sample_rate);
+ fluid_ostream_printf(out,
+ " ------------------------------------------------------------------------------\n");
+ fluid_ostream_printf(out,
+ " Code under profiling |Voices| Duration (microsecond) | Load(%%)\n");
+ fluid_ostream_printf(out,
+ " | nbr| min| avg| max|\n");
+ fluid_ostream_printf(out,
+ " ---------------------------|------|--------------------------------|----------\n");
+
+ for(i = 0; i < FLUID_PROFILE_NBR; i++)
+ {
+ unsigned int count = fluid_profile_data[i].count;
+
+ if(count > 0)
+ {
+ /* data are available */
+
+ if(FLUID_PROF_WRITE <= i && i <= FLUID_PROF_ONE_BLOCK_CHORUS)
+ {
+ double load = fluid_profile_load(fluid_profile_data[i].total, sample_rate,
+ fluid_profile_data[i].n_samples);
+ fluid_ostream_printf(out, " %s|%6d|%10.2f|%10.2f|%10.2f|%8.3f\n",
+ fluid_profile_data[i].description, /* code under profiling */
+ fluid_profile_data[i].n_voices / count, /* voices number */
+ fluid_profile_data[i].min, /* minimum duration */
+ fluid_profile_data[i].total / count, /* average duration */
+ fluid_profile_data[i].max, /* maximum duration */
+ load); /* cpu load */
+ }
+ else
+ {
+ /* note and release duration */
+ fluid_ostream_printf(out, " %s|%6d|%10.0f|%10.0f|%10.0f|\n",
+ fluid_profile_data[i].description, /* code under profiling */
+ fluid_profile_data[i].n_voices / count,
+ fluid_profile_data[i].min, /* minimum duration */
+ fluid_profile_data[i].total / count, /* average duration */
+ fluid_profile_data[i].max); /* maximum duration */
+ }
+ }
+ else
+ {
+ /* data aren't available */
+ fluid_ostream_printf(out,
+ " %s| no profiling available\n", fluid_profile_data[i].description);
+ }
+ }
+ }
+
+ /* prints cpu loads only */
+ fluid_profiling_print_load(sample_rate, out);/* prints cpu loads */
+}
+
+/*
+ Returns true if the user cancels the current profiling measurement.
+ Actually this is implemented using the <ENTER> key. To add this functionality:
+ 1) Adds #define FLUID_PROFILE_CANCEL in fluid_sys.h.
+ 2) Adds the necessary code inside fluid_profile_is_cancel().
+
+ When FLUID_PROFILE_CANCEL is not defined, the function return FALSE.
+*/
+int fluid_profile_is_cancel_req(void)
+{
+#ifdef FLUID_PROFILE_CANCEL
+
+#if defined(WIN32) /* Windows specific stuff */
+ /* Profile cancellation is supported for Windows */
+ /* returns TRUE if key <ENTER> is depressed */
+ return(GetAsyncKeyState(VK_RETURN) & 0x1);
+
+#elif defined(__OS2__) /* OS/2 specific stuff */
+ /* Profile cancellation isn't yet supported for OS2 */
+ /* For OS2, replaces the following line with the function that returns
+ true when the keyboard key <ENTER> is depressed */
+ return FALSE; /* default value */
+
+#else /* POSIX stuff */
+ /* Profile cancellation is supported for Linux */
+ /* returns true is <ENTER> is depressed */
+ {
+ /* Here select() is used to poll the standard input to see if an input
+ is ready. As the standard input is usually buffered, the user
+ needs to depress <ENTER> to set the input to a "ready" state.
+ */
+ struct timeval tv;
+ fd_set fds; /* just one fds need to be polled */
+ tv.tv_sec = 0; /* Setting both values to 0, means a 0 timeout */
+ tv.tv_usec = 0;
+ FD_ZERO(&fds); /* reset fds */
+ FD_SET(STDIN_FILENO, &fds); /* sets fds to poll standard input only */
+ select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); /* polling */
+ return (FD_ISSET(0, &fds)); /* returns true if standard input is ready */
+ }
+#endif /* OS stuff */
+
+#else /* FLUID_PROFILE_CANCEL not defined */
+ return FALSE; /* default value */
+#endif /* FLUID_PROFILE_CANCEL */
+}
+/**
+* Returns status used in shell command "prof_start".
+* The function is an internal profiling API between the "profile" command
+* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
+*
+* @return status
+* - PROFILE_READY profiling data are ready.
+* - PROFILE_RUNNING, profiling data are still under acquisition.
+* - PROFILE_CANCELED, acquisition has been cancelled by the user.
+* - PROFILE_STOP, no acquisition in progress.
+*
+* When status is PROFILE_RUNNING, the caller can do passive waiting, or other
+* work before recalling the function later.
+*/
+int fluid_profile_get_status(void)
+{
+ /* Checks if user has requested to cancel the current measurement */
+ /* Cancellation must have precedence over other status */
+ if(fluid_profile_is_cancel_req())
+ {
+ fluid_profile_start_stop(0, 0); /* stops the measurement */
+ return PROFILE_CANCELED;
+ }
+
+ switch(fluid_profile_status)
+ {
+ case PROFILE_READY:
+ return PROFILE_READY; /* profiling data are ready */
+
+ case PROFILE_START:
+ return PROFILE_RUNNING;/* profiling data are under acquisition */
+
+ default:
+ return PROFILE_STOP;
+ }
+}
+/**
+* Starts or stops profiling measurement.
+* The function is an internal profiling API between the "profile" command
+* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
+*
+* @param end_tick end position of the measure (in ticks).
+* - If end_tick is greater then 0, the function starts a measure if a measure
+* isn't running. If a measure is already running, the function does nothing
+* and returns.
+* - If end_tick is 0, the function stops a measure.
+* @param clear_data,
+* - If clear_data is 0, the function clears fluid_profile_data before starting
+* a measure, otherwise, the data from the started measure will be accumulated
+* within fluid_profile_data.
+*/
+void fluid_profile_start_stop(unsigned int end_ticks, short clear_data)
+{
+ if(end_ticks) /* This is a "start" request */
+ {
+ /* Checks if a measure is already running */
+ if(fluid_profile_status != PROFILE_START)
+ {
+ short i;
+ fluid_profile_end_ticks = end_ticks;
+
+ /* Clears profile data */
+ if(clear_data == 0)
+ for(i = 0; i < FLUID_PROFILE_NBR; i++)
+ {
+ fluid_profile_data[i].min = 1e10;/* min sets to max value */
+ fluid_profile_data[i].max = 0; /* maximum sets to min value */
+ fluid_profile_data[i].total = 0; /* total duration microsecond */
+ fluid_profile_data[i].count = 0; /* data count */
+ fluid_profile_data[i].n_voices = 0; /* voices number */
+ fluid_profile_data[i].n_samples = 0;/* audio samples number */
+ }
+
+ fluid_profile_status = PROFILE_START; /* starts profiling */
+ }
+
+ /* else do nothing when profiling is already started */
+ }
+ else /* This is a "stop" request */
+ {
+ /* forces the current running profile (if any) to stop */
+ fluid_profile_status = PROFILE_STOP; /* stops profiling */
+ }
+}
+
+#endif /* WITH_PROFILING */
/***************************************************************
*
@@ -576,25 +967,29 @@ void fluid_profiling_print(void)
/* Rather than inline this one, we just declare it as a function, to prevent
* GCC warning about inline failure. */
fluid_cond_t *
-new_fluid_cond (void)
+new_fluid_cond(void)
{
- if (!g_thread_supported ()) g_thread_init (NULL);
- return g_cond_new ();
+ if(!g_thread_supported())
+ {
+ g_thread_init(NULL);
+ }
+
+ return g_cond_new();
}
#endif
static gpointer
-fluid_thread_high_prio (gpointer data)
+fluid_thread_high_prio(gpointer data)
{
- fluid_thread_info_t *info = data;
+ fluid_thread_info_t *info = data;
- fluid_thread_self_set_prio (info->prio_level);
+ fluid_thread_self_set_prio(info->prio_level);
- info->func (info->data);
- FLUID_FREE (info);
+ info->func(info->data);
+ FLUID_FREE(info);
- return NULL;
+ return NULL;
}
/**
@@ -607,59 +1002,78 @@ fluid_thread_high_prio (gpointer data)
* @return New thread pointer or NULL on error
*/
fluid_thread_t *
-new_fluid_thread (const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
+new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
{
- GThread *thread;
- fluid_thread_info_t *info;
- GError *err = NULL;
+ GThread *thread;
+ fluid_thread_info_t *info;
+ GError *err = NULL;
- g_return_val_if_fail (func != NULL, NULL);
+ g_return_val_if_fail(func != NULL, NULL);
#if OLD_GLIB_THREAD_API
- /* Make sure g_thread_init has been called.
- * FIXME - Probably not a good idea in a shared library,
- * but what can we do *and* remain backwards compatible? */
- if (!g_thread_supported ()) g_thread_init (NULL);
-#endif
-
- if (prio_level > 0)
- {
- info = FLUID_NEW (fluid_thread_info_t);
- if (!info)
+ /* Make sure g_thread_init has been called.
+ * FIXME - Probably not a good idea in a shared library,
+ * but what can we do *and* remain backwards compatible? */
+ if(!g_thread_supported())
{
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
+ g_thread_init(NULL);
}
- info->func = func;
- info->data = data;
- info->prio_level = prio_level;
+#endif
+
+ if(prio_level > 0)
+ {
+ info = FLUID_NEW(fluid_thread_info_t);
+
+ if(!info)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ info->func = func;
+ info->data = data;
+ info->prio_level = prio_level;
#if NEW_GLIB_THREAD_API
- thread = g_thread_try_new (name, fluid_thread_high_prio, info, &err);
+ thread = g_thread_try_new(name, fluid_thread_high_prio, info, &err);
#else
- thread = g_thread_create (fluid_thread_high_prio, info, detach == FALSE, &err);
+ thread = g_thread_create(fluid_thread_high_prio, info, detach == FALSE, &err);
#endif
- }
+ }
+
#if NEW_GLIB_THREAD_API
- else thread = g_thread_try_new (name, (GThreadFunc)func, data, &err);
+ else
+ {
+ thread = g_thread_try_new(name, (GThreadFunc)func, data, &err);
+ }
+
#else
- else thread = g_thread_create ((GThreadFunc)func, data, detach == FALSE, &err);
+ else
+ {
+ thread = g_thread_create((GThreadFunc)func, data, detach == FALSE, &err);
+ }
+
#endif
- if (!thread)
- {
- FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
- fluid_gerror_message (err));
- g_clear_error (&err);
- return NULL;
- }
+ if(!thread)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
+ fluid_gerror_message(err));
+ g_clear_error(&err);
+ return NULL;
+ }
#if NEW_GLIB_THREAD_API
- if (detach) g_thread_unref (thread); // Release thread reference, if caller wants to detach
+
+ if(detach)
+ {
+ g_thread_unref(thread); // Release thread reference, if caller wants to detach
+ }
+
#endif
- return thread;
+ return thread;
}
/**
@@ -667,9 +1081,9 @@ new_fluid_thread (const char *name, fluid_thread_func_t func, void *data, int pr
* @param thread Thread to free
*/
void
-delete_fluid_thread(fluid_thread_t* thread)
+delete_fluid_thread(fluid_thread_t *thread)
{
- /* Threads free themselves when they quit, nothing to do */
+ /* Threads free themselves when they quit, nothing to do */
}
/**
@@ -678,115 +1092,142 @@ delete_fluid_thread(fluid_thread_t* thread)
* @return FLUID_OK
*/
int
-fluid_thread_join(fluid_thread_t* thread)
+fluid_thread_join(fluid_thread_t *thread)
{
- g_thread_join (thread);
+ g_thread_join(thread);
- return FLUID_OK;
+ return FLUID_OK;
}
-static void
-fluid_timer_run (void *data)
+static fluid_thread_return_t
+fluid_timer_run(void *data)
{
- fluid_timer_t *timer;
- int count = 0;
- int cont;
- long start;
- long delay;
+ fluid_timer_t *timer;
+ int count = 0;
+ int cont;
+ long start;
+ long delay;
+
+ timer = (fluid_timer_t *)data;
+
+ /* keep track of the start time for absolute positioning */
+ start = fluid_curtime();
- timer = (fluid_timer_t *)data;
+ while(timer->cont)
+ {
+ cont = (*timer->callback)(timer->data, fluid_curtime() - start);
- /* keep track of the start time for absolute positioning */
- start = fluid_curtime ();
+ count++;
- while (timer->cont)
- {
- cont = (*timer->callback)(timer->data, fluid_curtime() - start);
+ if(!cont)
+ {
+ break;
+ }
- count++;
- if (!cont) break;
+ /* to avoid incremental time errors, calculate the delay between
+ two callbacks bringing in the "absolute" time (count *
+ timer->msec) */
+ delay = (count * timer->msec) - (fluid_curtime() - start);
- /* to avoid incremental time errors, calculate the delay between
- two callbacks bringing in the "absolute" time (count *
- timer->msec) */
- delay = (count * timer->msec) - (fluid_curtime() - start);
- if (delay > 0) g_usleep (delay * 1000);
- }
+ if(delay > 0)
+ {
+ fluid_msleep(delay);
+ }
+ }
- FLUID_LOG (FLUID_DBG, "Timer thread finished");
+ FLUID_LOG(FLUID_DBG, "Timer thread finished");
- if (timer->auto_destroy)
- FLUID_FREE (timer);
+ if(timer->auto_destroy)
+ {
+ FLUID_FREE(timer);
+ }
- return;
+ return FLUID_THREAD_RETURN_VALUE;
}
-fluid_timer_t*
-new_fluid_timer (int msec, fluid_timer_callback_t callback, void* data,
- int new_thread, int auto_destroy, int high_priority)
+fluid_timer_t *
+new_fluid_timer(int msec, fluid_timer_callback_t callback, void *data,
+ int new_thread, int auto_destroy, int high_priority)
{
- fluid_timer_t *timer;
+ fluid_timer_t *timer;
- timer = FLUID_NEW (fluid_timer_t);
+ timer = FLUID_NEW(fluid_timer_t);
- if (timer == NULL)
- {
- FLUID_LOG (FLUID_ERR, "Out of memory");
- return NULL;
- }
-
- timer->msec = msec;
- timer->callback = callback;
- timer->data = data;
- timer->cont = TRUE ;
- timer->thread = NULL;
- timer->auto_destroy = auto_destroy;
-
- if (new_thread)
- {
- timer->thread = new_fluid_thread ("timer", fluid_timer_run, timer, high_priority
- ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
- if (!timer->thread)
+ if(timer == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ timer->msec = msec;
+ timer->callback = callback;
+ timer->data = data;
+ timer->cont = TRUE ;
+ timer->thread = NULL;
+ timer->auto_destroy = auto_destroy;
+
+ if(new_thread)
+ {
+ timer->thread = new_fluid_thread("timer", fluid_timer_run, timer, high_priority
+ ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
+
+ if(!timer->thread)
+ {
+ FLUID_FREE(timer);
+ return NULL;
+ }
+ }
+ else
{
- FLUID_FREE (timer);
- return NULL;
+ fluid_timer_run(timer); /* Run directly, instead of as a separate thread */
+
+ if(auto_destroy)
+ {
+ /* do NOT return freed memory */
+ return NULL;
+ }
}
- }
- else fluid_timer_run (timer); /* Run directly, instead of as a separate thread */
- return timer;
+ return timer;
}
-int
-delete_fluid_timer (fluid_timer_t *timer)
+void
+delete_fluid_timer(fluid_timer_t *timer)
{
- int auto_destroy = timer->auto_destroy;
+ int auto_destroy;
+ fluid_return_if_fail(timer != NULL);
- timer->cont = 0;
- fluid_timer_join (timer);
+ auto_destroy = timer->auto_destroy;
- /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
+ timer->cont = 0;
+ fluid_timer_join(timer);
- if (!auto_destroy) FLUID_FREE (timer);
+ /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
- return FLUID_OK;
+ if(!auto_destroy)
+ {
+ FLUID_FREE(timer);
+ }
}
int
-fluid_timer_join (fluid_timer_t *timer)
+fluid_timer_join(fluid_timer_t *timer)
{
- int auto_destroy;
+ int auto_destroy;
- if (timer->thread)
- {
- auto_destroy = timer->auto_destroy;
- fluid_thread_join (timer->thread);
+ if(timer->thread)
+ {
+ auto_destroy = timer->auto_destroy;
+ fluid_thread_join(timer->thread);
- if (!auto_destroy) timer->thread = NULL;
- }
+ if(!auto_destroy)
+ {
+ timer->thread = NULL;
+ }
+ }
- return FLUID_OK;
+ return FLUID_OK;
}
@@ -801,9 +1242,9 @@ fluid_timer_join (fluid_timer_t *timer)
* @return Standard in stream.
*/
fluid_istream_t
-fluid_get_stdin (void)
+fluid_get_stdin(void)
{
- return STDIN_FILENO;
+ return STDIN_FILENO;
}
/**
@@ -811,9 +1252,9 @@ fluid_get_stdin (void)
* @return Standard out stream.
*/
fluid_ostream_t
-fluid_get_stdout (void)
+fluid_get_stdout(void)
{
- return STDOUT_FILENO;
+ return STDOUT_FILENO;
}
/**
@@ -821,31 +1262,34 @@ fluid_get_stdout (void)
* @return 0 if end-of-stream, -1 if error, non zero otherwise
*/
int
-fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
- char* buf, int len)
+fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt,
+ char *buf, int len)
{
#if WITH_READLINE
- if (in == fluid_get_stdin ())
- {
- char *line;
- line = readline (prompt);
+ if(in == fluid_get_stdin())
+ {
+ char *line;
- if (line == NULL)
- return -1;
+ line = readline(prompt);
- snprintf(buf, len, "%s", line);
- buf[len - 1] = 0;
+ if(line == NULL)
+ {
+ return -1;
+ }
- free(line);
- return 1;
- }
- else
+ FLUID_SNPRINTF(buf, len, "%s", line);
+ buf[len - 1] = 0;
+
+ free(line);
+ return 1;
+ }
+ else
#endif
- {
- fluid_ostream_printf (out, "%s", prompt);
- return fluid_istream_gets (in, buf, len);
- }
+ {
+ fluid_ostream_printf(out, "%s", prompt);
+ return fluid_istream_gets(in, buf, len);
+ }
}
/**
@@ -856,49 +1300,67 @@ fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
* @return 1 if a line was read, 0 on end of stream, -1 on error
*/
static int
-fluid_istream_gets (fluid_istream_t in, char* buf, int len)
+fluid_istream_gets(fluid_istream_t in, char *buf, int len)
{
- char c;
- int n;
+ char c;
+ int n;
- buf[len - 1] = 0;
+ buf[len - 1] = 0;
- while (--len > 0)
- {
+ while(--len > 0)
+ {
#ifndef WIN32
- n = read(in, &c, 1);
- if (n == -1) return -1;
+ n = read(in, &c, 1);
+
+ if(n == -1)
+ {
+ return -1;
+ }
+
#else
- /* Handle read differently depending on if its a socket or file descriptor */
- if (!(in & WIN32_SOCKET_FLAG))
- {
- n = read(in, &c, 1);
- if (n == -1) return -1;
- }
- else
- {
- n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0);
- if (n == SOCKET_ERROR) return -1;
- }
-#endif
- if (n == 0)
- {
- *buf++ = 0;
- return 0;
- }
+ /* Handle read differently depending on if its a socket or file descriptor */
+ if(!(in & FLUID_SOCKET_FLAG))
+ {
+ n = read(in, &c, 1);
+
+ if(n == -1)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0);
+
+ if(n == SOCKET_ERROR)
+ {
+ return -1;
+ }
+ }
- if ((c == '\n'))
- {
- *buf++ = 0;
- return 1;
- }
+#endif
- /* Store all characters excluding CR */
- if (c != '\r') *buf++ = c;
- }
+ if(n == 0)
+ {
+ *buf = 0;
+ return 0;
+ }
+
+ if(c == '\n')
+ {
+ *buf = 0;
+ return 1;
+ }
+
+ /* Store all characters excluding CR */
+ if(c != '\r')
+ {
+ *buf++ = c;
+ }
+ }
- return -1;
+ return -1;
}
/**
@@ -909,390 +1371,297 @@ fluid_istream_gets (fluid_istream_t in, char* buf, int len)
* @return Number of bytes written or -1 on error
*/
int
-fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
+fluid_ostream_printf(fluid_ostream_t out, const char *format, ...)
{
- char buf[4096];
- va_list args;
- int len;
+ char buf[4096];
+ va_list args;
+ int len;
- va_start (args, format);
- len = vsnprintf (buf, 4095, format, args);
- va_end (args);
+ va_start(args, format);
+ len = FLUID_VSNPRINTF(buf, 4095, format, args);
+ va_end(args);
- if (len == 0)
- {
- return 0;
- }
+ if(len == 0)
+ {
+ return 0;
+ }
- if (len < 0)
- {
- printf("fluid_ostream_printf: buffer overflow");
- return -1;
- }
+ if(len < 0)
+ {
+ printf("fluid_ostream_printf: buffer overflow");
+ return -1;
+ }
- buf[4095] = 0;
+ buf[4095] = 0;
#ifndef WIN32
- return write (out, buf, strlen (buf));
+ return write(out, buf, FLUID_STRLEN(buf));
#else
- {
- int retval;
+ {
+ int retval;
- /* Handle write differently depending on if its a socket or file descriptor */
- if (!(out & WIN32_SOCKET_FLAG))
- return write(out, buf, strlen (buf));
+ /* Handle write differently depending on if its a socket or file descriptor */
+ if(!(out & FLUID_SOCKET_FLAG))
+ {
+ return write(out, buf, FLUID_STRLEN(buf));
+ }
- /* Socket */
- retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0);
+ /* Socket */
+ retval = send(out & ~FLUID_SOCKET_FLAG, buf, FLUID_STRLEN(buf), 0);
- return retval != SOCKET_ERROR ? retval : -1;
- }
+ return retval != SOCKET_ERROR ? retval : -1;
+ }
#endif
}
-#if 0 // Ardour says: no, thanks
+#ifdef NETWORK_SUPPORT
+
int fluid_server_socket_join(fluid_server_socket_t *server_socket)
{
- return fluid_thread_join (server_socket->thread);
+ return fluid_thread_join(server_socket->thread);
}
+static int fluid_socket_init(void)
+{
+#ifdef _WIN32
+ WSADATA wsaData;
+ int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
-#ifndef WIN32 // Not win32?
-
-#define SOCKET_ERROR -1
+ if(res != 0)
+ {
+ FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res);
+ return FLUID_FAILED;
+ }
-fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
-{
- return sock;
-}
+#endif
-fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
-{
- return sock;
+ return FLUID_OK;
}
-void fluid_socket_close(fluid_socket_t sock)
+static void fluid_socket_cleanup(void)
{
- if (sock != INVALID_SOCKET)
- close (sock);
+#ifdef _WIN32
+ WSACleanup();
+#endif
}
-static void
-fluid_server_socket_run (void *data)
+static int fluid_socket_get_error(void)
{
- fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
- fluid_socket_t client_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
- char straddr[INET6_ADDRSTRLEN];
+#ifdef _WIN32
+ return (int)WSAGetLastError();
#else
- struct sockaddr_in addr;
- char straddr[INET_ADDRSTRLEN];
+ return errno;
#endif
- socklen_t addrlen = sizeof (addr);
- int retval;
- FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
-
- FLUID_LOG (FLUID_DBG, "Server listening for connections");
+}
- while (server_socket->cont)
- {
- client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
+fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
+{
+ return sock | FLUID_SOCKET_FLAG;
+}
- FLUID_LOG (FLUID_DBG, "New client connection");
+fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
+{
+ return sock | FLUID_SOCKET_FLAG;
+}
- if (client_socket == INVALID_SOCKET)
+void fluid_socket_close(fluid_socket_t sock)
+{
+ if(sock != INVALID_SOCKET)
{
- if (server_socket->cont)
- FLUID_LOG(FLUID_ERR, "Failed to accept connection");
-
- server_socket->cont = 0;
- return;
- } else {
-#ifdef IPV6
- inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
+#ifdef _WIN32
+ closesocket(sock);
+
#else
- inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
+ close(sock);
#endif
- retval = server_socket->func (server_socket->data, client_socket,
- straddr);
-
- if (retval != 0)
- fluid_socket_close(client_socket);
}
- }
-
- FLUID_LOG(FLUID_DBG, "Server closing");
}
-fluid_server_socket_t*
-new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
+static fluid_thread_return_t fluid_server_socket_run(void *data)
{
- fluid_server_socket_t* server_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
+ fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
+ fluid_socket_t client_socket;
+#ifdef IPV6_SUPPORT
+ struct sockaddr_in6 addr;
#else
- struct sockaddr_in addr;
+ struct sockaddr_in addr;
#endif
- fluid_socket_t sock;
-
- g_return_val_if_fail (func != NULL, NULL);
-#ifdef IPV6
- sock = socket(AF_INET6, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- FLUID_LOG(FLUID_ERR, "Failed to create server socket");
- return NULL;
- }
- FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in6));
- addr.sin6_family = AF_INET6;
- addr.sin6_addr = in6addr_any;
- addr.sin6_port = htons(port);
+#ifdef HAVE_INETNTOP
+#ifdef IPV6_SUPPORT
+ char straddr[INET6_ADDRSTRLEN];
#else
+ char straddr[INET_ADDRSTRLEN];
+#endif /* IPV6_SUPPORT */
+#endif /* HAVE_INETNTOP */
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- FLUID_LOG(FLUID_ERR, "Failed to create server socket");
- return NULL;
- }
-
- FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = htons(port);
-#endif
- if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
- FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
- fluid_socket_close(sock);
- return NULL;
- }
-
- if (listen(sock, 10) == SOCKET_ERROR) {
- FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
- fluid_socket_close(sock);
- return NULL;
- }
-
- server_socket = FLUID_NEW(fluid_server_socket_t);
- if (server_socket == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- fluid_socket_close(sock);
- return NULL;
- }
+ socklen_t addrlen = sizeof(addr);
+ int r;
+ FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
- server_socket->socket = sock;
- server_socket->func = func;
- server_socket->data = data;
- server_socket->cont = 1;
-
- server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
- 0, FALSE);
- if (server_socket->thread == NULL) {
- FLUID_FREE(server_socket);
- fluid_socket_close(sock);
- return NULL;
- }
-
- return server_socket;
-}
-
-int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
-{
- server_socket->cont = 0;
- if (server_socket->socket != INVALID_SOCKET) {
- fluid_socket_close(server_socket->socket);
- }
- if (server_socket->thread) {
- delete_fluid_thread(server_socket->thread);
- }
- FLUID_FREE(server_socket);
- return FLUID_OK;
-}
-
-
-#else // Win32 is "special"
+ FLUID_LOG(FLUID_DBG, "Server listening for connections");
+ while(server_socket->cont)
+ {
+ client_socket = accept(server_socket->socket, (struct sockaddr *)&addr, &addrlen);
+
+ FLUID_LOG(FLUID_DBG, "New client connection");
+
+ if(client_socket == INVALID_SOCKET)
+ {
+ if(server_socket->cont)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
+ }
+
+ server_socket->cont = 0;
+ return FLUID_THREAD_RETURN_VALUE;
+ }
+ else
+ {
+#ifdef HAVE_INETNTOP
+
+#ifdef IPV6_SUPPORT
+ inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
+#else
+ inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
+#endif
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
+ r = server_socket->func(server_socket->data, client_socket,
+ straddr);
+#else
+ r = server_socket->func(server_socket->data, client_socket,
+ inet_ntoa(addr.sin_addr));
#endif
-fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
-{
- return sock | WIN32_SOCKET_FLAG;
-}
+ if(r != 0)
+ {
+ fluid_socket_close(client_socket);
+ }
+ }
+ }
-fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
-{
- return sock | WIN32_SOCKET_FLAG;
-}
+ FLUID_LOG(FLUID_DBG, "Server closing");
-void fluid_socket_close (fluid_socket_t sock)
-{
- if (sock != INVALID_SOCKET)
- closesocket (sock);
+ return FLUID_THREAD_RETURN_VALUE;
}
-static void fluid_server_socket_run (void *data)
+fluid_server_socket_t *
+new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
{
- fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
- fluid_socket_t client_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
- char straddr[INET6_ADDRSTRLEN];
+ fluid_server_socket_t *server_socket;
+#ifdef IPV6_SUPPORT
+ struct sockaddr_in6 addr;
#else
- struct sockaddr_in addr;
- char straddr[INET_ADDRSTRLEN];
+ struct sockaddr_in addr;
#endif
- socklen_t addrlen = sizeof (addr);
- int r;
- FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
- FLUID_LOG(FLUID_DBG, "Server listening for connections");
+ fluid_socket_t sock;
- while (server_socket->cont)
- {
- client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
+ fluid_return_val_if_fail(func != NULL, NULL);
- FLUID_LOG (FLUID_DBG, "New client connection");
-
- if (client_socket == INVALID_SOCKET)
+ if(fluid_socket_init() != FLUID_OK)
{
- if (server_socket->cont)
- FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", WSAGetLastError ());
-
- server_socket->cont = 0;
- return;
+ return NULL;
}
- else
+
+#ifdef IPV6_SUPPORT
+ sock = socket(AF_INET6, SOCK_STREAM, 0);
+
+ if(sock == INVALID_SOCKET)
{
-#ifdef IPV6
- inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
-#else
- inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
-#endif
- r = server_socket->func (server_socket->data, client_socket,
- straddr);
- if (r != 0)
- fluid_socket_close (client_socket);
+ FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
+ fluid_socket_cleanup();
+ return NULL;
}
- }
- FLUID_LOG (FLUID_DBG, "Server closing");
-}
-
-fluid_server_socket_t*
-new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
-{
- fluid_server_socket_t* server_socket;
-#ifdef IPV6
- struct sockaddr_in6 addr;
+ FLUID_MEMSET(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons((uint16_t)port);
+ addr.sin6_addr = in6addr_any;
#else
- struct sockaddr_in addr;
-#endif
-
- fluid_socket_t sock;
- WSADATA wsaData;
- int retval;
- g_return_val_if_fail (func != NULL, NULL);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
- // Win32 requires initialization of winsock
- retval = WSAStartup (MAKEWORD (2,2), &wsaData);
+ if(sock == INVALID_SOCKET)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
+ fluid_socket_cleanup();
+ return NULL;
+ }
- if (retval != 0)
- {
- FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", retval);
- return NULL;
- }
-#ifdef IPV6
- sock = socket (AF_INET6, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET)
- {
- FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
- WSACleanup ();
- return NULL;
- }
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons (port);
- addr.sin6_addr = in6addr_any;
-#else
+ FLUID_MEMSET(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons((uint16_t)port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+#endif
- sock = socket (AF_INET, SOCK_STREAM, 0);
+ if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- if (sock == INVALID_SOCKET)
- {
- FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
- WSACleanup ();
- return NULL;
- }
+ if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
+ {
+ FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- addr.sin_family = AF_INET;
- addr.sin_port = htons (port);
- addr.sin_addr.s_addr = htonl (INADDR_ANY);
-#endif
- retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
+ server_socket = FLUID_NEW(fluid_server_socket_t);
- if (retval == SOCKET_ERROR)
- {
- FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ());
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
+ if(server_socket == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- if (listen (sock, SOMAXCONN) == SOCKET_ERROR)
- {
- FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ());
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
+ server_socket->socket = sock;
+ server_socket->func = func;
+ server_socket->data = data;
+ server_socket->cont = 1;
- server_socket = FLUID_NEW (fluid_server_socket_t);
+ server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
+ 0, FALSE);
- if (server_socket == NULL)
- {
- FLUID_LOG (FLUID_ERR, "Out of memory");
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
-
- server_socket->socket = sock;
- server_socket->func = func;
- server_socket->data = data;
- server_socket->cont = 1;
-
- server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
- 0, FALSE);
- if (server_socket->thread == NULL)
- {
- FLUID_FREE (server_socket);
- fluid_socket_close (sock);
- WSACleanup ();
- return NULL;
- }
+ if(server_socket->thread == NULL)
+ {
+ FLUID_FREE(server_socket);
+ fluid_socket_close(sock);
+ fluid_socket_cleanup();
+ return NULL;
+ }
- return server_socket;
+ return server_socket;
}
-int delete_fluid_server_socket(fluid_server_socket_t *server_socket)
+void delete_fluid_server_socket(fluid_server_socket_t *server_socket)
{
- server_socket->cont = 0;
+ fluid_return_if_fail(server_socket != NULL);
- if (server_socket->socket != INVALID_SOCKET)
- fluid_socket_close (server_socket->socket);
+ server_socket->cont = 0;
- if (server_socket->thread)
- delete_fluid_thread (server_socket->thread);
+ if(server_socket->socket != INVALID_SOCKET)
+ {
+ fluid_socket_close(server_socket->socket);
+ }
- FLUID_FREE (server_socket);
+ if(server_socket->thread)
+ {
+ fluid_thread_join(server_socket->thread);
+ delete_fluid_thread(server_socket->thread);
+ }
- WSACleanup (); // Should be called the same number of times as WSAStartup
+ FLUID_FREE(server_socket);
- return FLUID_OK;
+ // Should be called the same number of times as fluid_socket_init()
+ fluid_socket_cleanup();
}
-#endif
-#endif
+#endif // NETWORK_SUPPORT
diff --git a/libs/fluidsynth/src/fluid_sys.h b/libs/fluidsynth/src/fluid_sys.h
index 4953515692..d95f6159f2 100644
--- a/libs/fluidsynth/src/fluid_sys.h
+++ b/libs/fluidsynth/src/fluid_sys.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -36,9 +36,13 @@
#ifndef _FLUID_SYS_H
#define _FLUID_SYS_H
-#include <glib.h>
#include "fluidsynth_priv.h"
+#ifdef LADSPA
+#include <gmodule.h>
+#endif
+
+#include <glib/gstdio.h>
/**
* Macro used for safely accessing a message from a GError and using a default
@@ -48,50 +52,46 @@
*/
#define fluid_gerror_message(err) ((err) ? err->message : "No error details")
-
-void fluid_sys_config(void);
-void fluid_log_config(void);
-void fluid_time_config(void);
-
-
/* Misc */
+#if defined(__INTEL_COMPILER)
+#define FLUID_RESTRICT restrict
+#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
+#define FLUID_RESTRICT __restrict__
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
+#define FLUID_RESTRICT __restrict
+#else
+#warning "Dont know how this compiler handles restrict pointers, refuse to use them."
+#define FLUID_RESTRICT
+#endif
-#define fluid_return_val_if_fail g_return_val_if_fail
-#define fluid_return_if_fail g_return_if_fail
#define FLUID_INLINE inline
#define FLUID_POINTER_TO_UINT GPOINTER_TO_UINT
#define FLUID_UINT_TO_POINTER GUINT_TO_POINTER
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
#define FLUID_N_ELEMENTS(struct) (sizeof (struct) / sizeof (struct[0]))
+#define FLUID_MEMBER_SIZE(struct, member) ( sizeof (((struct *)0)->member) )
#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)
-/*
- * Utility functions
- */
-char *fluid_strtok (char **str, char *delim);
+#define FLUID_LE32TOH(x) GINT32_FROM_LE(x)
+#define FLUID_LE16TOH(x) GINT16_FROM_LE(x)
-/**
+#define fluid_return_if_fail(cond) \
+if(cond) \
+ ; \
+else \
+ return
- Additional debugging system, separate from the log system. This
- allows to print selected debug messages of a specific subsystem.
- */
-
-extern unsigned int fluid_debug_flags;
-
-#if DEBUG
-
-enum fluid_debug_level {
- FLUID_DBG_DRIVER = 1
-};
+#define fluid_return_val_if_fail(cond, val) \
+ fluid_return_if_fail(cond) (val)
-int fluid_debug(int level, char * fmt, ...);
-#else
-#define fluid_debug
-#endif
+/*
+ * Utility functions
+ */
+char *fluid_strtok(char **str, const char *delim);
#if defined(__OS2__)
@@ -112,17 +112,17 @@ double fluid_utime(void);
/* if the callback function returns 1 the timer will continue; if it
returns 0 it will stop */
-typedef int (*fluid_timer_callback_t)(void* data, unsigned int msec);
+typedef int (*fluid_timer_callback_t)(void *data, unsigned int msec);
typedef struct _fluid_timer_t fluid_timer_t;
-fluid_timer_t* new_fluid_timer(int msec, fluid_timer_callback_t callback,
- void* data, int new_thread, int auto_destroy,
+fluid_timer_t *new_fluid_timer(int msec, fluid_timer_callback_t callback,
+ void *data, int new_thread, int auto_destroy,
int high_priority);
-int delete_fluid_timer(fluid_timer_t* timer);
-int fluid_timer_join(fluid_timer_t* timer);
-int fluid_timer_stop(fluid_timer_t* timer);
+void delete_fluid_timer(fluid_timer_t *timer);
+int fluid_timer_join(fluid_timer_t *timer);
+int fluid_timer_stop(fluid_timer_t *timer);
// Macros to use for pre-processor if statements to test which Glib thread API we have (pre or post 2.32)
#define NEW_GLIB_THREAD_API (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 32))
@@ -155,19 +155,20 @@ typedef GMutex fluid_cond_mutex_t;
#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)
static FLUID_INLINE fluid_cond_mutex_t *
-new_fluid_cond_mutex (void)
+new_fluid_cond_mutex(void)
{
- GMutex *mutex;
- mutex = g_new (GMutex, 1);
- g_mutex_init (mutex);
- return (mutex);
+ GMutex *mutex;
+ mutex = g_new(GMutex, 1);
+ g_mutex_init(mutex);
+ return (mutex);
}
static FLUID_INLINE void
-delete_fluid_cond_mutex (fluid_cond_mutex_t *m)
+delete_fluid_cond_mutex(fluid_cond_mutex_t *m)
{
- g_mutex_clear (m);
- g_free (m);
+ fluid_return_if_fail(m != NULL);
+ g_mutex_clear(m);
+ g_free(m);
}
/* Thread condition signaling */
@@ -177,19 +178,20 @@ typedef GCond fluid_cond_t;
#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex)
static FLUID_INLINE fluid_cond_t *
-new_fluid_cond (void)
+new_fluid_cond(void)
{
- GCond *cond;
- cond = g_new (GCond, 1);
- g_cond_init (cond);
- return (cond);
+ GCond *cond;
+ cond = g_new(GCond, 1);
+ g_cond_init(cond);
+ return (cond);
}
static FLUID_INLINE void
-delete_fluid_cond (fluid_cond_t *cond)
+delete_fluid_cond(fluid_cond_t *cond)
{
- g_cond_clear (cond);
- g_free (cond);
+ fluid_return_if_fail(cond != NULL);
+ g_cond_clear(cond);
+ g_free(cond);
}
/* Thread private data */
@@ -211,10 +213,10 @@ typedef GStaticMutex fluid_mutex_t;
#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))
#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m))
-#define fluid_mutex_init(_m) G_STMT_START { \
+#define fluid_mutex_init(_m) do { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_mutex_init (&(_m)); \
-} G_STMT_END;
+} while(0)
/* Recursive lock capable mutex */
typedef GStaticRecMutex fluid_rec_mutex_t;
@@ -222,10 +224,10 @@ typedef GStaticRecMutex fluid_rec_mutex_t;
#define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))
#define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))
-#define fluid_rec_mutex_init(_m) G_STMT_START { \
+#define fluid_rec_mutex_init(_m) do { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_rec_mutex_init (&(_m)); \
-} G_STMT_END;
+} while(0)
/* Dynamically allocated mutex suitable for fluid_cond_t use */
typedef GMutex fluid_cond_mutex_t;
@@ -234,15 +236,19 @@ typedef GMutex fluid_cond_mutex_t;
#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)
static FLUID_INLINE fluid_cond_mutex_t *
-new_fluid_cond_mutex (void)
+new_fluid_cond_mutex(void)
{
- if (!g_thread_supported ()) g_thread_init (NULL);
- return g_mutex_new ();
+ if(!g_thread_supported())
+ {
+ g_thread_init(NULL);
+ }
+
+ return g_mutex_new();
}
/* Thread condition signaling */
typedef GCond fluid_cond_t;
-fluid_cond_t *new_fluid_cond (void);
+fluid_cond_t *new_fluid_cond(void);
#define delete_fluid_cond(cond) g_cond_free(cond)
#define fluid_cond_signal(cond) g_cond_signal(cond)
#define fluid_cond_broadcast(cond) g_cond_broadcast(cond)
@@ -254,10 +260,10 @@ typedef GStaticPrivate fluid_private_t;
#define fluid_private_set(_priv, _data) g_static_private_set(&(_priv), _data, NULL)
#define fluid_private_free(_priv) g_static_private_free(&(_priv))
-#define fluid_private_init(_priv) G_STMT_START { \
+#define fluid_private_init(_priv) do { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_private_init (&(_priv)); \
-} G_STMT_END;
+} while(0)
#endif
@@ -265,7 +271,6 @@ typedef GStaticPrivate fluid_private_t;
/* Atomic operations */
#define fluid_atomic_int_inc(_pi) g_atomic_int_inc(_pi)
-#define fluid_atomic_int_add(_pi, _val) g_atomic_int_add(_pi, _val)
#define fluid_atomic_int_get(_pi) g_atomic_int_get(_pi)
#define fluid_atomic_int_set(_pi, _val) g_atomic_int_set(_pi, _val)
#define fluid_atomic_int_dec_and_test(_pi) g_atomic_int_dec_and_test(_pi)
@@ -275,9 +280,13 @@ typedef GStaticPrivate fluid_private_t;
#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 30)
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
g_atomic_int_add(_pi, _add)
+#define fluid_atomic_int_add(_pi, _add) \
+ g_atomic_int_add(_pi, _add)
#else
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
g_atomic_int_exchange_and_add(_pi, _add)
+#define fluid_atomic_int_add(_pi, _add) \
+ g_atomic_int_exchange_and_add(_pi, _add)
#endif
#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp)
@@ -288,115 +297,276 @@ typedef GStaticPrivate fluid_private_t;
static FLUID_INLINE void
fluid_atomic_float_set(volatile float *fptr, float val)
{
- sint32 ival;
- memcpy (&ival, &val, 4);
- fluid_atomic_int_set ((volatile int *)fptr, ival);
+ int32_t ival;
+ memcpy(&ival, &val, 4);
+ fluid_atomic_int_set((volatile int *)fptr, ival);
}
static FLUID_INLINE float
fluid_atomic_float_get(volatile float *fptr)
{
- sint32 ival;
- float fval;
- ival = fluid_atomic_int_get ((volatile int *)fptr);
- memcpy (&fval, &ival, 4);
- return fval;
+ int32_t ival;
+ float fval;
+ ival = fluid_atomic_int_get((volatile int *)fptr);
+ memcpy(&fval, &ival, 4);
+ return fval;
}
/* Threads */
+/* other thread implementations might change this for their needs */
+typedef void *fluid_thread_return_t;
+/* static return value for thread functions which requires a return value */
+#define FLUID_THREAD_RETURN_VALUE (NULL)
+
typedef GThread fluid_thread_t;
-typedef void (*fluid_thread_func_t)(void* data);
+typedef fluid_thread_return_t (*fluid_thread_func_t)(void *data);
#define FLUID_THREAD_ID_NULL NULL /* A NULL "ID" value */
#define fluid_thread_id_t GThread * /* Data type for a thread ID */
#define fluid_thread_get_id() g_thread_self() /* Get unique "ID" for current thread */
-fluid_thread_t* new_fluid_thread(const char *name, fluid_thread_func_t func, void *data,
+fluid_thread_t *new_fluid_thread(const char *name, fluid_thread_func_t func, void *data,
int prio_level, int detach);
-void delete_fluid_thread(fluid_thread_t* thread);
-void fluid_thread_self_set_prio (int prio_level);
-int fluid_thread_join(fluid_thread_t* thread);
+void delete_fluid_thread(fluid_thread_t *thread);
+void fluid_thread_self_set_prio(int prio_level);
+int fluid_thread_join(fluid_thread_t *thread);
+
+/* Dynamic Module Loading, currently only used by LADSPA subsystem */
+#ifdef LADSPA
+
+typedef GModule fluid_module_t;
+
+#define fluid_module_open(_name) g_module_open((_name), G_MODULE_BIND_LOCAL)
+#define fluid_module_close(_mod) g_module_close(_mod)
+#define fluid_module_error() g_module_error()
+#define fluid_module_name(_mod) g_module_name(_mod)
+#define fluid_module_symbol(_mod, _name, _ptr) g_module_symbol((_mod), (_name), (_ptr))
+
+#endif /* LADSPA */
/* Sockets and I/O */
-fluid_istream_t fluid_get_stdin (void);
-fluid_ostream_t fluid_get_stdout (void);
-int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char* prompt, char* buf, int len);
-int fluid_ostream_printf (fluid_ostream_t out, char* format, ...);
+fluid_istream_t fluid_get_stdin(void);
+fluid_ostream_t fluid_get_stdout(void);
+int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt, char *buf, int len);
+int fluid_ostream_printf(fluid_ostream_t out, const char *format, ...);
/* The function should return 0 if no error occured, non-zero
otherwise. If the function return non-zero, the socket will be
closed by the server. */
-typedef int (*fluid_server_func_t)(void* data, fluid_socket_t client_socket, char* addr);
+typedef int (*fluid_server_func_t)(void *data, fluid_socket_t client_socket, char *addr);
-fluid_server_socket_t* new_fluid_server_socket(int port, fluid_server_func_t func, void* data);
-int delete_fluid_server_socket(fluid_server_socket_t* sock);
-int fluid_server_socket_join(fluid_server_socket_t* sock);
+fluid_server_socket_t *new_fluid_server_socket(int port, fluid_server_func_t func, void *data);
+void delete_fluid_server_socket(fluid_server_socket_t *sock);
+int fluid_server_socket_join(fluid_server_socket_t *sock);
void fluid_socket_close(fluid_socket_t sock);
fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock);
fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock);
+/* File access */
+#if !GLIB_CHECK_VERSION(2, 26, 0)
+ /* GStatBuf has not been introduced yet, manually typedef to what they had at that time:
+ * https://github.com/GNOME/glib/blob/e7763678b56e3be073cc55d707a6e92fc2055ee0/glib/gstdio.h#L98-L115
+ */
+ #if defined(WIN32) || HAVE_WINDOWS_H // somehow reliably mock G_OS_WIN32??
+ #if defined (_MSC_VER) && !defined(_WIN64)
+ typedef struct _stat32 fluid_stat_buf_t;
+ #else
+ typedef struct _stat fluid_stat_buf_t;
+ #endif
+ #else
+ /* posix, OS/2, etc. */
+ typedef struct stat fluid_stat_buf_t;
+ #endif
+#else
+typedef GStatBuf fluid_stat_buf_t;
+#endif
+#define fluid_stat(_filename, _statbuf) g_stat((_filename), (_statbuf))
/* Profiling */
+#if WITH_PROFILING
+/** profiling interface beetween Profiling command shell and Audio
+ rendering API (FluidProfile_0004.pdf- 3.2.2)
+*/
+/*
+ -----------------------------------------------------------------------------
+ Shell task side | Profiling interface | Audio task side
+ -----------------------------------------------------------------------------
+ profiling | Internal | | | Audio
+ command <---> |<-- profling -->| Data |<--macros -->| <--> rendering
+ shell | API | | | API
-/**
- * Profile numbers. List all the pieces of code you want to profile
- * here. Be sure to add an entry in the fluid_profile_data table in
- * fluid_sys.c
- */
-enum {
- FLUID_PROF_WRITE,
- FLUID_PROF_ONE_BLOCK,
- FLUID_PROF_ONE_BLOCK_CLEAR,
- FLUID_PROF_ONE_BLOCK_VOICE,
- FLUID_PROF_ONE_BLOCK_VOICES,
- FLUID_PROF_ONE_BLOCK_REVERB,
- FLUID_PROF_ONE_BLOCK_CHORUS,
- FLUID_PROF_VOICE_NOTE,
- FLUID_PROF_VOICE_RELEASE,
- FLUID_PROF_LAST
-};
+*/
+/* default parameters for shell command "prof_start" in fluid_sys.c */
+#define FLUID_PROFILE_DEFAULT_BANK 0 /* default bank */
+#define FLUID_PROFILE_DEFAULT_PROG 16 /* default prog (organ) */
+#define FLUID_PROFILE_FIRST_KEY 12 /* first key generated */
+#define FLUID_PROFILE_LAST_KEY 108 /* last key generated */
+#define FLUID_PROFILE_DEFAULT_VEL 64 /* default note velocity */
+#define FLUID_PROFILE_VOICE_ATTEN -0.04f /* gain attenuation per voice (dB) */
-#if WITH_PROFILING
-void fluid_profiling_print(void);
+#define FLUID_PROFILE_DEFAULT_PRINT 0 /* default print mode */
+#define FLUID_PROFILE_DEFAULT_N_PROF 1 /* default number of measures */
+#define FLUID_PROFILE_DEFAULT_DURATION 500 /* default duration (ms) */
+
+
+extern unsigned short fluid_profile_notes; /* number of generated notes */
+extern unsigned char fluid_profile_bank; /* bank,prog preset used by */
+extern unsigned char fluid_profile_prog; /* generated notes */
+extern unsigned char fluid_profile_print; /* print mode */
+
+extern unsigned short fluid_profile_n_prof;/* number of measures */
+extern unsigned short fluid_profile_dur; /* measure duration in ms */
+extern fluid_atomic_int_t fluid_profile_lock ; /* lock between multiple shell */
+/**/
+
+/*----------------------------------------------
+ Internal profiling API (in fluid_sys.c)
+-----------------------------------------------*/
+/* Starts a profiling measure used in shell command "prof_start" */
+void fluid_profile_start_stop(unsigned int end_ticks, short clear_data);
+
+/* Returns status used in shell command "prof_start" */
+int fluid_profile_get_status(void);
+
+/* Prints profiling data used in shell command "prof_start" */
+void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out);
+
+/* Returns True if profiling cancellation has been requested */
+int fluid_profile_is_cancel_req(void);
+
+/* For OS that implement <ENTER> key for profile cancellation:
+ 1) Adds #define FLUID_PROFILE_CANCEL
+ 2) Adds the necessary code inside fluid_profile_is_cancel() see fluid_sys.c
+*/
+#if defined(WIN32) /* Profile cancellation is supported for Windows */
+#define FLUID_PROFILE_CANCEL
+
+#elif defined(__OS2__) /* OS/2 specific stuff */
+/* Profile cancellation isn't yet supported for OS2 */
+#else /* POSIX stuff */
+#define FLUID_PROFILE_CANCEL /* Profile cancellation is supported for linux */
+#include <unistd.h> /* STDIN_FILENO */
+#include <sys/select.h> /* select() */
+#endif /* posix */
-/** Profiling data. Keep track of min/avg/max values to execute a
+/* logging profiling data (used on synthesizer instance deletion) */
+void fluid_profiling_print(void);
+
+/*----------------------------------------------
+ Profiling Data (in fluid_sys.c)
+-----------------------------------------------*/
+/** Profiling data. Keep track of min/avg/max values to profile a
piece of code. */
-typedef struct _fluid_profile_data_t {
- int num;
- char* description;
- double min, max, total;
- unsigned int count;
+typedef struct _fluid_profile_data_t
+{
+ const char *description; /* name of the piece of code under profiling */
+ double min, max, total; /* duration (microsecond) */
+ unsigned int count; /* total count */
+ unsigned int n_voices; /* voices number */
+ unsigned int n_samples; /* audio samples number */
} fluid_profile_data_t;
-extern fluid_profile_data_t fluid_profile_data[];
+enum
+{
+ /* commands/status (profiling interface) */
+ PROFILE_STOP, /* command to stop a profiling measure */
+ PROFILE_START, /* command to start a profile measure */
+ PROFILE_READY, /* status to signal that a profiling measure has finished
+ and ready to be printed */
+ /*- State returned by fluid_profile_get_status() -*/
+ /* between profiling commands and internal profiling API */
+ PROFILE_RUNNING, /* a profiling measure is running */
+ PROFILE_CANCELED,/* a profiling measure has been canceled */
+};
+
+/* Data interface */
+extern unsigned char fluid_profile_status ; /* command and status */
+extern unsigned int fluid_profile_end_ticks; /* ending position (in ticks) */
+extern fluid_profile_data_t fluid_profile_data[]; /* Profiling data */
-/** Macro to obtain a time refence used for the profiling */
+/*----------------------------------------------
+ Probes macros
+-----------------------------------------------*/
+/** Macro to obtain a time reference used for the profiling */
#define fluid_profile_ref() fluid_utime()
/** Macro to create a variable and assign the current reference time for profiling.
* So we don't get unused variable warnings when profiling is disabled. */
#define fluid_profile_ref_var(name) double name = fluid_utime()
-/** Macro to calculate the min/avg/max. Needs a time refence and a
- profile number. */
-#define fluid_profile(_num,_ref) { \
- double _now = fluid_utime(); \
- double _delta = _now - _ref; \
- fluid_profile_data[_num].min = _delta < fluid_profile_data[_num].min ? _delta : fluid_profile_data[_num].min; \
- fluid_profile_data[_num].max = _delta > fluid_profile_data[_num].max ? _delta : fluid_profile_data[_num].max; \
- fluid_profile_data[_num].total += _delta; \
- fluid_profile_data[_num].count++; \
- _ref = _now; \
+/**
+ * Profile identifier numbers. List all the pieces of code you want to profile
+ * here. Be sure to add an entry in the fluid_profile_data table in
+ * fluid_sys.c
+ */
+enum
+{
+ FLUID_PROF_WRITE,
+ FLUID_PROF_ONE_BLOCK,
+ FLUID_PROF_ONE_BLOCK_CLEAR,
+ FLUID_PROF_ONE_BLOCK_VOICE,
+ FLUID_PROF_ONE_BLOCK_VOICES,
+ FLUID_PROF_ONE_BLOCK_REVERB,
+ FLUID_PROF_ONE_BLOCK_CHORUS,
+ FLUID_PROF_VOICE_NOTE,
+ FLUID_PROF_VOICE_RELEASE,
+ FLUID_PROFILE_NBR /* number of profile probes */
+};
+/** Those macros are used to calculate the min/avg/max. Needs a profile number, a
+ time reference, the voices and samples number. */
+
+/* local macro : acquiere data */
+#define fluid_profile_data(_num, _ref, voices, samples)\
+{\
+ double _now = fluid_utime();\
+ double _delta = _now - _ref;\
+ fluid_profile_data[_num].min = _delta < fluid_profile_data[_num].min ?\
+ _delta : fluid_profile_data[_num].min; \
+ fluid_profile_data[_num].max = _delta > fluid_profile_data[_num].max ?\
+ _delta : fluid_profile_data[_num].max;\
+ fluid_profile_data[_num].total += _delta;\
+ fluid_profile_data[_num].count++;\
+ fluid_profile_data[_num].n_voices += voices;\
+ fluid_profile_data[_num].n_samples += samples;\
+ _ref = _now;\
}
+/** Macro to collect data, called from inner functions inside audio
+ rendering API */
+#define fluid_profile(_num, _ref, voices, samples)\
+{\
+ if ( fluid_profile_status == PROFILE_START)\
+ { /* acquires data */\
+ fluid_profile_data(_num, _ref, voices, samples)\
+ }\
+}
+
+/** Macro to collect data, called from audio rendering API (fluid_write_xxxx()).
+ This macro control profiling ending position (in ticks).
+*/
+#define fluid_profile_write(_num, _ref, voices, samples)\
+{\
+ if (fluid_profile_status == PROFILE_START)\
+ {\
+ /* acquires data first: must be done before checking that profile is
+ finished to ensure at least one valid data sample.
+ */\
+ fluid_profile_data(_num, _ref, voices, samples)\
+ if (fluid_synth_get_ticks(synth) >= fluid_profile_end_ticks)\
+ {\
+ /* profiling is finished */\
+ fluid_profile_status = PROFILE_READY;\
+ }\
+ }\
+}
#else
@@ -404,11 +574,9 @@ extern fluid_profile_data_t fluid_profile_data[];
#define fluid_profiling_print()
#define fluid_profile_ref() 0
#define fluid_profile_ref_var(name)
-#define fluid_profile(_num,_ref)
-
-#endif
-
-
+#define fluid_profile(_num,_ref,voices, samples)
+#define fluid_profile_write(_num,_ref, voices, samples)
+#endif /* WITH_PROFILING */
/**
@@ -442,7 +610,32 @@ extern fluid_profile_data_t fluid_profile_data[];
#define fluid_clear_fpe()
#endif
-unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe);
+unsigned int fluid_check_fpe_i386(char *explanation_in_case_of_fpe);
void fluid_clear_fpe_i386(void);
+/* System control */
+void fluid_msleep(unsigned int msecs);
+
+/**
+ * Advances the given \c ptr to the next \c alignment byte boundary.
+ * Make sure you've allocated an extra of \c alignment bytes to avoid a buffer overflow.
+ *
+ * @note \c alignment must be a power of two
+ * @return Returned pointer is guarenteed to be aligned to \c alignment boundary and in range \f[ ptr <= returned_ptr < ptr + alignment \f].
+ */
+static FLUID_INLINE void *fluid_align_ptr(const void *ptr, unsigned int alignment)
+{
+ uintptr_t ptr_int = (uintptr_t)ptr;
+ unsigned int offset = ptr_int & (alignment - 1);
+ unsigned int add = (alignment - offset) & (alignment - 1); // advance the pointer to the next alignment boundary
+ ptr_int += add;
+
+ /* assert alignment is power of two */
+ FLUID_ASSERT(!(alignment == 0) && !(alignment & (alignment - 1)));
+
+ return (void *)ptr_int;
+}
+
+#define FLUID_DEFAULT_ALIGNMENT (64U)
+
#endif /* _FLUID_SYS_H */
diff --git a/libs/fluidsynth/src/fluid_tuning.c b/libs/fluidsynth/src/fluid_tuning.c
index 8977ed6728..ee083116a2 100644
--- a/libs/fluidsynth/src/fluid_tuning.c
+++ b/libs/fluidsynth/src/fluid_tuning.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -24,151 +24,168 @@
#include "fluid_sys.h"
-fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog)
+fluid_tuning_t *new_fluid_tuning(const char *name, int bank, int prog)
{
- fluid_tuning_t* tuning;
- int i;
+ fluid_tuning_t *tuning;
+ int i;
- tuning = FLUID_NEW(fluid_tuning_t);
- if (tuning == NULL) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- return NULL;
- }
+ tuning = FLUID_NEW(fluid_tuning_t);
- tuning->name = NULL;
+ if(tuning == NULL)
+ {
+ FLUID_LOG(FLUID_PANIC, "Out of memory");
+ return NULL;
+ }
- if (name != NULL) {
- tuning->name = FLUID_STRDUP(name);
- }
+ FLUID_MEMSET(tuning, 0, sizeof(fluid_tuning_t));
- tuning->bank = bank;
- tuning->prog = prog;
+ if(fluid_tuning_set_name(tuning, name) != FLUID_OK)
+ {
+ delete_fluid_tuning(tuning);
+ return NULL;
+ }
- for (i = 0; i < 128; i++) {
- tuning->pitch[i] = i * 100.0;
- }
+ tuning->bank = bank;
+ tuning->prog = prog;
- tuning->refcount = 1; /* Start with a refcount of 1 */
+ for(i = 0; i < 128; i++)
+ {
+ tuning->pitch[i] = i * 100.0;
+ }
+
+ fluid_atomic_int_set(&tuning->refcount, 1); /* Start with a refcount of 1 */
- return tuning;
+ return tuning;
}
/* Duplicate a tuning */
fluid_tuning_t *
-fluid_tuning_duplicate (fluid_tuning_t *tuning)
+fluid_tuning_duplicate(fluid_tuning_t *tuning)
{
- fluid_tuning_t *new_tuning;
- int i;
+ fluid_tuning_t *new_tuning;
+ int i;
- new_tuning = FLUID_NEW (fluid_tuning_t);
+ new_tuning = FLUID_NEW(fluid_tuning_t);
- if (!new_tuning) {
- FLUID_LOG (FLUID_PANIC, "Out of memory");
- return NULL;
- }
+ if(!new_tuning)
+ {
+ FLUID_LOG(FLUID_PANIC, "Out of memory");
+ return NULL;
+ }
- if (tuning->name)
- {
- new_tuning->name = FLUID_STRDUP (tuning->name);
+ FLUID_MEMSET(new_tuning, 0, sizeof(fluid_tuning_t));
- if (!new_tuning->name)
+ if(fluid_tuning_set_name(new_tuning, tuning->name) != FLUID_OK)
{
- FLUID_FREE (new_tuning);
- FLUID_LOG (FLUID_PANIC, "Out of memory");
- return NULL;
+ delete_fluid_tuning(new_tuning);
+ return NULL;
}
- }
- else new_tuning->name = NULL;
- new_tuning->bank = tuning->bank;
- new_tuning->prog = tuning->prog;
+ new_tuning->bank = tuning->bank;
+ new_tuning->prog = tuning->prog;
- for (i = 0; i < 128; i++)
- new_tuning->pitch[i] = tuning->pitch[i];
+ for(i = 0; i < 128; i++)
+ {
+ new_tuning->pitch[i] = tuning->pitch[i];
+ }
- new_tuning->refcount = 1; /* Start with a refcount of 1 */
+ fluid_atomic_int_set(&new_tuning->refcount, 1); /* Start with a refcount of 1 */
- return new_tuning;
+ return new_tuning;
}
void
-delete_fluid_tuning (fluid_tuning_t *tuning)
+delete_fluid_tuning(fluid_tuning_t *tuning)
{
- if (tuning->name) FLUID_FREE (tuning->name);
- FLUID_FREE (tuning);
+ fluid_return_if_fail(tuning != NULL);
+
+ FLUID_FREE(tuning->name);
+ FLUID_FREE(tuning);
}
/* Add a reference to a tuning object */
void
-fluid_tuning_ref (fluid_tuning_t *tuning)
+fluid_tuning_ref(fluid_tuning_t *tuning)
{
- fluid_return_if_fail (tuning != NULL);
+ fluid_return_if_fail(tuning != NULL);
- fluid_atomic_int_inc (&tuning->refcount);
+ fluid_atomic_int_inc(&tuning->refcount);
}
/* Unref a tuning object, when it reaches 0 it is deleted, returns TRUE if deleted */
int
-fluid_tuning_unref (fluid_tuning_t *tuning, int count)
+fluid_tuning_unref(fluid_tuning_t *tuning, int count)
{
- fluid_return_val_if_fail (tuning != NULL, FALSE);
-
- /* Add and compare are separate, but that is OK, since refcount will only
- * reach 0 when there are no references and therefore no possibility of
- * another thread adding a reference in between */
- fluid_atomic_int_add (&tuning->refcount, -count);
-
- /* Delete when refcount reaches 0 */
- if (!fluid_atomic_int_get (&tuning->refcount))
- {
- delete_fluid_tuning (tuning);
- return TRUE;
- }
- else return FALSE;
-}
+ fluid_return_val_if_fail(tuning != NULL, FALSE);
-void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name)
-{
- if (tuning->name != NULL) {
- FLUID_FREE(tuning->name);
- tuning->name = NULL;
- }
- if (name != NULL) {
- tuning->name = FLUID_STRDUP(name);
- }
+ /* Add and compare are separate, but that is OK, since refcount will only
+ * reach 0 when there are no references and therefore no possibility of
+ * another thread adding a reference in between */
+ fluid_atomic_int_add(&tuning->refcount, -count);
+
+ /* Delete when refcount reaches 0 */
+ if(!fluid_atomic_int_get(&tuning->refcount))
+ {
+ delete_fluid_tuning(tuning);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
}
-char* fluid_tuning_get_name(fluid_tuning_t* tuning)
+int fluid_tuning_set_name(fluid_tuning_t *tuning, const char *name)
{
- return tuning->name;
+ if(tuning->name != NULL)
+ {
+ FLUID_FREE(tuning->name);
+ tuning->name = NULL;
+ }
+
+ if(name != NULL)
+ {
+ tuning->name = FLUID_STRDUP(name);
+
+ if(tuning->name == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return FLUID_FAILED;
+ }
+ }
+
+ return FLUID_OK;
}
-static void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
+char *fluid_tuning_get_name(fluid_tuning_t *tuning)
{
- tuning->pitch[key] = pitch;
+ return tuning->name;
}
-void fluid_tuning_set_octave(fluid_tuning_t* tuning, const double* pitch_deriv)
+void fluid_tuning_set_octave(fluid_tuning_t *tuning, const double *pitch_deriv)
{
- int i;
+ int i;
- for (i = 0; i < 128; i++) {
- tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12];
- }
+ for(i = 0; i < 128; i++)
+ {
+ tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12];
+ }
}
-void fluid_tuning_set_all(fluid_tuning_t* tuning, const double* pitch)
+void fluid_tuning_set_all(fluid_tuning_t *tuning, const double *pitch)
{
- int i;
+ int i;
- for (i = 0; i < 128; i++) {
- tuning->pitch[i] = pitch[i];
- }
+ for(i = 0; i < 128; i++)
+ {
+ tuning->pitch[i] = pitch[i];
+ }
}
-void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch)
+void fluid_tuning_set_pitch(fluid_tuning_t *tuning, int key, double pitch)
{
- if ((key >= 0) && (key < 128)) {
- tuning->pitch[key] = pitch;
- }
+ if((key >= 0) && (key < 128))
+ {
+ tuning->pitch[key] = pitch;
+ }
}
diff --git a/libs/fluidsynth/src/fluid_tuning.h b/libs/fluidsynth/src/fluid_tuning.h
index d974139276..3afe2c65ad 100644
--- a/libs/fluidsynth/src/fluid_tuning.h
+++ b/libs/fluidsynth/src/fluid_tuning.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -34,32 +34,33 @@
#include "fluidsynth_priv.h"
-struct _fluid_tuning_t {
- char* name;
- int bank;
- int prog;
- double pitch[128]; /* the pitch of every key, in cents */
- int refcount; /* Tuning reference count */
+struct _fluid_tuning_t
+{
+ char *name;
+ int bank;
+ int prog;
+ double pitch[128]; /* the pitch of every key, in cents */
+ fluid_atomic_int_t refcount; /* Tuning reference count */
};
-fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog);
-void delete_fluid_tuning (fluid_tuning_t *tuning);
-fluid_tuning_t *fluid_tuning_duplicate (fluid_tuning_t *tuning);
-void fluid_tuning_ref (fluid_tuning_t *tuning);
-int fluid_tuning_unref (fluid_tuning_t *tuning, int count);
+fluid_tuning_t *new_fluid_tuning(const char *name, int bank, int prog);
+void delete_fluid_tuning(fluid_tuning_t *tuning);
+fluid_tuning_t *fluid_tuning_duplicate(fluid_tuning_t *tuning);
+void fluid_tuning_ref(fluid_tuning_t *tuning);
+int fluid_tuning_unref(fluid_tuning_t *tuning, int count);
-void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name);
-char* fluid_tuning_get_name(fluid_tuning_t* tuning);
+int fluid_tuning_set_name(fluid_tuning_t *tuning, const char *name);
+char *fluid_tuning_get_name(fluid_tuning_t *tuning);
#define fluid_tuning_get_bank(_t) ((_t)->bank)
#define fluid_tuning_get_prog(_t) ((_t)->prog)
-void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch);
+void fluid_tuning_set_pitch(fluid_tuning_t *tuning, int key, double pitch);
#define fluid_tuning_get_pitch(_t, _key) ((_t)->pitch[_key])
-void fluid_tuning_set_octave(fluid_tuning_t* tuning, const double* pitch_deriv);
+void fluid_tuning_set_octave(fluid_tuning_t *tuning, const double *pitch_deriv);
-void fluid_tuning_set_all(fluid_tuning_t* tuning, const double* pitch);
+void fluid_tuning_set_all(fluid_tuning_t *tuning, const double *pitch);
#define fluid_tuning_get_all(_t) (&(_t)->pitch[0])
diff --git a/libs/fluidsynth/src/fluid_voice.c b/libs/fluidsynth/src/fluid_voice.c
index e6efbac899..51c1ebf655 100644
--- a/libs/fluidsynth/src/fluid_voice.c
+++ b/libs/fluidsynth/src/fluid_voice.c
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -27,6 +27,7 @@
#include "fluid_sys.h"
#include "fluid_sfont.h"
#include "fluid_rvoice_event.h"
+#include "fluid_defsfont.h"
/* used for filter turn off optimization - if filter cutoff is above the
specified value and filter q is below the other value, turn filter off */
@@ -36,299 +37,349 @@
/* min vol envelope release (to stop clicks) in SoundFont timecents */
#define FLUID_MIN_VOLENVRELEASE -7200.0f /* ~16ms */
-static int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice);
-static int calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
+
+static const int32_t INT24_MAX = (1 << (16 + 8 - 1));
+
+static int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t *voice);
+static int calculate_hold_decay_buffers(fluid_voice_t *voice, int gen_base,
int gen_key2base, int is_decay);
static fluid_real_t
-fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice);
+fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t *voice);
#define UPDATE_RVOICE0(proc) \
do { \
- if (voice->can_access_rvoice) proc(voice->rvoice); \
- else fluid_rvoice_eventhandler_push(voice->channel->synth->eventhandler, \
- proc, voice->rvoice, 0, 0.0f); \
- } while (0)
-
-#define UPDATE_RVOICE_PTR(proc, obj) \
- do { \
- if (voice->can_access_rvoice) proc(voice->rvoice, obj); \
- else fluid_rvoice_eventhandler_push_ptr(voice->channel->synth->eventhandler, \
- proc, voice->rvoice, obj); \
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \
+ fluid_rvoice_eventhandler_push(voice->eventhandler, proc, voice->rvoice, param); \
} while (0)
-
#define UPDATE_RVOICE_GENERIC_R1(proc, obj, rarg) \
do { \
- if (voice->can_access_rvoice) proc(obj, rarg); \
- else fluid_rvoice_eventhandler_push(voice->channel->synth->eventhandler, \
- proc, obj, 0, rarg); \
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \
+ param[0].real = rarg; \
+ fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \
} while (0)
#define UPDATE_RVOICE_GENERIC_I1(proc, obj, iarg) \
do { \
- if (voice->can_access_rvoice) proc(obj, iarg); \
- else fluid_rvoice_eventhandler_push(voice->channel->synth->eventhandler, \
- proc, obj, iarg, 0.0f); \
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \
+ param[0].i = iarg; \
+ fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \
} while (0)
-#define UPDATE_RVOICE_GENERIC_IR(proc, obj, iarg, rarg) \
+#define UPDATE_RVOICE_GENERIC_I2(proc, obj, iarg1, iarg2) \
do { \
- if (voice->can_access_rvoice) proc(obj, iarg, rarg); \
- else fluid_rvoice_eventhandler_push(voice->channel->synth->eventhandler, \
- proc, obj, iarg, rarg); \
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \
+ param[0].i = iarg1; \
+ param[1].i = iarg2; \
+ fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \
} while (0)
-#define UPDATE_RVOICE_GENERIC_ALL(proc, obj, iarg, r1, r2, r3, r4, r5) \
+#define UPDATE_RVOICE_GENERIC_IR(proc, obj, iarg, rarg) \
do { \
- if (voice->can_access_rvoice) proc(obj, iarg, r1, r2, r3, r4, r5); \
- else fluid_rvoice_eventhandler_push5(voice->channel->synth->eventhandler, \
- proc, obj, iarg, r1, r2, r3, r4, r5); \
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \
+ param[0].i = iarg; \
+ param[1].real = rarg; \
+ fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \
} while (0)
-#define UPDATE_RVOICE_VOLENV(section, arg1, arg2, arg3, arg4, arg5) \
- do { \
- fluid_adsr_env_set_data(&voice->volenv, section, arg1, arg2, arg3, arg4, arg5) \
- UPDATE_RVOICE_GENERIC_ALL(fluid_adsr_env_set_data, &voice->rvoice->envlfo.volenv, section, arg1, arg2, arg3, arg4, arg5) \
- } while(0)
-
-#define UPDATE_RVOICE_MODENV(section, arg1, arg2, arg3, arg4, arg5) \
- UPDATE_RVOICE_GENERIC_ALL(fluid_adsr_env_set_data, &voice->rvoice->envlfo.modenv, section, arg1, arg2, arg3, arg4, arg5)
-
#define UPDATE_RVOICE_R1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, voice->rvoice, arg1)
#define UPDATE_RVOICE_I1(proc, arg1) UPDATE_RVOICE_GENERIC_I1(proc, voice->rvoice, arg1)
-#define UPDATE_RVOICE_FILTER1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, &voice->rvoice->resonant_filter, arg1)
-#define UPDATE_RVOICE2(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, voice->rvoice, iarg, rarg)
-#define UPDATE_RVOICE_BUFFERS2(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, &voice->rvoice->buffers, iarg, rarg)
-#define UPDATE_RVOICE_ENVLFO_R1(proc, envp, rarg) UPDATE_RVOICE_GENERIC_R1(proc, &voice->rvoice->envlfo.envp, rarg)
-#define UPDATE_RVOICE_ENVLFO_I1(proc, envp, iarg) UPDATE_RVOICE_GENERIC_I1(proc, &voice->rvoice->envlfo.envp, iarg)
+#define UPDATE_RVOICE_BUFFERS_AMP(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, &voice->rvoice->buffers, iarg, rarg)
+#define UPDATE_RVOICE_ENVLFO_R1(proc, envp, rarg) UPDATE_RVOICE_GENERIC_R1(proc, &voice->rvoice->envlfo.envp, rarg)
+#define UPDATE_RVOICE_ENVLFO_I1(proc, envp, iarg) UPDATE_RVOICE_GENERIC_I1(proc, &voice->rvoice->envlfo.envp, iarg)
-static inline void
-fluid_voice_update_volenv(fluid_voice_t* voice,
- fluid_adsr_env_section_t section,
+static FLUID_INLINE void
+fluid_voice_update_volenv(fluid_voice_t *voice,
+ int enqueue,
+ fluid_adsr_env_section_t section,
unsigned int count,
fluid_real_t coeff,
fluid_real_t increment,
fluid_real_t min,
fluid_real_t max)
{
- fluid_adsr_env_set_data(&voice->volenv, section, count, coeff, increment,
- min, max);
- UPDATE_RVOICE_GENERIC_ALL(fluid_adsr_env_set_data,
- &voice->rvoice->envlfo.volenv, section, count,
- coeff, increment, min, max);
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS];
+
+ param[0].i = section;
+ param[1].i = count;
+ param[2].real = coeff;
+ param[3].real = increment;
+ param[4].real = min;
+ param[5].real = max;
+
+ if(enqueue)
+ {
+ fluid_rvoice_eventhandler_push(voice->eventhandler,
+ fluid_adsr_env_set_data,
+ &voice->rvoice->envlfo.volenv,
+ param);
+ }
+ else
+ {
+ fluid_adsr_env_set_data(&voice->rvoice->envlfo.volenv, param);
+ }
}
-static inline void
-fluid_voice_update_modenv(fluid_voice_t* voice,
- fluid_adsr_env_section_t section,
+static FLUID_INLINE void
+fluid_voice_update_modenv(fluid_voice_t *voice,
+ int enqueue,
+ fluid_adsr_env_section_t section,
unsigned int count,
fluid_real_t coeff,
fluid_real_t increment,
fluid_real_t min,
fluid_real_t max)
{
- UPDATE_RVOICE_GENERIC_ALL(fluid_adsr_env_set_data,
- &voice->rvoice->envlfo.modenv, section, count,
- coeff, increment, min, max);
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS];
+
+ param[0].i = section;
+ param[1].i = count;
+ param[2].real = coeff;
+ param[3].real = increment;
+ param[4].real = min;
+ param[5].real = max;
+
+ if(enqueue)
+ {
+ fluid_rvoice_eventhandler_push(voice->eventhandler,
+ fluid_adsr_env_set_data,
+ &voice->rvoice->envlfo.modenv,
+ param);
+ }
+ else
+ {
+ fluid_adsr_env_set_data(&voice->rvoice->envlfo.modenv, param);
+ }
}
-static inline void fluid_sample_null_ptr(fluid_sample_t** sample)
+static FLUID_INLINE void fluid_voice_sample_unref(fluid_sample_t **sample)
{
- if (*sample != NULL) {
- fluid_sample_decr_ref(*sample);
- *sample = NULL;
- }
+ if(*sample != NULL)
+ {
+ fluid_sample_decr_ref(*sample);
+ *sample = NULL;
+ }
}
/*
* Swaps the current rvoice with the current overflow_rvoice
*/
-static void fluid_voice_swap_rvoice(fluid_voice_t* voice)
+static void fluid_voice_swap_rvoice(fluid_voice_t *voice)
{
- fluid_rvoice_t* rtemp = voice->rvoice;
- int ctemp = voice->can_access_rvoice;
- voice->rvoice = voice->overflow_rvoice;
- voice->can_access_rvoice = voice->can_access_overflow_rvoice;
- voice->overflow_rvoice = rtemp;
- voice->can_access_overflow_rvoice = ctemp;
+ fluid_rvoice_t *rtemp = voice->rvoice;
+ int ctemp = voice->can_access_rvoice;
+ voice->rvoice = voice->overflow_rvoice;
+ voice->can_access_rvoice = voice->can_access_overflow_rvoice;
+ voice->overflow_rvoice = rtemp;
+ voice->can_access_overflow_rvoice = ctemp;
}
-static void fluid_voice_initialize_rvoice(fluid_voice_t* voice)
+static void fluid_voice_initialize_rvoice(fluid_voice_t *voice, fluid_real_t output_rate)
{
- FLUID_MEMSET(voice->rvoice, 0, sizeof(fluid_rvoice_t));
-
- /* The 'sustain' and 'finished' segments of the volume / modulation
- * envelope are constant. They are never affected by any modulator
- * or generator. Therefore it is enough to initialize them once
- * during the lifetime of the synth.
- */
- fluid_voice_update_volenv(voice, FLUID_VOICE_ENVSUSTAIN,
- 0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f);
- fluid_voice_update_volenv(voice, FLUID_VOICE_ENVFINISHED,
- 0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f);
- fluid_voice_update_modenv(voice, FLUID_VOICE_ENVSUSTAIN,
- 0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f);
- fluid_voice_update_modenv(voice, FLUID_VOICE_ENVFINISHED,
- 0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f);
+ fluid_rvoice_param_t param[MAX_EVENT_PARAMS];
+
+ FLUID_MEMSET(voice->rvoice, 0, sizeof(fluid_rvoice_t));
+
+ /* The 'sustain' and 'finished' segments of the volume / modulation
+ * envelope are constant. They are never affected by any modulator
+ * or generator. Therefore it is enough to initialize them once
+ * during the lifetime of the synth.
+ */
+ fluid_voice_update_volenv(voice, FALSE, FLUID_VOICE_ENVSUSTAIN,
+ 0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f);
+ fluid_voice_update_volenv(voice, FALSE, FLUID_VOICE_ENVFINISHED,
+ 0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f);
+ fluid_voice_update_modenv(voice, FALSE, FLUID_VOICE_ENVSUSTAIN,
+ 0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f);
+ fluid_voice_update_modenv(voice, FALSE, FLUID_VOICE_ENVFINISHED,
+ 0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f);
+
+ param[0].i = FLUID_IIR_LOWPASS;
+ param[1].i = 0;
+ fluid_iir_filter_init(&voice->rvoice->resonant_filter, param);
+
+ param[0].i = FLUID_IIR_DISABLED;
+ fluid_iir_filter_init(&voice->rvoice->resonant_custom_filter, param);
+
+ param[0].real = output_rate;
+ fluid_rvoice_set_output_rate(voice->rvoice, param);
}
/*
* new_fluid_voice
*/
-fluid_voice_t*
-new_fluid_voice(fluid_real_t output_rate)
+fluid_voice_t *
+new_fluid_voice(fluid_rvoice_eventhandler_t *handler, fluid_real_t output_rate)
{
- fluid_voice_t* voice;
- voice = FLUID_NEW(fluid_voice_t);
- if (voice == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- return NULL;
- }
- voice->rvoice = FLUID_NEW(fluid_rvoice_t);
- voice->overflow_rvoice = FLUID_NEW(fluid_rvoice_t);
- if (voice->rvoice == NULL || voice->overflow_rvoice == NULL) {
- FLUID_LOG(FLUID_ERR, "Out of memory");
- FLUID_FREE(voice->rvoice);
- FLUID_FREE(voice);
- return NULL;
- }
-
- voice->status = FLUID_VOICE_CLEAN;
- voice->chan = NO_CHANNEL;
- voice->key = 0;
- voice->vel = 0;
- voice->channel = NULL;
- voice->sample = NULL;
-
- /* Initialize both the rvoice and overflow_rvoice */
- voice->can_access_rvoice = 1;
- voice->can_access_overflow_rvoice = 1;
- fluid_voice_initialize_rvoice(voice);
- fluid_voice_swap_rvoice(voice);
- fluid_voice_initialize_rvoice(voice);
-
- fluid_voice_set_output_rate(voice, output_rate);
-
- return voice;
+ fluid_voice_t *voice;
+ voice = FLUID_NEW(fluid_voice_t);
+
+ if(voice == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+
+ voice->can_access_rvoice = TRUE;
+ voice->can_access_overflow_rvoice = TRUE;
+
+ voice->rvoice = FLUID_NEW(fluid_rvoice_t);
+ voice->overflow_rvoice = FLUID_NEW(fluid_rvoice_t);
+
+ if(voice->rvoice == NULL || voice->overflow_rvoice == NULL)
+ {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ delete_fluid_voice(voice);
+ return NULL;
+ }
+
+ voice->status = FLUID_VOICE_CLEAN;
+ voice->chan = NO_CHANNEL;
+ voice->key = 0;
+ voice->vel = 0;
+ voice->eventhandler = handler;
+ voice->channel = NULL;
+ voice->sample = NULL;
+ voice->output_rate = output_rate;
+
+ /* Initialize both the rvoice and overflow_rvoice */
+ fluid_voice_initialize_rvoice(voice, output_rate);
+ fluid_voice_swap_rvoice(voice);
+ fluid_voice_initialize_rvoice(voice, output_rate);
+
+ return voice;
}
/*
* delete_fluid_voice
*/
-int
-delete_fluid_voice(fluid_voice_t* voice)
+void
+delete_fluid_voice(fluid_voice_t *voice)
{
- if (voice == NULL) {
- return FLUID_OK;
- }
- if (!voice->can_access_rvoice || !voice->can_access_overflow_rvoice) {
- /* stop rvoice before deleting voice! */
- return FLUID_FAILED;
- }
- FLUID_FREE(voice->overflow_rvoice);
- FLUID_FREE(voice->rvoice);
- FLUID_FREE(voice);
- return FLUID_OK;
+ fluid_return_if_fail(voice != NULL);
+
+ if(!voice->can_access_rvoice || !voice->can_access_overflow_rvoice)
+ {
+ FLUID_LOG(FLUID_WARN, "Deleting voice %u which has locked rvoices!", voice->id);
+ }
+
+ FLUID_FREE(voice->overflow_rvoice);
+ FLUID_FREE(voice->rvoice);
+ FLUID_FREE(voice);
}
/* fluid_voice_init
*
* Initialize the synthesis process
+ * inst_zone, the Instrument Zone contains the sample, Keyrange,Velrange
+ * of the voice.
+ * When playing legato (n1,n2) in mono mode, n2 will use n1 voices
+ * as far as n2 still enters in Keyrange,Velrange of n1.
*/
int
-fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
- fluid_channel_t* channel, int key, int vel, unsigned int id,
- unsigned int start_time, fluid_real_t gain)
+fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
+ fluid_zone_range_t *inst_zone_range,
+ fluid_channel_t *channel, int key, int vel, unsigned int id,
+ unsigned int start_time, fluid_real_t gain)
{
- /* Note: The voice parameters will be initialized later, when the
- * generators have been retrieved from the sound font. Here, only
- * the 'working memory' of the voice (position in envelopes, history
- * of IIR filters, position in sample etc) is initialized. */
- int i;
-
- if (!voice->can_access_rvoice) {
- if (voice->can_access_overflow_rvoice)
- fluid_voice_swap_rvoice(voice);
- else {
- FLUID_LOG(FLUID_ERR, "Internal error: Cannot access an rvoice in fluid_voice_init!");
- return FLUID_FAILED;
+ /* Note: The voice parameters will be initialized later, when the
+ * generators have been retrieved from the sound font. Here, only
+ * the 'working memory' of the voice (position in envelopes, history
+ * of IIR filters, position in sample etc) is initialized. */
+ int i;
+
+ if(!voice->can_access_rvoice)
+ {
+ if(voice->can_access_overflow_rvoice)
+ {
+ fluid_voice_swap_rvoice(voice);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_ERR, "Internal error: Cannot access an rvoice in fluid_voice_init!");
+ return FLUID_FAILED;
+ }
}
- }
- /* We are now guaranteed to have access to the rvoice */
-
- if (voice->sample)
- fluid_voice_off(voice);
-
- voice->id = id;
- voice->chan = fluid_channel_get_num(channel);
- voice->key = (unsigned char) key;
- voice->vel = (unsigned char) vel;
- voice->channel = channel;
- voice->mod_count = 0;
- voice->start_time = start_time;
- voice->debug = 0;
- voice->has_noteoff = 0;
- UPDATE_RVOICE0(fluid_rvoice_reset);
-
- /* Increment the reference count of the sample to prevent the
- unloading of the soundfont while this voice is playing,
- once for us and once for the rvoice. */
- fluid_sample_incr_ref(sample);
- UPDATE_RVOICE_PTR(fluid_rvoice_set_sample, sample);
- fluid_sample_incr_ref(sample);
- voice->sample = sample;
-
- i = fluid_channel_get_interp_method(channel);
- UPDATE_RVOICE_I1(fluid_rvoice_set_interp_method, i);
-
- /* Set all the generators to their default value, according to SF
- * 2.01 section 8.1.3 (page 48). The value of NRPN messages are
- * copied from the channel to the voice's generators. The sound font
- * loader overwrites them. The generator values are later converted
- * into voice parameters in
- * fluid_voice_calculate_runtime_synthesis_parameters. */
- fluid_gen_init(&voice->gen[0], channel);
- UPDATE_RVOICE_I1(fluid_rvoice_set_samplemode, _SAMPLEMODE(voice));
-
- voice->synth_gain = gain;
- /* avoid division by zero later*/
- if (voice->synth_gain < 0.0000001){
- voice->synth_gain = 0.0000001;
- }
- UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, voice->synth_gain);
-
- /* Set up buffer mapping, should be done more flexible in the future. */
- i = channel->synth->audio_groups;
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_mapping, 2, i*2 + SYNTH_REVERB_CHANNEL);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_mapping, 3, i*2 + SYNTH_CHORUS_CHANNEL);
- i = 2 * (voice->chan % i);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_mapping, 0, i);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_mapping, 1, i+1);
-
- return FLUID_OK;
+
+ /* We are now guaranteed to have access to the rvoice */
+
+ if(voice->sample)
+ {
+ fluid_voice_off(voice);
+ }
+
+ voice->zone_range = inst_zone_range; /* Instrument zone range for legato */
+ voice->id = id;
+ voice->chan = fluid_channel_get_num(channel);
+ voice->key = (unsigned char) key;
+ voice->vel = (unsigned char) vel;
+ voice->channel = channel;
+ voice->mod_count = 0;
+ voice->start_time = start_time;
+ voice->has_noteoff = 0;
+ UPDATE_RVOICE0(fluid_rvoice_reset);
+
+ /* Increment the reference count of the sample to prevent the
+ unloading of the soundfont while this voice is playing,
+ once for us and once for the rvoice. */
+ fluid_sample_incr_ref(sample);
+ fluid_rvoice_eventhandler_push_ptr(voice->eventhandler, fluid_rvoice_set_sample, voice->rvoice, sample);
+ fluid_sample_incr_ref(sample);
+ voice->sample = sample;
+
+ i = fluid_channel_get_interp_method(channel);
+ UPDATE_RVOICE_I1(fluid_rvoice_set_interp_method, i);
+
+ /* Set all the generators to their default value, according to SF
+ * 2.01 section 8.1.3 (page 48). The value of NRPN messages are
+ * copied from the channel to the voice's generators. The sound font
+ * loader overwrites them. The generator values are later converted
+ * into voice parameters in
+ * fluid_voice_calculate_runtime_synthesis_parameters. */
+ fluid_gen_init(&voice->gen[0], channel);
+ UPDATE_RVOICE_I1(fluid_rvoice_set_samplemode, _SAMPLEMODE(voice));
+
+ voice->synth_gain = gain;
+
+ /* avoid division by zero later*/
+ if(voice->synth_gain < 0.0000001)
+ {
+ voice->synth_gain = 0.0000001;
+ }
+
+ UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, voice->synth_gain);
+
+ /* Set up buffer mapping, should be done more flexible in the future. */
+ i = 2 * channel->synth->audio_groups;
+ i += (voice->chan % channel->synth->effects_groups) * channel->synth->effects_channels;
+ UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 2, i + SYNTH_REVERB_CHANNEL);
+ UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 3, i + SYNTH_CHORUS_CHANNEL);
+
+ i = 2 * (voice->chan % channel->synth->audio_groups);
+ UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 0, i);
+ UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 1, i + 1);
+
+ return FLUID_OK;
}
/**
- * Update sample rate.
- * NOTE: If the voice is active, it will be turned off.
+ * Update sample rate.
+ * @note If the voice is active, it will be turned off.
*/
-int
-fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value)
+void
+fluid_voice_set_output_rate(fluid_voice_t *voice, fluid_real_t value)
{
- if (_PLAYING(voice))
- fluid_voice_off(voice);
-
- voice->output_rate = value;
- UPDATE_RVOICE_R1(fluid_rvoice_set_output_rate, value);
- /* Update the other rvoice as well */
- fluid_voice_swap_rvoice(voice);
- UPDATE_RVOICE_R1(fluid_rvoice_set_output_rate, value);
- fluid_voice_swap_rvoice(voice);
-
- return FLUID_FAILED;
+ if(fluid_voice_is_playing(voice))
+ {
+ fluid_voice_off(voice);
+ }
+
+ voice->output_rate = value;
+ UPDATE_RVOICE_GENERIC_R1(fluid_rvoice_set_output_rate, voice->rvoice, value);
+ UPDATE_RVOICE_GENERIC_R1(fluid_rvoice_set_output_rate, voice->overflow_rvoice, value);
}
@@ -339,12 +390,15 @@ fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value)
* @param val Generator value
*/
void
-fluid_voice_gen_set(fluid_voice_t* voice, int i, float val)
+fluid_voice_gen_set(fluid_voice_t *voice, int i, float val)
{
- voice->gen[i].val = val;
- voice->gen[i].flags = GEN_SET;
- if (i == GEN_SAMPLEMODE)
- UPDATE_RVOICE_I1(fluid_rvoice_set_samplemode, (int) val);
+ voice->gen[i].val = val;
+ voice->gen[i].flags = GEN_SET;
+
+ if(i == GEN_SAMPLEMODE)
+ {
+ UPDATE_RVOICE_I1(fluid_rvoice_set_samplemode, (int) val);
+ }
}
/**
@@ -354,10 +408,10 @@ fluid_voice_gen_set(fluid_voice_t* voice, int i, float val)
* @param val Value to add to the existing value
*/
void
-fluid_voice_gen_incr(fluid_voice_t* voice, int i, float val)
+fluid_voice_gen_incr(fluid_voice_t *voice, int i, float val)
{
- voice->gen[i].val += val;
- voice->gen[i].flags = GEN_SET;
+ voice->gen[i].val += val;
+ voice->gen[i].flags = GEN_SET;
}
/**
@@ -367,128 +421,102 @@ fluid_voice_gen_incr(fluid_voice_t* voice, int i, float val)
* @return Current generator value
*/
float
-fluid_voice_gen_get(fluid_voice_t* voice, int gen)
+fluid_voice_gen_get(fluid_voice_t *voice, int gen)
{
- return voice->gen[gen].val;
+ return voice->gen[gen].val;
}
-fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num)
+fluid_real_t fluid_voice_gen_value(const fluid_voice_t *voice, int num)
{
- /* This is an extension to the SoundFont standard. More
- * documentation is available at the fluid_synth_set_gen2()
- * function. */
- if (voice->gen[num].flags == GEN_ABS_NRPN) {
- return (fluid_real_t) voice->gen[num].nrpn;
- } else {
- return (fluid_real_t) (voice->gen[num].val + voice->gen[num].mod + voice->gen[num].nrpn);
- }
+ /* This is an extension to the SoundFont standard. More
+ * documentation is available at the fluid_synth_set_gen2()
+ * function. */
+ if(voice->gen[num].flags == GEN_ABS_NRPN)
+ {
+ return (fluid_real_t) voice->gen[num].nrpn;
+ }
+ else
+ {
+ return (fluid_real_t)(voice->gen[num].val + voice->gen[num].mod + voice->gen[num].nrpn);
+ }
}
-
-/**
- * Synthesize a voice to a buffer.
- *
- * @param voice Voice to synthesize
- * @param dsp_buf Audio buffer to synthesize to (#FLUID_BUFSIZE in length)
- * @return Count of samples written to dsp_buf (can be 0)
- *
- * Panning, reverb and chorus are processed separately. The dsp interpolation
- * routine is in (fluid_dsp_float.c).
+/*
+ * fluid_voice_start
*/
-int
-fluid_voice_write (fluid_voice_t* voice, fluid_real_t *dsp_buf)
+void fluid_voice_start(fluid_voice_t *voice)
{
- int result;
- if (!voice->can_access_rvoice)
- return 0;
+ /* The maximum volume of the loop is calculated and cached once for each
+ * sample with its nominal loop settings. This happens, when the sample is used
+ * for the first time.*/
- result = fluid_rvoice_write(voice->rvoice, dsp_buf);
+ fluid_voice_calculate_runtime_synthesis_parameters(voice);
- if (result == -1)
- return 0;
+#ifdef WITH_PROFILING
+ voice->ref = fluid_profile_ref();
+#endif
- if ((result < FLUID_BUFSIZE) && _PLAYING(voice)) /* Voice finished by itself */
- fluid_voice_off(voice);
+ voice->status = FLUID_VOICE_ON;
- return result;
+ /* Increment voice count */
+ voice->channel->synth->active_voice_count++;
}
-
/**
- * Mix voice data to left/right (panning), reverb and chorus buffers.
- * @param count Number of samples
- * @param dsp_buf Source buffer
- * @param voice Voice to mix
- * @param left_buf Left audio buffer
- * @param right_buf Right audio buffer
- * @param reverb_buf Reverb buffer
- * @param chorus_buf Chorus buffer
+ * Calculate the amplitude of a voice.
*
+ * @param gain The gain value in the range [0.0 ; 1.0]
+ * @return An amplitude used by rvoice_mixer's buffers
*/
-void
-fluid_voice_mix (fluid_voice_t *voice, int count, fluid_real_t* dsp_buf,
- fluid_real_t* left_buf, fluid_real_t* right_buf,
- fluid_real_t* reverb_buf, fluid_real_t* chorus_buf)
+static FLUID_INLINE fluid_real_t
+fluid_voice_calculate_gain_amplitude(const fluid_voice_t *voice, fluid_real_t gain)
{
- fluid_rvoice_buffers_t buffers;
- fluid_real_t* dest_buf[4] = {left_buf, right_buf, reverb_buf, chorus_buf};
-
- fluid_rvoice_buffers_set_amp(&buffers, 0, voice->amp_left);
- fluid_rvoice_buffers_set_amp(&buffers, 1, voice->amp_right);
- fluid_rvoice_buffers_set_amp(&buffers, 2, voice->amp_reverb);
- fluid_rvoice_buffers_set_amp(&buffers, 3, voice->amp_chorus);
-
- fluid_rvoice_buffers_mix(&buffers, dsp_buf, count, dest_buf, 4);
-
- fluid_check_fpe ("voice_mix");
+ /* we use 24bit samples in fluid_rvoice_dsp. in order to normalize float
+ * samples to [0.0;1.0] divide samples by the max. value of an int24 and
+ * amplify them with the gain */
+ return gain * voice->synth_gain / (INT24_MAX * 1.0f);
}
-
-
-/*
- * fluid_voice_start
- */
-void fluid_voice_start(fluid_voice_t* voice)
+/* Useful to return the nominal pitch of a key */
+/* The nominal pitch is dependant of voice->root_pitch,tuning, and
+ GEN_SCALETUNE generator.
+ This is useful to set the value of GEN_PITCH generator on noteOn.
+ This is useful to get the beginning/ending pitch for portamento.
+*/
+fluid_real_t fluid_voice_calculate_pitch(fluid_voice_t *voice, int key)
{
- /* The maximum volume of the loop is calculated and cached once for each
- * sample with its nominal loop settings. This happens, when the sample is used
- * for the first time.*/
-
- fluid_voice_calculate_runtime_synthesis_parameters(voice);
-
- voice->ref = fluid_profile_ref();
-
- voice->status = FLUID_VOICE_ON;
+ fluid_tuning_t *tuning;
+ fluid_real_t x, pitch;
+
+ /* Now the nominal pitch of the key is returned.
+ * Note about SCALETUNE: SF2.01 8.1.3 says, that this generator is a
+ * non-realtime parameter. So we don't allow modulation (as opposed
+ * to fluid_voice_gen_value(voice, GEN_SCALETUNE) When the scale tuning is varied,
+ * one key remains fixed. Here C3 (MIDI number 60) is used.
+ */
+ if(fluid_channel_has_tuning(voice->channel))
+ {
+ tuning = fluid_channel_get_tuning(voice->channel);
+ x = fluid_tuning_get_pitch(tuning, (int)(voice->root_pitch / 100.0f));
+ pitch = voice->gen[GEN_SCALETUNE].val / 100.0f *
+ (fluid_tuning_get_pitch(tuning, key) - x) + x;
+ }
+ else
+ {
+ pitch = voice->gen[GEN_SCALETUNE].val
+ * (key - voice->root_pitch / 100.0f) + voice->root_pitch;
+ }
- /* Increment voice count */
- voice->channel->synth->active_voice_count++;
+ return pitch;
}
-void
-fluid_voice_calculate_gen_pitch(fluid_voice_t* voice)
+void
+fluid_voice_calculate_gen_pitch(fluid_voice_t *voice)
{
- fluid_tuning_t* tuning;
- fluid_real_t x;
-
- /* The GEN_PITCH is a hack to fit the pitch bend controller into the
- * modulator paradigm. Now the nominal pitch of the key is set.
- * Note about SCALETUNE: SF2.01 8.1.3 says, that this generator is a
- * non-realtime parameter. So we don't allow modulation (as opposed
- * to _GEN(voice, GEN_SCALETUNE) When the scale tuning is varied,
- * one key remains fixed. Here C3 (MIDI number 60) is used.
- */
- if (fluid_channel_has_tuning(voice->channel)) {
- tuning = fluid_channel_get_tuning (voice->channel);
- x = fluid_tuning_get_pitch (tuning, (int)(voice->root_pitch / 100.0f));
- voice->gen[GEN_PITCH].val = voice->gen[GEN_SCALETUNE].val / 100.0f *
- (fluid_tuning_get_pitch (tuning, voice->key) - x) + x;
- } else {
- voice->gen[GEN_PITCH].val = voice->gen[GEN_SCALETUNE].val
- * (voice->key - voice->root_pitch / 100.0f) + voice->root_pitch;
- }
-
+ voice->gen[GEN_PITCH].val = fluid_voice_calculate_pitch(voice, fluid_voice_get_actual_key(voice));
}
+
/*
* fluid_voice_calculate_runtime_synthesis_parameters
*
@@ -500,176 +528,206 @@ fluid_voice_calculate_gen_pitch(fluid_voice_t* voice)
* example, for the pitch since it is modulated by the controllers in
* cents. */
static int
-fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice)
+fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t *voice)
{
- int i;
-
- int list_of_generators_to_initialize[35] = {
- GEN_STARTADDROFS, /* SF2.01 page 48 #0 */
- GEN_ENDADDROFS, /* #1 */
- GEN_STARTLOOPADDROFS, /* #2 */
- GEN_ENDLOOPADDROFS, /* #3 */
- /* GEN_STARTADDRCOARSEOFS see comment below [1] #4 */
- GEN_MODLFOTOPITCH, /* #5 */
- GEN_VIBLFOTOPITCH, /* #6 */
- GEN_MODENVTOPITCH, /* #7 */
- GEN_FILTERFC, /* #8 */
- GEN_FILTERQ, /* #9 */
- GEN_MODLFOTOFILTERFC, /* #10 */
- GEN_MODENVTOFILTERFC, /* #11 */
- /* GEN_ENDADDRCOARSEOFS [1] #12 */
- GEN_MODLFOTOVOL, /* #13 */
- /* not defined #14 */
- GEN_CHORUSSEND, /* #15 */
- GEN_REVERBSEND, /* #16 */
- GEN_PAN, /* #17 */
- /* not defined #18 */
- /* not defined #19 */
- /* not defined #20 */
- GEN_MODLFODELAY, /* #21 */
- GEN_MODLFOFREQ, /* #22 */
- GEN_VIBLFODELAY, /* #23 */
- GEN_VIBLFOFREQ, /* #24 */
- GEN_MODENVDELAY, /* #25 */
- GEN_MODENVATTACK, /* #26 */
- GEN_MODENVHOLD, /* #27 */
- GEN_MODENVDECAY, /* #28 */
- /* GEN_MODENVSUSTAIN [1] #29 */
- GEN_MODENVRELEASE, /* #30 */
- /* GEN_KEYTOMODENVHOLD [1] #31 */
- /* GEN_KEYTOMODENVDECAY [1] #32 */
- GEN_VOLENVDELAY, /* #33 */
- GEN_VOLENVATTACK, /* #34 */
- GEN_VOLENVHOLD, /* #35 */
- GEN_VOLENVDECAY, /* #36 */
- /* GEN_VOLENVSUSTAIN [1] #37 */
- GEN_VOLENVRELEASE, /* #38 */
- /* GEN_KEYTOVOLENVHOLD [1] #39 */
- /* GEN_KEYTOVOLENVDECAY [1] #40 */
- /* GEN_STARTLOOPADDRCOARSEOFS [1] #45 */
- GEN_KEYNUM, /* #46 */
- GEN_VELOCITY, /* #47 */
- GEN_ATTENUATION, /* #48 */
- /* GEN_ENDLOOPADDRCOARSEOFS [1] #50 */
- /* GEN_COARSETUNE [1] #51 */
- /* GEN_FINETUNE [1] #52 */
- GEN_OVERRIDEROOTKEY, /* #58 */
- GEN_PITCH, /* --- */
- -1}; /* end-of-list marker */
-
- /* When the voice is made ready for the synthesis process, a lot of
- * voice-internal parameters have to be calculated.
- *
- * At this point, the sound font has already set the -nominal- value
- * for all generators (excluding GEN_PITCH). Most generators can be
- * modulated - they include a nominal value and an offset (which
- * changes with velocity, note number, channel parameters like
- * aftertouch, mod wheel...) Now this offset will be calculated as
- * follows:
- *
- * - Process each modulator once.
- * - Calculate its output value.
- * - Find the target generator.
- * - Add the output value to the modulation value of the generator.
- *
- * Note: The generators have been initialized with
- * fluid_gen_set_default_values.
- */
-
- for (i = 0; i < voice->mod_count; i++) {
- fluid_mod_t* mod = &voice->mod[i];
- fluid_real_t modval = fluid_mod_get_value(mod, voice->channel, voice);
- int dest_gen_index = mod->dest;
- fluid_gen_t* dest_gen = &voice->gen[dest_gen_index];
- dest_gen->mod += modval;
- /* fluid_dump_modulator(mod); */
- }
-
- /* Now the generators are initialized, nominal and modulation value.
- * The voice parameters (which depend on generators) are calculated
- * with fluid_voice_update_param. Processing the list of generator
- * changes will calculate each voice parameter once.
- *
- * Note [1]: Some voice parameters depend on several generators. For
- * example, the pitch depends on GEN_COARSETUNE, GEN_FINETUNE and
- * GEN_PITCH. voice->pitch. Unnecessary recalculation is avoided
- * by removing all but one generator from the list of voice
- * parameters. Same with GEN_XXX and GEN_XXXCOARSE: the
- * initialisation list contains only GEN_XXX.
- */
-
- /* Calculate the voice parameter(s) dependent on each generator. */
- for (i = 0; list_of_generators_to_initialize[i] != -1; i++) {
- fluid_voice_update_param(voice, list_of_generators_to_initialize[i]);
- }
-
- /* Make an estimate on how loud this voice can get at any time (attenuation). */
- UPDATE_RVOICE_R1(fluid_rvoice_set_min_attenuation_cB,
- fluid_voice_get_lower_boundary_for_attenuation(voice));
- return FLUID_OK;
+ int i;
+ unsigned int n;
+
+ static int const list_of_generators_to_initialize[] =
+ {
+ GEN_STARTADDROFS, /* SF2.01 page 48 #0 */
+ GEN_ENDADDROFS, /* #1 */
+ GEN_STARTLOOPADDROFS, /* #2 */
+ GEN_ENDLOOPADDROFS, /* #3 */
+ /* GEN_STARTADDRCOARSEOFS see comment below [1] #4 */
+ GEN_MODLFOTOPITCH, /* #5 */
+ GEN_VIBLFOTOPITCH, /* #6 */
+ GEN_MODENVTOPITCH, /* #7 */
+ GEN_FILTERFC, /* #8 */
+ GEN_FILTERQ, /* #9 */
+ GEN_MODLFOTOFILTERFC, /* #10 */
+ GEN_MODENVTOFILTERFC, /* #11 */
+ /* GEN_ENDADDRCOARSEOFS [1] #12 */
+ GEN_MODLFOTOVOL, /* #13 */
+ /* not defined #14 */
+ GEN_CHORUSSEND, /* #15 */
+ GEN_REVERBSEND, /* #16 */
+ GEN_PAN, /* #17 */
+ /* not defined #18 */
+ /* not defined #19 */
+ /* not defined #20 */
+ GEN_MODLFODELAY, /* #21 */
+ GEN_MODLFOFREQ, /* #22 */
+ GEN_VIBLFODELAY, /* #23 */
+ GEN_VIBLFOFREQ, /* #24 */
+ GEN_MODENVDELAY, /* #25 */
+ GEN_MODENVATTACK, /* #26 */
+ GEN_MODENVHOLD, /* #27 */
+ GEN_MODENVDECAY, /* #28 */
+ /* GEN_MODENVSUSTAIN [1] #29 */
+ GEN_MODENVRELEASE, /* #30 */
+ /* GEN_KEYTOMODENVHOLD [1] #31 */
+ /* GEN_KEYTOMODENVDECAY [1] #32 */
+ GEN_VOLENVDELAY, /* #33 */
+ GEN_VOLENVATTACK, /* #34 */
+ GEN_VOLENVHOLD, /* #35 */
+ GEN_VOLENVDECAY, /* #36 */
+ /* GEN_VOLENVSUSTAIN [1] #37 */
+ GEN_VOLENVRELEASE, /* #38 */
+ /* GEN_KEYTOVOLENVHOLD [1] #39 */
+ /* GEN_KEYTOVOLENVDECAY [1] #40 */
+ /* GEN_STARTLOOPADDRCOARSEOFS [1] #45 */
+ GEN_KEYNUM, /* #46 */
+ GEN_VELOCITY, /* #47 */
+ GEN_ATTENUATION, /* #48 */
+ /* GEN_ENDLOOPADDRCOARSEOFS [1] #50 */
+ /* GEN_COARSETUNE [1] #51 */
+ /* GEN_FINETUNE [1] #52 */
+ GEN_OVERRIDEROOTKEY, /* #58 */
+ GEN_PITCH, /* --- */
+ GEN_CUSTOM_BALANCE, /* --- */
+ GEN_CUSTOM_FILTERFC, /* --- */
+ GEN_CUSTOM_FILTERQ /* --- */
+ };
+
+ /* When the voice is made ready for the synthesis process, a lot of
+ * voice-internal parameters have to be calculated.
+ *
+ * At this point, the sound font has already set the -nominal- value
+ * for all generators (excluding GEN_PITCH). Most generators can be
+ * modulated - they include a nominal value and an offset (which
+ * changes with velocity, note number, channel parameters like
+ * aftertouch, mod wheel...) Now this offset will be calculated as
+ * follows:
+ *
+ * - Process each modulator once.
+ * - Calculate its output value.
+ * - Find the target generator.
+ * - Add the output value to the modulation value of the generator.
+ *
+ * Note: The generators have been initialized with
+ * fluid_gen_set_default_values.
+ */
+
+ for(i = 0; i < voice->mod_count; i++)
+ {
+ fluid_mod_t *mod = &voice->mod[i];
+ fluid_real_t modval = fluid_mod_get_value(mod, voice);
+ int dest_gen_index = mod->dest;
+ fluid_gen_t *dest_gen = &voice->gen[dest_gen_index];
+ dest_gen->mod += modval;
+ /* fluid_dump_modulator(mod); */
+ }
+
+ /* Now the generators are initialized, nominal and modulation value.
+ * The voice parameters (which depend on generators) are calculated
+ * with fluid_voice_update_param. Processing the list of generator
+ * changes will calculate each voice parameter once.
+ *
+ * Note [1]: Some voice parameters depend on several generators. For
+ * example, the pitch depends on GEN_COARSETUNE, GEN_FINETUNE and
+ * GEN_PITCH. voice->pitch. Unnecessary recalculation is avoided
+ * by removing all but one generator from the list of voice
+ * parameters. Same with GEN_XXX and GEN_XXXCOARSE: the
+ * initialisation list contains only GEN_XXX.
+ */
+
+ /* Calculate the voice parameter(s) dependent on each generator. */
+ for(n = 0; n < FLUID_N_ELEMENTS(list_of_generators_to_initialize); n++)
+ {
+ fluid_voice_update_param(voice, list_of_generators_to_initialize[n]);
+ }
+
+ /* Start portamento if enabled */
+ {
+ /* fromkey note comes from "GetFromKeyPortamentoLegato()" detector.
+ When fromkey is set to ValidNote , portamento is started */
+ /* Return fromkey portamento */
+ int fromkey = voice->channel->synth->fromkey_portamento;
+
+ if(fluid_channel_is_valid_note(fromkey))
+ {
+ /* Send portamento parameters to the voice dsp */
+ fluid_voice_update_portamento(voice, fromkey, fluid_voice_get_actual_key(voice));
+ }
+ }
+
+ /* Make an estimate on how loud this voice can get at any time (attenuation). */
+ UPDATE_RVOICE_R1(fluid_rvoice_set_min_attenuation_cB,
+ fluid_voice_get_lower_boundary_for_attenuation(voice));
+ return FLUID_OK;
}
/*
* calculate_hold_decay_buffers
*/
static int
-calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
+calculate_hold_decay_buffers(fluid_voice_t *voice, int gen_base,
int gen_key2base, int is_decay)
{
- /* Purpose:
- *
- * Returns the number of DSP loops, that correspond to the hold
- * (is_decay=0) or decay (is_decay=1) time.
- * gen_base=GEN_VOLENVHOLD, GEN_VOLENVDECAY, GEN_MODENVHOLD,
- * GEN_MODENVDECAY gen_key2base=GEN_KEYTOVOLENVHOLD,
- * GEN_KEYTOVOLENVDECAY, GEN_KEYTOMODENVHOLD, GEN_KEYTOMODENVDECAY
- */
-
- fluid_real_t timecents;
- fluid_real_t seconds;
- int buffers;
-
- /* SF2.01 section 8.4.3 # 31, 32, 39, 40
- * GEN_KEYTOxxxENVxxx uses key 60 as 'origin'.
- * The unit of the generator is timecents per key number.
- * If KEYTOxxxENVxxx is 100, a key one octave over key 60 (72)
- * will cause (60-72)*100=-1200 timecents of time variation.
- * The time is cut in half.
- */
- timecents = (_GEN(voice, gen_base) + _GEN(voice, gen_key2base) * (60.0 - voice->key));
-
- /* Range checking */
- if (is_decay){
- /* SF 2.01 section 8.1.3 # 28, 36 */
- if (timecents > 8000.0) {
- timecents = 8000.0;
+ /* Purpose:
+ *
+ * Returns the number of DSP loops, that correspond to the hold
+ * (is_decay=0) or decay (is_decay=1) time.
+ * gen_base=GEN_VOLENVHOLD, GEN_VOLENVDECAY, GEN_MODENVHOLD,
+ * GEN_MODENVDECAY gen_key2base=GEN_KEYTOVOLENVHOLD,
+ * GEN_KEYTOVOLENVDECAY, GEN_KEYTOMODENVHOLD, GEN_KEYTOMODENVDECAY
+ */
+
+ fluid_real_t timecents;
+ fluid_real_t seconds;
+ int buffers;
+
+ /* SF2.01 section 8.4.3 # 31, 32, 39, 40
+ * GEN_KEYTOxxxENVxxx uses key 60 as 'origin'.
+ * The unit of the generator is timecents per key number.
+ * If KEYTOxxxENVxxx is 100, a key one octave over key 60 (72)
+ * will cause (60-72)*100=-1200 timecents of time variation.
+ * The time is cut in half.
+ */
+ timecents = (fluid_voice_gen_value(voice, gen_base) + fluid_voice_gen_value(voice, gen_key2base) * (60.0 - fluid_voice_get_actual_key(voice)));
+
+ /* Range checking */
+ if(is_decay)
+ {
+ /* SF 2.01 section 8.1.3 # 28, 36 */
+ if(timecents > 8000.0)
+ {
+ timecents = 8000.0;
+ }
}
- } else {
- /* SF 2.01 section 8.1.3 # 27, 35 */
- if (timecents > 5000) {
- timecents = 5000.0;
+ else
+ {
+ /* SF 2.01 section 8.1.3 # 27, 35 */
+ if(timecents > 5000)
+ {
+ timecents = 5000.0;
+ }
+
+ /* SF 2.01 section 8.1.2 # 27, 35:
+ * The most negative number indicates no hold time
+ */
+ if(timecents <= -32768.)
+ {
+ return 0;
+ }
}
- /* SF 2.01 section 8.1.2 # 27, 35:
- * The most negative number indicates no hold time
- */
- if (timecents <= -32768.) {
- return 0;
+
+ /* SF 2.01 section 8.1.3 # 27, 28, 35, 36 */
+ if(timecents < -12000.0)
+ {
+ timecents = -12000.0;
}
- }
- /* SF 2.01 section 8.1.3 # 27, 28, 35, 36 */
- if (timecents < -12000.0) {
- timecents = -12000.0;
- }
- seconds = fluid_tc2sec(timecents);
- /* Each DSP loop processes FLUID_BUFSIZE samples. */
+ seconds = fluid_tc2sec(timecents);
+ /* Each DSP loop processes FLUID_BUFSIZE samples. */
- /* round to next full number of buffers */
- buffers = (int)(((fluid_real_t)voice->output_rate * seconds)
- / (fluid_real_t)FLUID_BUFSIZE
- +0.5);
+ /* round to next full number of buffers */
+ buffers = (int)(((fluid_real_t)voice->output_rate * seconds)
+ / (fluid_real_t)FLUID_BUFSIZE
+ + 0.5);
- return buffers;
+ return buffers;
}
/*
@@ -684,7 +742,7 @@ calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
*
* Note: The generator holds three values: The base value .val, an
* offset caused by modulators .mod, and an offset caused by the
- * NRPN system. _GEN(voice, generator_enumerator) returns the sum
+ * NRPN system. fluid_voice_gen_value(voice, generator_enumerator) returns the sum
* of all three.
*/
/**
@@ -696,236 +754,245 @@ calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
* Most applications will not need this function.
*/
void
-fluid_voice_update_param(fluid_voice_t* voice, int gen)
+fluid_voice_update_param(fluid_voice_t *voice, int gen)
{
- double q_dB;
- fluid_real_t x;
- fluid_real_t y;
- unsigned int count, z;
- // Alternate attenuation scale used by EMU10K1 cards when setting the attenuation at the preset or instrument level within the SoundFont bank.
- static const float ALT_ATTENUATION_SCALE = 0.4;
-
- switch (gen) {
-
- case GEN_PAN:
- /* range checking is done in the fluid_pan function */
- voice->pan = _GEN(voice, GEN_PAN);
- voice->amp_left = fluid_pan(voice->pan, 1) * voice->synth_gain / 32768.0f;
- voice->amp_right = fluid_pan(voice->pan, 0) * voice->synth_gain / 32768.0f;
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 0, voice->amp_left);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 1, voice->amp_right);
- break;
-
- case GEN_ATTENUATION:
- voice->attenuation = ((fluid_real_t)(voice)->gen[GEN_ATTENUATION].val*ALT_ATTENUATION_SCALE) +
- (fluid_real_t)(voice)->gen[GEN_ATTENUATION].mod + (fluid_real_t)(voice)->gen[GEN_ATTENUATION].nrpn;
-
- /* Range: SF2.01 section 8.1.3 # 48
- * Motivation for range checking:
- * OHPiano.SF2 sets initial attenuation to a whooping -96 dB */
- fluid_clip(voice->attenuation, 0.0, 1440.0);
- UPDATE_RVOICE_R1(fluid_rvoice_set_attenuation, voice->attenuation);
- break;
+ unsigned int count, z;
+ fluid_real_t x = fluid_voice_gen_value(voice, gen);
+
+ switch(gen)
+ {
+
+ case GEN_PAN:
+ case GEN_CUSTOM_BALANCE:
+ /* range checking is done in the fluid_pan and fluid_balance functions */
+ voice->pan = fluid_voice_gen_value(voice, GEN_PAN);
+ voice->balance = fluid_voice_gen_value(voice, GEN_CUSTOM_BALANCE);
+
+ /* left amp */
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 0,
+ fluid_voice_calculate_gain_amplitude(voice,
+ fluid_pan(voice->pan, 1) * fluid_balance(voice->balance, 1)));
+
+ /* right amp */
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 1,
+ fluid_voice_calculate_gain_amplitude(voice,
+ fluid_pan(voice->pan, 0) * fluid_balance(voice->balance, 0)));
+ break;
+
+ case GEN_ATTENUATION:
+ voice->attenuation = x;
+
+ /* Range: SF2.01 section 8.1.3 # 48
+ * Motivation for range checking:
+ * OHPiano.SF2 sets initial attenuation to a whooping -96 dB */
+ fluid_clip(voice->attenuation, 0.0, 1440.0);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_attenuation, voice->attenuation);
+ break;
/* The pitch is calculated from three different generators.
* Read comment in fluidsynth.h about GEN_PITCH.
*/
- case GEN_PITCH:
- case GEN_COARSETUNE:
- case GEN_FINETUNE:
- /* The testing for allowed range is done in 'fluid_ct2hz' */
- voice->pitch = (_GEN(voice, GEN_PITCH)
- + 100.0f * _GEN(voice, GEN_COARSETUNE)
- + _GEN(voice, GEN_FINETUNE));
- UPDATE_RVOICE_R1(fluid_rvoice_set_pitch, voice->pitch);
- break;
-
- case GEN_REVERBSEND:
- /* The generator unit is 'tenths of a percent'. */
- voice->reverb_send = _GEN(voice, GEN_REVERBSEND) / 1000.0f;
- fluid_clip(voice->reverb_send, 0.0, 1.0);
- voice->amp_reverb = voice->reverb_send * voice->synth_gain / 32768.0f;
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 2, voice->amp_reverb);
- break;
-
- case GEN_CHORUSSEND:
- /* The generator unit is 'tenths of a percent'. */
- voice->chorus_send = _GEN(voice, GEN_CHORUSSEND) / 1000.0f;
- fluid_clip(voice->chorus_send, 0.0, 1.0);
- voice->amp_chorus = voice->chorus_send * voice->synth_gain / 32768.0f;
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 3, voice->amp_chorus);
- break;
-
- case GEN_OVERRIDEROOTKEY:
- /* This is a non-realtime parameter. Therefore the .mod part of the generator
- * can be neglected.
- * NOTE: origpitch sets MIDI root note while pitchadj is a fine tuning amount
- * which offsets the original rate. This means that the fine tuning is
- * inverted with respect to the root note (so subtract it, not add).
- */
- if (voice->sample != NULL) {
- if (voice->gen[GEN_OVERRIDEROOTKEY].val > -1) //FIXME: use flag instead of -1
- voice->root_pitch = voice->gen[GEN_OVERRIDEROOTKEY].val * 100.0f
- - voice->sample->pitchadj;
- else
- voice->root_pitch = voice->sample->origpitch * 100.0f - voice->sample->pitchadj;
- x = (fluid_ct2hz(voice->root_pitch) * ((fluid_real_t) voice->output_rate / voice->sample->samplerate));
- } else {
- if (voice->gen[GEN_OVERRIDEROOTKEY].val > -1) //FIXME: use flag instead of -1
- voice->root_pitch = voice->gen[GEN_OVERRIDEROOTKEY].val * 100.0f;
- else
- voice->root_pitch = 0;
- x = fluid_ct2hz(voice->root_pitch);
- }
- /* voice->pitch depends on voice->root_pitch, so calculate voice->pitch now */
- fluid_voice_calculate_gen_pitch(voice);
- UPDATE_RVOICE_R1(fluid_rvoice_set_root_pitch_hz, x);
-
- break;
-
- case GEN_FILTERFC:
- /* The resonance frequency is converted from absolute cents to
- * midicents .val and .mod are both used, this permits real-time
- * modulation. The allowed range is tested in the 'fluid_ct2hz'
- * function [PH,20021214]
- */
- x = _GEN(voice, GEN_FILTERFC);
- UPDATE_RVOICE_FILTER1(fluid_iir_filter_set_fres, x);
- break;
-
- case GEN_FILTERQ:
- /* The generator contains 'centibels' (1/10 dB) => divide by 10 to
- * obtain dB */
- q_dB = _GEN(voice, GEN_FILTERQ) / 10.0f;
+ case GEN_PITCH:
+ case GEN_COARSETUNE:
+ case GEN_FINETUNE:
+ /* The testing for allowed range is done in 'fluid_ct2hz' */
+ voice->pitch = (fluid_voice_gen_value(voice, GEN_PITCH)
+ + 100.0f * fluid_voice_gen_value(voice, GEN_COARSETUNE)
+ + fluid_voice_gen_value(voice, GEN_FINETUNE));
+ UPDATE_RVOICE_R1(fluid_rvoice_set_pitch, voice->pitch);
+ break;
+
+ case GEN_REVERBSEND:
+ /* The generator unit is 'tenths of a percent'. */
+ voice->reverb_send = x / 1000.0f;
+ fluid_clip(voice->reverb_send, 0.0, 1.0);
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 2, fluid_voice_calculate_gain_amplitude(voice, voice->reverb_send));
+ break;
+
+ case GEN_CHORUSSEND:
+ /* The generator unit is 'tenths of a percent'. */
+ voice->chorus_send = x / 1000.0f;
+ fluid_clip(voice->chorus_send, 0.0, 1.0);
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 3, fluid_voice_calculate_gain_amplitude(voice, voice->chorus_send));
+ break;
+
+ case GEN_OVERRIDEROOTKEY:
+
+ /* This is a non-realtime parameter. Therefore the .mod part of the generator
+ * can be neglected.
+ * NOTE: origpitch sets MIDI root note while pitchadj is a fine tuning amount
+ * which offsets the original rate. This means that the fine tuning is
+ * inverted with respect to the root note (so subtract it, not add).
+ */
+ if(voice->sample != NULL)
+ {
+ if(voice->gen[GEN_OVERRIDEROOTKEY].val > -1) //FIXME: use flag instead of -1
+ {
+ voice->root_pitch = voice->gen[GEN_OVERRIDEROOTKEY].val * 100.0f
+ - voice->sample->pitchadj;
+ }
+ else
+ {
+ voice->root_pitch = voice->sample->origpitch * 100.0f - voice->sample->pitchadj;
+ }
+
+ x = (fluid_ct2hz(voice->root_pitch) * ((fluid_real_t) voice->output_rate / voice->sample->samplerate));
+ }
+ else
+ {
+ if(voice->gen[GEN_OVERRIDEROOTKEY].val > -1) //FIXME: use flag instead of -1
+ {
+ voice->root_pitch = voice->gen[GEN_OVERRIDEROOTKEY].val * 100.0f;
+ }
+ else
+ {
+ voice->root_pitch = 0;
+ }
+
+ x = fluid_ct2hz(voice->root_pitch);
+ }
+
+ /* voice->pitch depends on voice->root_pitch, so calculate voice->pitch now */
+ fluid_voice_calculate_gen_pitch(voice);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_root_pitch_hz, x);
+
+ break;
+
+ case GEN_FILTERFC:
+ /* The resonance frequency is converted from absolute cents to
+ * midicents .val and .mod are both used, this permits real-time
+ * modulation. The allowed range is tested in the 'fluid_ct2hz'
+ * function [PH,20021214]
+ */
+ UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_fres, &voice->rvoice->resonant_filter, x);
+ break;
+
+ case GEN_FILTERQ:
+ UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_q, &voice->rvoice->resonant_filter, x);
+ break;
+
+ /* same as the two above, only for the custom filter */
+ case GEN_CUSTOM_FILTERFC:
+ UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_fres, &voice->rvoice->resonant_custom_filter, x);
+ break;
+
+ case GEN_CUSTOM_FILTERQ:
+ UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_q, &voice->rvoice->resonant_custom_filter, x);
+ break;
+
+ case GEN_MODLFOTOPITCH:
+ fluid_clip(x, -12000.0, 12000.0);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_pitch, x);
+ break;
+
+ case GEN_MODLFOTOVOL:
+ fluid_clip(x, -960.0, 960.0);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_vol, x);
+ break;
+
+ case GEN_MODLFOTOFILTERFC:
+ fluid_clip(x, -12000, 12000);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_fc, x);
+ break;
+
+ case GEN_MODLFODELAY:
+ fluid_clip(x, -12000.0f, 5000.0f);
+ z = (unsigned int)(voice->output_rate * fluid_tc2sec_delay(x));
+ UPDATE_RVOICE_ENVLFO_I1(fluid_lfo_set_delay, modlfo, z);
+ break;
+
+ case GEN_MODLFOFREQ:
+ /* - the frequency is converted into a delta value, per buffer of FLUID_BUFSIZE samples
+ * - the delay into a sample delay
+ */
+ fluid_clip(x, -16000.0f, 4500.0f);
+ x = (4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->output_rate);
+ UPDATE_RVOICE_ENVLFO_R1(fluid_lfo_set_incr, modlfo, x);
+ break;
+
+ case GEN_VIBLFOFREQ:
+ /* vib lfo
+ *
+ * - the frequency is converted into a delta value, per buffer of FLUID_BUFSIZE samples
+ * - the delay into a sample delay
+ */
+ fluid_clip(x, -16000.0f, 4500.0f);
+ x = 4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->output_rate;
+ UPDATE_RVOICE_ENVLFO_R1(fluid_lfo_set_incr, viblfo, x);
+ break;
+
+ case GEN_VIBLFODELAY:
+ fluid_clip(x, -12000.0f, 5000.0f);
+ z = (unsigned int)(voice->output_rate * fluid_tc2sec_delay(x));
+ UPDATE_RVOICE_ENVLFO_I1(fluid_lfo_set_delay, viblfo, z);
+ break;
+
+ case GEN_VIBLFOTOPITCH:
+ fluid_clip(x, -12000.0, 12000.0);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_viblfo_to_pitch, x);
+ break;
+
+ case GEN_KEYNUM:
+ /* GEN_KEYNUM: SF2.01 page 46, item 46
+ *
+ * If this generator is active, it forces the key number to its
+ * value. Non-realtime controller.
+ *
+ * There is a flag, which should indicate, whether a generator is
+ * enabled or not. But here we rely on the default value of -1.
+ */
+
+ /* 2017-09-02: do not change the voice's key here, otherwise it will
+ * never be released on a noteoff event
+ */
+#if 0
+ x = fluid_voice_gen_value(voice, GEN_KEYNUM);
- /* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */
- fluid_clip(q_dB, 0.0f, 96.0f);
+ if(x >= 0)
+ {
+ voice->key = x;
+ }
- /* Short version: Modify the Q definition in a way, that a Q of 0
- * dB leads to no resonance hump in the freq. response.
- *
- * Long version: From SF2.01, page 39, item 9 (initialFilterQ):
- * "The gain at the cutoff frequency may be less than zero when
- * zero is specified". Assume q_dB=0 / q_lin=1: If we would leave
- * q as it is, then this results in a 3 dB hump slightly below
- * fc. At fc, the gain is exactly the DC gain (0 dB). What is
- * (probably) meant here is that the filter does not show a
- * resonance hump for q_dB=0. In this case, the corresponding
- * q_lin is 1/sqrt(2)=0.707. The filter should have 3 dB of
- * attenuation at fc now. In this case Q_dB is the height of the
- * resonance peak not over the DC gain, but over the frequency
- * response of a non-resonant filter. This idea is implemented as
- * follows: */
- q_dB -= 3.01f;
- UPDATE_RVOICE_FILTER1(fluid_iir_filter_set_q_dB, q_dB);
-
- break;
-
- case GEN_MODLFOTOPITCH:
- x = _GEN(voice, GEN_MODLFOTOPITCH);
- fluid_clip(x, -12000.0, 12000.0);
- UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_pitch, x);
- break;
-
- case GEN_MODLFOTOVOL:
- x = _GEN(voice, GEN_MODLFOTOVOL);
- fluid_clip(x, -960.0, 960.0);
- UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_vol, x);
- break;
-
- case GEN_MODLFOTOFILTERFC:
- x = _GEN(voice, GEN_MODLFOTOFILTERFC);
- fluid_clip(x, -12000, 12000);
- UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_fc, x);
- break;
-
- case GEN_MODLFODELAY:
- x = _GEN(voice, GEN_MODLFODELAY);
- fluid_clip(x, -12000.0f, 5000.0f);
- z = (unsigned int) (voice->output_rate * fluid_tc2sec_delay(x));
- UPDATE_RVOICE_ENVLFO_I1(fluid_lfo_set_delay, modlfo, z);
- break;
-
- case GEN_MODLFOFREQ:
- /* - the frequency is converted into a delta value, per buffer of FLUID_BUFSIZE samples
- * - the delay into a sample delay
- */
- x = _GEN(voice, GEN_MODLFOFREQ);
- fluid_clip(x, -16000.0f, 4500.0f);
- x = (4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->output_rate);
- UPDATE_RVOICE_ENVLFO_R1(fluid_lfo_set_incr, modlfo, x);
- break;
-
- case GEN_VIBLFOFREQ:
- /* vib lfo
- *
- * - the frequency is converted into a delta value, per buffer of FLUID_BUFSIZE samples
- * - the delay into a sample delay
- */
- x = _GEN(voice, GEN_VIBLFOFREQ);
- fluid_clip(x, -16000.0f, 4500.0f);
- x = 4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->output_rate;
- UPDATE_RVOICE_ENVLFO_R1(fluid_lfo_set_incr, viblfo, x);
- break;
-
- case GEN_VIBLFODELAY:
- x = _GEN(voice,GEN_VIBLFODELAY);
- fluid_clip(x, -12000.0f, 5000.0f);
- z = (unsigned int) (voice->output_rate * fluid_tc2sec_delay(x));
- UPDATE_RVOICE_ENVLFO_I1(fluid_lfo_set_delay, viblfo, z);
- break;
-
- case GEN_VIBLFOTOPITCH:
- x = _GEN(voice, GEN_VIBLFOTOPITCH);
- fluid_clip(x, -12000.0, 12000.0);
- UPDATE_RVOICE_R1(fluid_rvoice_set_viblfo_to_pitch, x);
- break;
-
- case GEN_KEYNUM:
- /* GEN_KEYNUM: SF2.01 page 46, item 46
- *
- * If this generator is active, it forces the key number to its
- * value. Non-realtime controller.
- *
- * There is a flag, which should indicate, whether a generator is
- * enabled or not. But here we rely on the default value of -1.
- * */
- x = _GEN(voice, GEN_KEYNUM);
- if (x >= 0){
- voice->key = x;
- }
- break;
+#endif
+ break;
+
+ case GEN_VELOCITY:
+ /* GEN_VELOCITY: SF2.01 page 46, item 47
+ *
+ * If this generator is active, it forces the velocity to its
+ * value. Non-realtime controller.
+ *
+ * There is a flag, which should indicate, whether a generator is
+ * enabled or not. But here we rely on the default value of -1.
+ */
+ /* 2017-09-02: do not change the voice's velocity here, use
+ * fluid_voice_get_actual_velocity() to get the value of this generator
+ * if active.
+ */
+#if 0
+ x = fluid_voice_gen_value(voice, GEN_VELOCITY);
- case GEN_VELOCITY:
- /* GEN_VELOCITY: SF2.01 page 46, item 47
- *
- * If this generator is active, it forces the velocity to its
- * value. Non-realtime controller.
- *
- * There is a flag, which should indicate, whether a generator is
- * enabled or not. But here we rely on the default value of -1. */
- x = _GEN(voice, GEN_VELOCITY);
- if (x > 0) {
- voice->vel = x;
- }
- break;
+ if(x > 0)
+ {
+ voice->vel = x;
+ }
- case GEN_MODENVTOPITCH:
- x = _GEN(voice, GEN_MODENVTOPITCH);
- fluid_clip(x, -12000.0, 12000.0);
- UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_pitch, x);
- break;
+#endif
+ break;
- case GEN_MODENVTOFILTERFC:
- x = _GEN(voice,GEN_MODENVTOFILTERFC);
+ case GEN_MODENVTOPITCH:
+ fluid_clip(x, -12000.0, 12000.0);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_pitch, x);
+ break;
- /* Range: SF2.01 section 8.1.3 # 1
- * Motivation for range checking:
- * Filter is reported to make funny noises now and then
- */
- fluid_clip(x, -12000.0, 12000.0);
- UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_fc, x);
- break;
+ case GEN_MODENVTOFILTERFC:
+ /* Range: SF2.01 section 8.1.3 # 1
+ * Motivation for range checking:
+ * Filter is reported to make funny noises now and then
+ */
+ fluid_clip(x, -12000.0, 12000.0);
+ UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_fc, x);
+ break;
/* sample start and ends points
@@ -939,45 +1006,59 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
* end point ahead of the loop start point => invalid, then
* move the loop start point forward => valid again.
*/
- case GEN_STARTADDROFS: /* SF2.01 section 8.1.3 # 0 */
- case GEN_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */
- if (voice->sample != NULL) {
- z = (voice->sample->start
- + (int) _GEN(voice, GEN_STARTADDROFS)
- + 32768 * (int) _GEN(voice, GEN_STARTADDRCOARSEOFS));
- UPDATE_RVOICE_I1(fluid_rvoice_set_start, z);
- }
- break;
- case GEN_ENDADDROFS: /* SF2.01 section 8.1.3 # 1 */
- case GEN_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */
- if (voice->sample != NULL) {
- z = (voice->sample->end
- + (int) _GEN(voice, GEN_ENDADDROFS)
- + 32768 * (int) _GEN(voice, GEN_ENDADDRCOARSEOFS));
- UPDATE_RVOICE_I1(fluid_rvoice_set_end, z);
- }
- break;
- case GEN_STARTLOOPADDROFS: /* SF2.01 section 8.1.3 # 2 */
- case GEN_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */
- if (voice->sample != NULL) {
- z = (voice->sample->loopstart
- + (int) _GEN(voice, GEN_STARTLOOPADDROFS)
- + 32768 * (int) _GEN(voice, GEN_STARTLOOPADDRCOARSEOFS));
- UPDATE_RVOICE_I1(fluid_rvoice_set_loopstart, z);
- }
- break;
-
- case GEN_ENDLOOPADDROFS: /* SF2.01 section 8.1.3 # 3 */
- case GEN_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */
- if (voice->sample != NULL) {
- z = (voice->sample->loopend
- + (int) _GEN(voice, GEN_ENDLOOPADDROFS)
- + 32768 * (int) _GEN(voice, GEN_ENDLOOPADDRCOARSEOFS));
- UPDATE_RVOICE_I1(fluid_rvoice_set_loopend, z);
- }
- break;
-
- /* Conversion functions differ in range limit */
+ case GEN_STARTADDROFS: /* SF2.01 section 8.1.3 # 0 */
+ case GEN_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */
+ if(voice->sample != NULL)
+ {
+ fluid_real_t start_fine = fluid_voice_gen_value(voice, GEN_STARTADDROFS);
+ fluid_real_t start_coar = fluid_voice_gen_value(voice, GEN_STARTADDRCOARSEOFS);
+
+ z = voice->sample->start + (int)start_fine + 32768 * (int)start_coar;
+ UPDATE_RVOICE_I1(fluid_rvoice_set_start, z);
+ }
+
+ break;
+
+ case GEN_ENDADDROFS: /* SF2.01 section 8.1.3 # 1 */
+ case GEN_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */
+ if(voice->sample != NULL)
+ {
+ fluid_real_t end_fine = fluid_voice_gen_value(voice, GEN_ENDADDROFS);
+ fluid_real_t end_coar = fluid_voice_gen_value(voice, GEN_ENDADDRCOARSEOFS);
+
+ z = voice->sample->end + (int)end_fine + 32768 * (int)end_coar;
+ UPDATE_RVOICE_I1(fluid_rvoice_set_end, z);
+ }
+
+ break;
+
+ case GEN_STARTLOOPADDROFS: /* SF2.01 section 8.1.3 # 2 */
+ case GEN_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */
+ if(voice->sample != NULL)
+ {
+ fluid_real_t lstart_fine = fluid_voice_gen_value(voice, GEN_STARTLOOPADDROFS);
+ fluid_real_t lstart_coar = fluid_voice_gen_value(voice, GEN_STARTLOOPADDRCOARSEOFS);
+
+ z = voice->sample->loopstart + (int)lstart_fine + 32768 * (int)lstart_coar;
+ UPDATE_RVOICE_I1(fluid_rvoice_set_loopstart, z);
+ }
+
+ break;
+
+ case GEN_ENDLOOPADDROFS: /* SF2.01 section 8.1.3 # 3 */
+ case GEN_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */
+ if(voice->sample != NULL)
+ {
+ fluid_real_t lend_fine = fluid_voice_gen_value(voice, GEN_ENDLOOPADDROFS);
+ fluid_real_t lend_coar = fluid_voice_gen_value(voice, GEN_ENDLOOPADDRCOARSEOFS);
+
+ z = voice->sample->loopend + (int)lend_fine + 32768 * (int)lend_coar;
+ UPDATE_RVOICE_I1(fluid_rvoice_set_loopend, z);
+ }
+
+ break;
+
+ /* Conversion functions differ in range limit */
#define NUM_BUFFERS_DELAY(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_delay(_v) / FLUID_BUFSIZE)
#define NUM_BUFFERS_ATTACK(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_attack(_v) / FLUID_BUFSIZE)
#define NUM_BUFFERS_RELEASE(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_release(_v) / FLUID_BUFSIZE)
@@ -988,90 +1069,84 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
* - sustain is converted to its absolute value
* - attack, decay and release are converted to their increment per sample
*/
- case GEN_VOLENVDELAY: /* SF2.01 section 8.1.3 # 33 */
- x = _GEN(voice, GEN_VOLENVDELAY);
- fluid_clip(x, -12000.0f, 5000.0f);
- count = NUM_BUFFERS_DELAY(x);
- fluid_voice_update_volenv(voice, FLUID_VOICE_ENVDELAY,
- count, 0.0f, 0.0f, -1.0f, 1.0f);
- break;
-
- case GEN_VOLENVATTACK: /* SF2.01 section 8.1.3 # 34 */
- x = _GEN(voice, GEN_VOLENVATTACK);
- fluid_clip(x, -12000.0f, 8000.0f);
- count = 1 + NUM_BUFFERS_ATTACK(x);
- fluid_voice_update_volenv(voice, FLUID_VOICE_ENVATTACK,
- count, 1.0f, count ? 1.0f / count : 0.0f, -1.0f, 1.0f);
- break;
-
- case GEN_VOLENVHOLD: /* SF2.01 section 8.1.3 # 35 */
- case GEN_KEYTOVOLENVHOLD: /* SF2.01 section 8.1.3 # 39 */
- count = calculate_hold_decay_buffers(voice, GEN_VOLENVHOLD, GEN_KEYTOVOLENVHOLD, 0); /* 0 means: hold */
- fluid_voice_update_volenv(voice, FLUID_VOICE_ENVHOLD,
- count, 1.0f, 0.0f, -1.0f, 2.0f);
- break;
-
- case GEN_VOLENVDECAY: /* SF2.01 section 8.1.3 # 36 */
- case GEN_VOLENVSUSTAIN: /* SF2.01 section 8.1.3 # 37 */
- case GEN_KEYTOVOLENVDECAY: /* SF2.01 section 8.1.3 # 40 */
- y = 1.0f - 0.001f * _GEN(voice, GEN_VOLENVSUSTAIN);
- fluid_clip(y, 0.0f, 1.0f);
- count = calculate_hold_decay_buffers(voice, GEN_VOLENVDECAY, GEN_KEYTOVOLENVDECAY, 1); /* 1 for decay */
- fluid_voice_update_volenv(voice, FLUID_VOICE_ENVDECAY,
- count, 1.0f, count ? -1.0f / count : 0.0f, y, 2.0f);
- break;
-
- case GEN_VOLENVRELEASE: /* SF2.01 section 8.1.3 # 38 */
- x = _GEN(voice, GEN_VOLENVRELEASE);
- fluid_clip(x, FLUID_MIN_VOLENVRELEASE, 8000.0f);
- count = 1 + NUM_BUFFERS_RELEASE(x);
- fluid_voice_update_volenv(voice, FLUID_VOICE_ENVRELEASE,
- count, 1.0f, count ? -1.0f / count : 0.0f, 0.0f, 1.0f);
- break;
+ case GEN_VOLENVDELAY: /* SF2.01 section 8.1.3 # 33 */
+ fluid_clip(x, -12000.0f, 5000.0f);
+ count = NUM_BUFFERS_DELAY(x);
+ fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVDELAY,
+ count, 0.0f, 0.0f, -1.0f, 1.0f);
+ break;
+
+ case GEN_VOLENVATTACK: /* SF2.01 section 8.1.3 # 34 */
+ fluid_clip(x, -12000.0f, 8000.0f);
+ count = 1 + NUM_BUFFERS_ATTACK(x);
+ fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVATTACK,
+ count, 1.0f, 1.0f / count, -1.0f, 1.0f);
+ break;
+
+ case GEN_VOLENVHOLD: /* SF2.01 section 8.1.3 # 35 */
+ case GEN_KEYTOVOLENVHOLD: /* SF2.01 section 8.1.3 # 39 */
+ count = calculate_hold_decay_buffers(voice, GEN_VOLENVHOLD, GEN_KEYTOVOLENVHOLD, 0); /* 0 means: hold */
+ fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVHOLD,
+ count, 1.0f, 0.0f, -1.0f, 2.0f);
+ break;
+
+ case GEN_VOLENVDECAY: /* SF2.01 section 8.1.3 # 36 */
+ case GEN_VOLENVSUSTAIN: /* SF2.01 section 8.1.3 # 37 */
+ case GEN_KEYTOVOLENVDECAY: /* SF2.01 section 8.1.3 # 40 */
+ x = 1.0f - 0.001f * fluid_voice_gen_value(voice, GEN_VOLENVSUSTAIN);
+ fluid_clip(x, 0.0f, 1.0f);
+ count = calculate_hold_decay_buffers(voice, GEN_VOLENVDECAY, GEN_KEYTOVOLENVDECAY, 1); /* 1 for decay */
+ fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVDECAY,
+ count, 1.0f, count ? -1.0f / count : 0.0f, x, 2.0f);
+ break;
+
+ case GEN_VOLENVRELEASE: /* SF2.01 section 8.1.3 # 38 */
+ fluid_clip(x, FLUID_MIN_VOLENVRELEASE, 8000.0f);
+ count = 1 + NUM_BUFFERS_RELEASE(x);
+ fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVRELEASE,
+ count, 1.0f, -1.0f / count, 0.0f, 1.0f);
+ break;
/* Modulation envelope */
- case GEN_MODENVDELAY: /* SF2.01 section 8.1.3 # 25 */
- x = _GEN(voice, GEN_MODENVDELAY);
- fluid_clip(x, -12000.0f, 5000.0f);
- fluid_voice_update_modenv(voice, FLUID_VOICE_ENVDELAY,
- NUM_BUFFERS_DELAY(x), 0.0f, 0.0f, -1.0f, 1.0f);
- break;
-
- case GEN_MODENVATTACK: /* SF2.01 section 8.1.3 # 26 */
- x = _GEN(voice, GEN_MODENVATTACK);
- fluid_clip(x, -12000.0f, 8000.0f);
- count = 1 + NUM_BUFFERS_ATTACK(x);
- fluid_voice_update_modenv(voice, FLUID_VOICE_ENVATTACK,
- count, 1.0f, count ? 1.0f / count : 0.0f, -1.0f, 1.0f);
- break;
-
- case GEN_MODENVHOLD: /* SF2.01 section 8.1.3 # 27 */
- case GEN_KEYTOMODENVHOLD: /* SF2.01 section 8.1.3 # 31 */
- count = calculate_hold_decay_buffers(voice, GEN_MODENVHOLD, GEN_KEYTOMODENVHOLD, 0); /* 1 means: hold */
- fluid_voice_update_modenv(voice, FLUID_VOICE_ENVHOLD,
- count, 1.0f, 0.0f, -1.0f, 2.0f);
- break;
-
- case GEN_MODENVDECAY: /* SF 2.01 section 8.1.3 # 28 */
- case GEN_MODENVSUSTAIN: /* SF 2.01 section 8.1.3 # 29 */
- case GEN_KEYTOMODENVDECAY: /* SF 2.01 section 8.1.3 # 32 */
- count = calculate_hold_decay_buffers(voice, GEN_MODENVDECAY, GEN_KEYTOMODENVDECAY, 1); /* 1 for decay */
- y = 1.0f - 0.001f * _GEN(voice, GEN_MODENVSUSTAIN);
- fluid_clip(y, 0.0f, 1.0f);
- fluid_voice_update_modenv(voice, FLUID_VOICE_ENVDECAY,
- count, 1.0f, count ? -1.0f / count : 0.0f, y, 2.0f);
- break;
-
- case GEN_MODENVRELEASE: /* SF 2.01 section 8.1.3 # 30 */
- x = _GEN(voice, GEN_MODENVRELEASE);
- fluid_clip(x, -12000.0f, 8000.0f);
- count = 1 + NUM_BUFFERS_RELEASE(x);
- fluid_voice_update_modenv(voice, FLUID_VOICE_ENVRELEASE,
- count, 1.0f, count ? -1.0f / count : 0.0f, 0.0f, 2.0f);
-
- break;
-
- } /* switch gen */
+ case GEN_MODENVDELAY: /* SF2.01 section 8.1.3 # 25 */
+ fluid_clip(x, -12000.0f, 5000.0f);
+ fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVDELAY,
+ NUM_BUFFERS_DELAY(x), 0.0f, 0.0f, -1.0f, 1.0f);
+ break;
+
+ case GEN_MODENVATTACK: /* SF2.01 section 8.1.3 # 26 */
+ fluid_clip(x, -12000.0f, 8000.0f);
+ count = 1 + NUM_BUFFERS_ATTACK(x);
+ fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVATTACK,
+ count, 1.0f, 1.0f / count, -1.0f, 1.0f);
+ break;
+
+ case GEN_MODENVHOLD: /* SF2.01 section 8.1.3 # 27 */
+ case GEN_KEYTOMODENVHOLD: /* SF2.01 section 8.1.3 # 31 */
+ count = calculate_hold_decay_buffers(voice, GEN_MODENVHOLD, GEN_KEYTOMODENVHOLD, 0); /* 1 means: hold */
+ fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVHOLD,
+ count, 1.0f, 0.0f, -1.0f, 2.0f);
+ break;
+
+ case GEN_MODENVDECAY: /* SF 2.01 section 8.1.3 # 28 */
+ case GEN_MODENVSUSTAIN: /* SF 2.01 section 8.1.3 # 29 */
+ case GEN_KEYTOMODENVDECAY: /* SF 2.01 section 8.1.3 # 32 */
+ count = calculate_hold_decay_buffers(voice, GEN_MODENVDECAY, GEN_KEYTOMODENVDECAY, 1); /* 1 for decay */
+ x = 1.0f - 0.001f * fluid_voice_gen_value(voice, GEN_MODENVSUSTAIN);
+ fluid_clip(x, 0.0f, 1.0f);
+ fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVDECAY,
+ count, 1.0f, count ? -1.0f / count : 0.0f, x, 2.0f);
+ break;
+
+ case GEN_MODENVRELEASE: /* SF 2.01 section 8.1.3 # 30 */
+ fluid_clip(x, -12000.0f, 8000.0f);
+ count = 1 + NUM_BUFFERS_RELEASE(x);
+ fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVRELEASE,
+ count, 1.0f, -1.0f / count, 0.0f, 2.0f);
+
+ break;
+
+ } /* switch gen */
}
/**
@@ -1099,43 +1174,48 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
* - For every changed generator, convert its value to the correct
* unit of the corresponding DSP parameter
*/
-int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl)
+int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
{
- int i, k;
- fluid_mod_t* mod;
- int gen;
- fluid_real_t modval;
-
-/* printf("Chan=%d, CC=%d, Src=%d, Val=%d\n", voice->channel->channum, cc, ctrl, val); */
-
- for (i = 0; i < voice->mod_count; i++) {
-
- mod = &voice->mod[i];
-
- /* step 1: find all the modulators that have the changed controller
- * as input source. */
- if (fluid_mod_has_source(mod, cc, ctrl)) {
-
- gen = fluid_mod_get_dest(mod);
- modval = 0.0;
-
- /* step 2: for every changed modulator, calculate the modulation
- * value of its associated generator */
- for (k = 0; k < voice->mod_count; k++) {
- if (fluid_mod_has_dest(&voice->mod[k], gen)) {
- modval += fluid_mod_get_value(&voice->mod[k], voice->channel, voice);
- }
- }
-
- fluid_gen_set_mod(&voice->gen[gen], modval);
-
- /* step 3: now that we have the new value of the generator,
- * recalculate the parameter values that are derived from the
- * generator */
- fluid_voice_update_param(voice, gen);
+ int i, k;
+ fluid_mod_t *mod;
+ int gen;
+ fluid_real_t modval;
+
+ /* printf("Chan=%d, CC=%d, Src=%d, Val=%d\n", voice->channel->channum, cc, ctrl, val); */
+
+ for(i = 0; i < voice->mod_count; i++)
+ {
+
+ mod = &voice->mod[i];
+
+ /* step 1: find all the modulators that have the changed controller
+ * as input source. */
+ if(fluid_mod_has_source(mod, cc, ctrl))
+ {
+
+ gen = fluid_mod_get_dest(mod);
+ modval = 0.0;
+
+ /* step 2: for every changed modulator, calculate the modulation
+ * value of its associated generator */
+ for(k = 0; k < voice->mod_count; k++)
+ {
+ if(fluid_mod_has_dest(&voice->mod[k], gen))
+ {
+ modval += fluid_mod_get_value(&voice->mod[k], voice);
+ }
+ }
+
+ fluid_gen_set_mod(&voice->gen[gen], modval);
+
+ /* step 3: now that we have the new value of the generator,
+ * recalculate the parameter values that are derived from the
+ * generator */
+ fluid_voice_update_param(voice, gen);
+ }
}
- }
- return FLUID_OK;
+
+ return FLUID_OK;
}
/**
@@ -1143,44 +1223,113 @@ int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl)
* ALL_CTRL_OFF MIDI message has been received (CC 121).
*
*/
-int fluid_voice_modulate_all(fluid_voice_t* voice)
+int fluid_voice_modulate_all(fluid_voice_t *voice)
{
- fluid_mod_t* mod;
- int i, k, gen;
- fluid_real_t modval;
-
- /* Loop through all the modulators.
-
- FIXME: we should loop through the set of generators instead of
- the set of modulators. We risk to call 'fluid_voice_update_param'
- several times for the same generator if several modulators have
- that generator as destination. It's not an error, just a wast of
- energy (think polution, global warming, unhappy musicians,
- ...) */
-
- for (i = 0; i < voice->mod_count; i++) {
-
- mod = &voice->mod[i];
- gen = fluid_mod_get_dest(mod);
- modval = 0.0;
-
- /* Accumulate the modulation values of all the modulators with
- * destination generator 'gen' */
- for (k = 0; k < voice->mod_count; k++) {
- if (fluid_mod_has_dest(&voice->mod[k], gen)) {
- modval += fluid_mod_get_value(&voice->mod[k], voice->channel, voice);
- }
+ fluid_mod_t *mod;
+ int i, k, gen;
+ fluid_real_t modval;
+
+ /* Loop through all the modulators.
+
+ FIXME: we should loop through the set of generators instead of
+ the set of modulators. We risk to call 'fluid_voice_update_param'
+ several times for the same generator if several modulators have
+ that generator as destination. It's not an error, just a wast of
+ energy (think polution, global warming, unhappy musicians,
+ ...) */
+
+ for(i = 0; i < voice->mod_count; i++)
+ {
+
+ mod = &voice->mod[i];
+ gen = fluid_mod_get_dest(mod);
+ modval = 0.0;
+
+ /* Accumulate the modulation values of all the modulators with
+ * destination generator 'gen' */
+ for(k = 0; k < voice->mod_count; k++)
+ {
+ if(fluid_mod_has_dest(&voice->mod[k], gen))
+ {
+ modval += fluid_mod_get_value(&voice->mod[k], voice);
+ }
+ }
+
+ fluid_gen_set_mod(&voice->gen[gen], modval);
+
+ /* Update the parameter values that are depend on the generator
+ * 'gen' */
+ fluid_voice_update_param(voice, gen);
}
- fluid_gen_set_mod(&voice->gen[gen], modval);
+ return FLUID_OK;
+}
- /* Update the parameter values that are depend on the generator
- * 'gen' */
- fluid_voice_update_param(voice, gen);
- }
+/** legato update functions --------------------------------------------------*/
+/* Updates voice portamento parameters
+ *
+ * @voice voice the synthesis voice
+ * @fromkey the beginning pitch of portamento.
+ * @tokey the ending pitch of portamento.
+ *
+ * The function calculates pitch offset and increment, then these parameters
+ * are send to the dsp.
+*/
+void fluid_voice_update_portamento(fluid_voice_t *voice, int fromkey, int tokey)
+
+{
+ fluid_channel_t *channel = voice->channel;
+
+ /* calculates pitch offset */
+ fluid_real_t PitchBeg = fluid_voice_calculate_pitch(voice, fromkey);
+ fluid_real_t PitchEnd = fluid_voice_calculate_pitch(voice, tokey);
+ fluid_real_t pitchoffset = PitchBeg - PitchEnd;
+
+ /* Calculates increment countinc */
+ /* Increment is function of PortamentoTime (ms)*/
+ unsigned int countinc = (unsigned int)(((fluid_real_t)voice->output_rate *
+ 0.001f *
+ (fluid_real_t)fluid_channel_portamentotime(channel)) /
+ (fluid_real_t)FLUID_BUFSIZE + 0.5);
+
+ /* Send portamento parameters to the voice dsp */
+ UPDATE_RVOICE_GENERIC_IR(fluid_rvoice_set_portamento, voice->rvoice, countinc, pitchoffset);
+}
+
+/*---------------------------------------------------------------*/
+/*legato mode 1: multi_retrigger
+ *
+ * Modulates all generators dependent of key,vel.
+ * Forces the voice envelopes in the attack section (legato mode 1).
+ *
+ * @voice voice the synthesis voice
+ * @tokey the new key to be applied to this voice.
+ * @vel the new velocity to be applied to this voice.
+ */
+void fluid_voice_update_multi_retrigger_attack(fluid_voice_t *voice,
+ int tokey, int vel)
+{
+ voice->key = tokey; /* new note */
+ voice->vel = vel; /* new velocity */
+ /* Updates generators dependent of velocity */
+ /* Modulates GEN_ATTENUATION (and others ) before calling
+ fluid_rvoice_multi_retrigger_attack().*/
+ fluid_voice_modulate(voice, FALSE, FLUID_MOD_VELOCITY);
+
+ /* Updates generator dependent of voice->key */
+ fluid_voice_update_param(voice, GEN_KEYTOMODENVHOLD);
+ fluid_voice_update_param(voice, GEN_KEYTOMODENVDECAY);
+ fluid_voice_update_param(voice, GEN_KEYTOVOLENVHOLD);
+ fluid_voice_update_param(voice, GEN_KEYTOVOLENVDECAY);
+
+ /* Updates pitch generator */
+ fluid_voice_calculate_gen_pitch(voice);
+ fluid_voice_update_param(voice, GEN_PITCH);
- return FLUID_OK;
+ /* updates adsr generator */
+ UPDATE_RVOICE0(fluid_rvoice_multi_retrigger_attack);
}
+/** end of legato update functions */
/*
Force the voice into release stage. Useful anywhere a voice
@@ -1190,40 +1339,45 @@ int fluid_voice_modulate_all(fluid_voice_t* voice)
fluid_voice_noteoff().
*/
void
-fluid_voice_release(fluid_voice_t* voice)
+fluid_voice_release(fluid_voice_t *voice)
{
- unsigned int at_tick = fluid_channel_get_min_note_length_ticks (voice->channel);
+ unsigned int at_tick = fluid_channel_get_min_note_length_ticks(voice->channel);
UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick);
voice->has_noteoff = 1; // voice is marked as noteoff occured
}
/*
* fluid_voice_noteoff
+ *
+ * Sending a noteoff event will advance the envelopes to section 5 (release).
+ * The function is convenient for polyphonic or monophonic note
*/
-int
-fluid_voice_noteoff(fluid_voice_t* voice)
+void
+fluid_voice_noteoff(fluid_voice_t *voice)
{
- fluid_channel_t* channel;
-
- fluid_profile(FLUID_PROF_VOICE_NOTE, voice->ref);
-
- channel = voice->channel;
-
- /* Sustain a note under Sostenuto pedal */
- if (fluid_channel_sostenuto(channel) &&
- channel->sostenuto_orderid > voice->id)
- { // Sostenuto depressed after note
- voice->status = FLUID_VOICE_HELD_BY_SOSTENUTO;
- }
- /* Or sustain a note under Sustain pedal */
- else if (fluid_channel_sustained(channel)) {
- voice->status = FLUID_VOICE_SUSTAINED;
- }
- /* Or force the voice to release stage */
- else
- fluid_voice_release(voice);
-
- return FLUID_OK;
+ fluid_channel_t *channel;
+
+ fluid_profile(FLUID_PROF_VOICE_NOTE, voice->ref, 0, 0);
+
+ channel = voice->channel;
+
+ /* Sustain a note under Sostenuto pedal */
+ if(fluid_channel_sostenuto(channel) &&
+ channel->sostenuto_orderid > voice->id)
+ {
+ // Sostenuto depressed after note
+ voice->status = FLUID_VOICE_HELD_BY_SOSTENUTO;
+ }
+ /* Or sustain a note under Sustain pedal */
+ else if(fluid_channel_sustained(channel))
+ {
+ voice->status = FLUID_VOICE_SUSTAINED;
+ }
+ /* Or force the voice to release stage */
+ else
+ {
+ fluid_voice_release(voice);
+ }
}
/*
@@ -1239,73 +1393,84 @@ fluid_voice_noteoff(fluid_voice_t* voice)
*/
int
-fluid_voice_kill_excl(fluid_voice_t* voice){
+fluid_voice_kill_excl(fluid_voice_t *voice)
+{
- unsigned int at_tick;
+ unsigned int at_tick;
- if (!_PLAYING(voice)) {
- return FLUID_OK;
- }
+ if(!fluid_voice_is_playing(voice))
+ {
+ return FLUID_OK;
+ }
- /* Turn off the exclusive class information for this voice,
- so that it doesn't get killed twice
- */
- fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, 0);
+ /* Turn off the exclusive class information for this voice,
+ so that it doesn't get killed twice
+ */
+ fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, 0);
- /* Speed up the volume envelope */
- /* The value was found through listening tests with hi-hat samples. */
- fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, -200);
- fluid_voice_update_param(voice, GEN_VOLENVRELEASE);
+ /* Speed up the volume envelope */
+ /* The value was found through listening tests with hi-hat samples. */
+ fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, -200);
+ fluid_voice_update_param(voice, GEN_VOLENVRELEASE);
- /* Speed up the modulation envelope */
- fluid_voice_gen_set(voice, GEN_MODENVRELEASE, -200);
- fluid_voice_update_param(voice, GEN_MODENVRELEASE);
+ /* Speed up the modulation envelope */
+ fluid_voice_gen_set(voice, GEN_MODENVRELEASE, -200);
+ fluid_voice_update_param(voice, GEN_MODENVRELEASE);
- at_tick = fluid_channel_get_min_note_length_ticks (voice->channel);
- UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick);
+ at_tick = fluid_channel_get_min_note_length_ticks(voice->channel);
+ UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick);
- return FLUID_OK;
+ return FLUID_OK;
}
/*
- * Called by fluid_synth when the overflow rvoice can be reclaimed.
+ * Called by fluid_synth when the overflow rvoice can be reclaimed.
*/
-void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice)
+void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice)
{
- voice->can_access_overflow_rvoice = 1;
- fluid_sample_null_ptr(&voice->overflow_rvoice->dsp.sample);
+ voice->can_access_overflow_rvoice = 1;
+ fluid_voice_sample_unref(&voice->overflow_rvoice->dsp.sample);
}
-
/*
* fluid_voice_off
*
+ * Force the voice into finished stage. Useful anywhere a voice
+ * needs to be cancelled from MIDI API.
+ */
+void fluid_voice_off(fluid_voice_t *voice)
+{
+ UPDATE_RVOICE0(fluid_rvoice_voiceoff); /* request to finish the voice */
+}
+
+/*
+ * fluid_voice_stop
+ *
* Purpose:
- * Turns off a voice, meaning that it is not processed
- * anymore by the DSP loop.
+ * Turns off a voice, meaning that it is not processed anymore by the
+ * DSP loop, i.e. contrary part to fluid_voice_start().
*/
-int
-fluid_voice_off(fluid_voice_t* voice)
+void
+fluid_voice_stop(fluid_voice_t *voice)
{
- fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
+ fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref, 0, 0);
- voice->chan = NO_CHANNEL;
- UPDATE_RVOICE0(fluid_rvoice_voiceoff);
-
- if (voice->can_access_rvoice)
- fluid_sample_null_ptr(&voice->rvoice->dsp.sample);
+ voice->chan = NO_CHANNEL;
- voice->status = FLUID_VOICE_OFF;
- voice->has_noteoff = 1;
+ if(voice->can_access_rvoice)
+ {
+ fluid_voice_sample_unref(&voice->rvoice->dsp.sample);
+ }
- /* Decrement the reference count of the sample. */
- fluid_sample_null_ptr(&voice->sample);
+ voice->status = FLUID_VOICE_OFF;
+ voice->has_noteoff = 1;
- /* Decrement voice count */
- voice->channel->synth->active_voice_count--;
+ /* Decrement the reference count of the sample. */
+ fluid_voice_sample_unref(&voice->sample);
- return FLUID_OK;
+ /* Decrement voice count */
+ voice->channel->synth->active_voice_count--;
}
/**
@@ -1319,57 +1484,70 @@ fluid_voice_off(fluid_voice_t* voice)
* exist so don't check.
*/
void
-fluid_voice_add_mod(fluid_voice_t* voice, fluid_mod_t* mod, int mode)
+fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode)
{
- int i;
-
- /*
- * Some soundfonts come with a huge number of non-standard
- * controllers, because they have been designed for one particular
- * sound card. Discard them, maybe print a warning.
- */
-
- if (((mod->flags1 & FLUID_MOD_CC) == 0)
- && ((mod->src1 != 0) /* SF2.01 section 8.2.1: Constant value */
- && (mod->src1 != 2) /* Note-on velocity */
- && (mod->src1 != 3) /* Note-on key number */
- && (mod->src1 != 10) /* Poly pressure */
- && (mod->src1 != 13) /* Channel pressure */
- && (mod->src1 != 14) /* Pitch wheel */
- && (mod->src1 != 16))) { /* Pitch wheel sensitivity */
- FLUID_LOG(FLUID_WARN, "Ignoring invalid controller, using non-CC source %i.", mod->src1);
- return;
- }
-
- if (mode == FLUID_VOICE_ADD) {
-
- /* if identical modulator exists, add them */
- for (i = 0; i < voice->mod_count; i++) {
- if (fluid_mod_test_identity(&voice->mod[i], mod)) {
- // printf("Adding modulator...\n");
- voice->mod[i].amount += mod->amount;
- return;
- }
+ int i;
+
+ /*
+ * Some soundfonts come with a huge number of non-standard
+ * controllers, because they have been designed for one particular
+ * sound card. Discard them, maybe print a warning.
+ */
+
+ if(((mod->flags1 & FLUID_MOD_CC) == 0)
+ && ((mod->src1 != FLUID_MOD_NONE) /* SF2.01 section 8.2.1: Constant value */
+ && (mod->src1 != FLUID_MOD_VELOCITY) /* Note-on velocity */
+ && (mod->src1 != FLUID_MOD_KEY) /* Note-on key number */
+ && (mod->src1 != FLUID_MOD_KEYPRESSURE) /* Poly pressure */
+ && (mod->src1 != FLUID_MOD_CHANNELPRESSURE) /* Channel pressure */
+ && (mod->src1 != FLUID_MOD_PITCHWHEEL) /* Pitch wheel */
+ && (mod->src1 != FLUID_MOD_PITCHWHEELSENS)))/* Pitch wheel sensitivity */
+ {
+ FLUID_LOG(FLUID_WARN, "Ignoring invalid controller, using non-CC source %i.", mod->src1);
+ return;
}
- } else if (mode == FLUID_VOICE_OVERWRITE) {
+ if(mode == FLUID_VOICE_ADD)
+ {
+
+ /* if identical modulator exists, add them */
+ for(i = 0; i < voice->mod_count; i++)
+ {
+ if(fluid_mod_test_identity(&voice->mod[i], mod))
+ {
+ // printf("Adding modulator...\n");
+ voice->mod[i].amount += mod->amount;
+ return;
+ }
+ }
- /* if identical modulator exists, replace it (only the amount has to be changed) */
- for (i = 0; i < voice->mod_count; i++) {
- if (fluid_mod_test_identity(&voice->mod[i], mod)) {
- // printf("Replacing modulator...amount is %f\n",mod->amount);
- voice->mod[i].amount = mod->amount;
- return;
- }
}
- }
-
- /* Add a new modulator (No existing modulator to add / overwrite).
- Also, default modulators (FLUID_VOICE_DEFAULT) are added without
- checking, if the same modulator already exists. */
- if (voice->mod_count < FLUID_NUM_MOD) {
- fluid_mod_clone(&voice->mod[voice->mod_count++], mod);
- }
+ else if(mode == FLUID_VOICE_OVERWRITE)
+ {
+
+ /* if identical modulator exists, replace it (only the amount has to be changed) */
+ for(i = 0; i < voice->mod_count; i++)
+ {
+ if(fluid_mod_test_identity(&voice->mod[i], mod))
+ {
+ // printf("Replacing modulator...amount is %f\n",mod->amount);
+ voice->mod[i].amount = mod->amount;
+ return;
+ }
+ }
+ }
+
+ /* Add a new modulator (No existing modulator to add / overwrite).
+ Also, default modulators (FLUID_VOICE_DEFAULT) are added without
+ checking, if the same modulator already exists. */
+ if(voice->mod_count < FLUID_NUM_MOD)
+ {
+ fluid_mod_clone(&voice->mod[voice->mod_count++], mod);
+ }
+ else
+ {
+ FLUID_LOG(FLUID_WARN, "Voice %i has more modulators than supported, ignoring.", voice->id);
+ }
}
/**
@@ -1388,19 +1566,134 @@ fluid_voice_add_mod(fluid_voice_t* voice, fluid_mod_t* mod, int mode)
*
* Otherwise the voice has finished playing.
*/
-unsigned int fluid_voice_get_id(fluid_voice_t* voice)
+unsigned int fluid_voice_get_id(const fluid_voice_t *voice)
{
- return voice->id;
+ return voice->id;
}
/**
- * Check if a voice is still playing.
+ * Check if a voice is producing sound. This is also true after a voice received a noteoff as it may be playing in release phase.
* @param voice Voice instance
* @return TRUE if playing, FALSE otherwise
*/
-int fluid_voice_is_playing(fluid_voice_t* voice)
+int fluid_voice_is_playing(const fluid_voice_t *voice)
+{
+ return (voice->status == FLUID_VOICE_ON)
+ || fluid_voice_is_sustained(voice)
+ || fluid_voice_is_sostenuto(voice);
+
+}
+
+/**
+ * Check if a voice is ON. A voice is ON, if it has not yet received a noteoff event.
+ * @param voice Voice instance
+ * @return TRUE if on, FALSE otherwise
+ * @since 1.1.7
+ */
+int fluid_voice_is_on(const fluid_voice_t *voice)
+{
+ return (voice->status == FLUID_VOICE_ON && !voice->has_noteoff);
+}
+
+/**
+ * Check if a voice keeps playing after it has received a noteoff due to being held by sustain.
+ * @param voice Voice instance
+ * @return TRUE if sustained, FALSE otherwise
+ * @since 1.1.7
+ */
+int fluid_voice_is_sustained(const fluid_voice_t *voice)
+{
+ return (voice->status == FLUID_VOICE_SUSTAINED);
+}
+
+/**
+ * Check if a voice keeps playing after it has received a noteoff due to being held by sostenuto.
+ * @param voice Voice instance
+ * @return TRUE if sostenuto, FALSE otherwise
+ * @since 1.1.7
+ */
+int fluid_voice_is_sostenuto(const fluid_voice_t *voice)
+{
+ return (voice->status == FLUID_VOICE_HELD_BY_SOSTENUTO);
+}
+
+/**
+ * If the voice is playing, gets the midi channel the voice is playing on. Else the result is undefined.
+ * @param voice Voice instance
+ * @return The channel assigned to this voice
+ * @since 1.1.7
+ */
+int fluid_voice_get_channel(const fluid_voice_t *voice)
+{
+ return voice->chan;
+}
+
+/**
+ * If the voice is playing, gets the midi key the voice is actually playing at. Else the result is undefined.
+ * If the voice was started from an instrument which uses a fixed key generator, it returns that.
+ * Else returns the same as \c fluid_voice_get_key.
+ * @param voice Voice instance
+ * @return The midi key this voice is playing at
+ * @since 1.1.7
+ */
+int fluid_voice_get_actual_key(const fluid_voice_t *voice)
+{
+ fluid_real_t x = fluid_voice_gen_value(voice, GEN_KEYNUM);
+
+ if(x >= 0)
+ {
+ return (int)x;
+ }
+ else
+ {
+ return fluid_voice_get_key(voice);
+ }
+}
+
+/**
+ * If the voice is playing, gets the midi key from the noteon event, by which the voice was initially turned on with.
+ * Else the result is undefined.
+ * @param voice Voice instance
+ * @return The midi key of the noteon event that originally turned on this voice
+ * @since 1.1.7
+ */
+int fluid_voice_get_key(const fluid_voice_t *voice)
+{
+ return voice->key;
+}
+
+/**
+ * If the voice is playing, gets the midi velocity the voice is actually playing at. Else the result is undefined.
+ * If the voice was started from an instrument which uses a fixed velocity generator, it returns that.
+ * Else returns the same as \c fluid_voice_get_velocity.
+ * @param voice Voice instance
+ * @return The midi velocity this voice is playing at
+ * @since 1.1.7
+ */
+int fluid_voice_get_actual_velocity(const fluid_voice_t *voice)
+{
+ fluid_real_t x = fluid_voice_gen_value(voice, GEN_VELOCITY);
+
+ if(x > 0)
+ {
+ return (int)x;
+ }
+ else
+ {
+ return fluid_voice_get_velocity(voice);
+ }
+}
+
+/**
+ * If the voice is playing, gets the midi velocity from the noteon event, by which the voice was initially
+ * turned on with. Else the result is undefined.
+ * @param voice Voice instance
+ * @return The midi velocity which originally turned on this voice
+ * @since 1.1.7
+ */
+int fluid_voice_get_velocity(const fluid_voice_t *voice)
{
- return _PLAYING(voice);
+ return voice->vel;
}
/*
@@ -1416,85 +1709,105 @@ int fluid_voice_is_playing(fluid_voice_t* voice)
* voice->attenuation has to be initialized.
*/
static fluid_real_t
-fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice)
+fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t *voice)
{
- int i;
- fluid_mod_t* mod;
- fluid_real_t possible_att_reduction_cB=0;
- fluid_real_t lower_bound;
-
- for (i = 0; i < voice->mod_count; i++) {
- mod = &voice->mod[i];
-
- /* Modulator has attenuation as target and can change over time? */
- if ((mod->dest == GEN_ATTENUATION)
- && ((mod->flags1 & FLUID_MOD_CC) || (mod->flags2 & FLUID_MOD_CC))) {
-
- fluid_real_t current_val = fluid_mod_get_value(mod, voice->channel, voice);
- fluid_real_t v = fabs(mod->amount);
-
- if ((mod->src1 == FLUID_MOD_PITCHWHEEL)
- || (mod->flags1 & FLUID_MOD_BIPOLAR)
- || (mod->flags2 & FLUID_MOD_BIPOLAR)
- || (mod->amount < 0)) {
- /* Can this modulator produce a negative contribution? */
- v *= -1.0;
- } else {
- /* No negative value possible. But still, the minimum contribution is 0. */
- v = 0;
- }
-
- /* For example:
- * - current_val=100
- * - min_val=-4000
- * - possible_att_reduction_cB += 4100
- */
- if (current_val > v){
- possible_att_reduction_cB += (current_val - v);
- }
+ int i;
+ fluid_mod_t *mod;
+ fluid_real_t possible_att_reduction_cB = 0;
+ fluid_real_t lower_bound;
+
+ for(i = 0; i < voice->mod_count; i++)
+ {
+ mod = &voice->mod[i];
+
+ /* Modulator has attenuation as target and can change over time? */
+ if((mod->dest == GEN_ATTENUATION)
+ && ((mod->flags1 & FLUID_MOD_CC)
+ || (mod->flags2 & FLUID_MOD_CC)
+ || (mod->src1 == FLUID_MOD_CHANNELPRESSURE)
+ || (mod->src1 == FLUID_MOD_KEYPRESSURE)
+ || (mod->src1 == FLUID_MOD_PITCHWHEEL)
+ || (mod->src2 == FLUID_MOD_CHANNELPRESSURE)
+ || (mod->src2 == FLUID_MOD_KEYPRESSURE)
+ || (mod->src2 == FLUID_MOD_PITCHWHEEL)))
+ {
+
+ fluid_real_t current_val = fluid_mod_get_value(mod, voice);
+ fluid_real_t v = fabs(mod->amount);
+
+ if((mod->src1 == FLUID_MOD_PITCHWHEEL)
+ || (mod->flags1 & FLUID_MOD_BIPOLAR)
+ || (mod->flags2 & FLUID_MOD_BIPOLAR)
+ || (mod->amount < 0))
+ {
+ /* Can this modulator produce a negative contribution? */
+ v *= -1.0;
+ }
+ else
+ {
+ /* No negative value possible. But still, the minimum contribution is 0. */
+ v = 0;
+ }
+
+ /* For example:
+ * - current_val=100
+ * - min_val=-4000
+ * - possible_att_reduction_cB += 4100
+ */
+ if(current_val > v)
+ {
+ possible_att_reduction_cB += (current_val - v);
+ }
+ }
}
- }
- lower_bound = voice->attenuation-possible_att_reduction_cB;
+ lower_bound = voice->attenuation - possible_att_reduction_cB;
- /* SF2.01 specs do not allow negative attenuation */
- if (lower_bound < 0) {
- lower_bound = 0;
- }
- return lower_bound;
+ /* SF2.01 specs do not allow negative attenuation */
+ if(lower_bound < 0)
+ {
+ lower_bound = 0;
+ }
+
+ return lower_bound;
}
-int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t nrpn_value, int abs)
+int fluid_voice_set_param(fluid_voice_t *voice, int gen, fluid_real_t nrpn_value, int abs)
{
- voice->gen[gen].nrpn = nrpn_value;
- voice->gen[gen].flags = (abs)? GEN_ABS_NRPN : GEN_SET;
- fluid_voice_update_param(voice, gen);
- return FLUID_OK;
+ voice->gen[gen].nrpn = nrpn_value;
+ voice->gen[gen].flags = (abs) ? GEN_ABS_NRPN : GEN_SET;
+ fluid_voice_update_param(voice, gen);
+ return FLUID_OK;
}
-int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain)
+int fluid_voice_set_gain(fluid_voice_t *voice, fluid_real_t gain)
{
- /* avoid division by zero*/
- if (gain < 0.0000001){
- gain = 0.0000001;
- }
-
- voice->synth_gain = gain;
- voice->amp_left = fluid_pan(voice->pan, 1) * gain / 32768.0f;
- voice->amp_right = fluid_pan(voice->pan, 0) * gain / 32768.0f;
- voice->amp_reverb = voice->reverb_send * gain / 32768.0f;
- voice->amp_chorus = voice->chorus_send * gain / 32768.0f;
-
- UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, gain);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 0, voice->amp_left);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 1, voice->amp_right);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 2, voice->amp_reverb);
- UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 3, voice->amp_chorus);
-
- return FLUID_OK;
+ fluid_real_t left, right, reverb, chorus;
+
+ /* avoid division by zero*/
+ if(gain < 0.0000001)
+ {
+ gain = 0.0000001;
+ }
+
+ voice->synth_gain = gain;
+ left = fluid_voice_calculate_gain_amplitude(voice,
+ fluid_pan(voice->pan, 1) * fluid_balance(voice->balance, 1));
+ right = fluid_voice_calculate_gain_amplitude(voice,
+ fluid_pan(voice->pan, 0) * fluid_balance(voice->balance, 0));
+ reverb = fluid_voice_calculate_gain_amplitude(voice, voice->reverb_send);
+ chorus = fluid_voice_calculate_gain_amplitude(voice, voice->chorus_send);
+
+ UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, gain);
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 0, left);
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 1, right);
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 2, reverb);
+ UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 3, chorus);
+
+ return FLUID_OK;
}
/* - Scan the loop
@@ -1514,113 +1827,162 @@ int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain)
* fluid_voice_optimize_sample() on each sample once.
*/
int
-fluid_voice_optimize_sample(fluid_sample_t* s)
+fluid_voice_optimize_sample(fluid_sample_t *s)
{
- signed short peak_max = 0;
- signed short peak_min = 0;
- signed short peak;
- fluid_real_t normalized_amplitude_during_loop;
- double result;
- int i;
-
- /* ignore ROM and other(?) invalid samples */
- if (!s->valid) return (FLUID_OK);
-
- if (!s->amplitude_that_reaches_noise_floor_is_valid){ /* Only once */
- /* Scan the loop */
- for (i = (int)s->loopstart; i < (int) s->loopend; i ++){
- signed short val = s->data[i];
- if (val > peak_max) {
- peak_max = val;
- } else if (val < peak_min) {
- peak_min = val;
- }
+ int32_t peak_max = 0;
+ int32_t peak_min = 0;
+ int32_t peak;
+ fluid_real_t normalized_amplitude_during_loop;
+ double result;
+ unsigned int i;
+
+ /* ignore disabled samples */
+ if(s->start == s->end)
+ {
+ return (FLUID_OK);
}
- /* Determine the peak level */
- if (peak_max >- peak_min){
- peak = peak_max;
- } else {
- peak =- peak_min;
- };
- if (peak == 0){
- /* Avoid division by zero */
- peak = 1;
- };
-
- /* Calculate what factor will make the loop inaudible
- * For example: Take a peak of 3277 (10 % of 32768). The
- * normalized amplitude is 0.1 (10 % of 32768). An amplitude
- * factor of 0.0001 (as opposed to the default 0.00001) will
- * drop this sample to the noise floor.
- */
-
- /* 16 bits => 96+4=100 dB dynamic range => 0.00001 */
- normalized_amplitude_during_loop = ((fluid_real_t)peak)/32768.;
- result = FLUID_NOISE_FLOOR / normalized_amplitude_during_loop;
-
- /* Store in sample */
- s->amplitude_that_reaches_noise_floor = (double)result;
- s->amplitude_that_reaches_noise_floor_is_valid = 1;
+ if(!s->amplitude_that_reaches_noise_floor_is_valid) /* Only once */
+ {
+ /* Scan the loop */
+ for(i = s->loopstart; i < s->loopend; i++)
+ {
+ int32_t val = fluid_rvoice_get_sample(s->data, s->data24, i);
+
+ if(val > peak_max)
+ {
+ peak_max = val;
+ }
+ else if(val < peak_min)
+ {
+ peak_min = val;
+ }
+ }
+
+ /* Determine the peak level */
+ if(peak_max > -peak_min)
+ {
+ peak = peak_max;
+ }
+ else
+ {
+ peak = -peak_min;
+ }
+
+ if(peak == 0)
+ {
+ /* Avoid division by zero */
+ peak = 1;
+ }
+
+ /* Calculate what factor will make the loop inaudible
+ * For example: Take a peak of 3277 (10 % of 32768). The
+ * normalized amplitude is 0.1 (10 % of 32768). An amplitude
+ * factor of 0.0001 (as opposed to the default 0.00001) will
+ * drop this sample to the noise floor.
+ */
+
+ /* 16 bits => 96+4=100 dB dynamic range => 0.00001 */
+ normalized_amplitude_during_loop = ((fluid_real_t)peak) / (INT24_MAX * 1.0f);
+ result = FLUID_NOISE_FLOOR / normalized_amplitude_during_loop;
+
+ /* Store in sample */
+ s->amplitude_that_reaches_noise_floor = (double)result;
+ s->amplitude_that_reaches_noise_floor_is_valid = 1;
#if 0
- printf("Sample peak detection: factor %f\n", (double)result);
+ printf("Sample peak detection: factor %f\n", (double)result);
#endif
- };
- return FLUID_OK;
+ }
+
+ return FLUID_OK;
}
-fluid_real_t
-fluid_voice_get_overflow_prio(fluid_voice_t* voice,
- fluid_overflow_prio_t* score,
- unsigned int cur_time)
+float
+fluid_voice_get_overflow_prio(fluid_voice_t *voice,
+ fluid_overflow_prio_t *score,
+ unsigned int cur_time)
{
- fluid_real_t this_voice_prio = 0;
-
- /* Are we already overflowing? */
- if (!voice->can_access_overflow_rvoice) {
- return OVERFLOW_PRIO_CANNOT_KILL;
- }
-
- /* Is this voice on the drum channel?
- * Then it is very important.
- * Also skip the released and sustained scores.
- */
- if (voice->channel->channel_type == CHANNEL_TYPE_DRUM){
- this_voice_prio += score->percussion;
- }
- else if (voice->has_noteoff) {
- /* Noteoff has */
- this_voice_prio += score->released;
- } else if (_SUSTAINED(voice) || _HELD_BY_SOSTENUTO(voice)) {
- /* This voice is still active, since the sustain pedal is held down.
- * Consider it less important than non-sustained channels.
- * This decision is somehow subjective. But usually the sustain pedal
- * is used to play 'more-voices-than-fingers', so it shouldn't hurt
- * if we kill one voice.
+ float this_voice_prio = 0;
+ int channel;
+
+ /* Are we already overflowing? */
+ if(!voice->can_access_overflow_rvoice)
+ {
+ return OVERFLOW_PRIO_CANNOT_KILL;
+ }
+
+ /* Is this voice on the drum channel?
+ * Then it is very important.
+ * Also skip the released and sustained scores.
*/
- this_voice_prio += score->sustained;
- }
-
- /* We are not enthusiastic about releasing voices, which have just been started.
- * Otherwise hitting a chord may result in killing notes belonging to that very same
- * chord. So give newer voices a higher score. */
- if (score->age) {
- cur_time -= voice->start_time;
- if (cur_time < 1)
- cur_time = 1; // Avoid div by zero
- this_voice_prio += (score->age * voice->output_rate) / cur_time;
- }
-
- /* take a rough estimate of loudness into account. Louder voices are more important. */
- if (score->volume) {
- fluid_real_t a = voice->attenuation;
- if (voice->has_noteoff) {
- // FIXME: Should take into account where on the envelope we are...?
+ if(voice->channel->channel_type == CHANNEL_TYPE_DRUM)
+ {
+ this_voice_prio += score->percussion;
}
- if (a < 0.1)
- a = 0.1; // Avoid div by zero
- this_voice_prio += score->volume / a;
+ else if(voice->has_noteoff)
+ {
+ /* Noteoff has */
+ this_voice_prio += score->released;
}
-
- return this_voice_prio;
+ else if(fluid_voice_is_sustained(voice) || fluid_voice_is_sostenuto(voice))
+ {
+ /* This voice is still active, since the sustain pedal is held down.
+ * Consider it less important than non-sustained channels.
+ * This decision is somehow subjective. But usually the sustain pedal
+ * is used to play 'more-voices-than-fingers', so it shouldn't hurt
+ * if we kill one voice.
+ */
+ this_voice_prio += score->sustained;
+ }
+
+ /* We are not enthusiastic about releasing voices, which have just been started.
+ * Otherwise hitting a chord may result in killing notes belonging to that very same
+ * chord. So give newer voices a higher score. */
+ if(score->age)
+ {
+ cur_time -= voice->start_time;
+
+ if(cur_time < 1)
+ {
+ cur_time = 1; // Avoid div by zero
+ }
+
+ this_voice_prio += (score->age * voice->output_rate) / cur_time;
+ }
+
+ /* take a rough estimate of loudness into account. Louder voices are more important. */
+ if(score->volume)
+ {
+ fluid_real_t a = voice->attenuation;
+
+ if(voice->has_noteoff)
+ {
+ // FIXME: Should take into account where on the envelope we are...?
+ }
+
+ if(a < 0.1)
+ {
+ a = 0.1; // Avoid div by zero
+ }
+
+ this_voice_prio += score->volume / a;
+ }
+
+ /* Check if this voice is on an important channel. If so, then add the
+ * score for important channels */
+ channel = fluid_voice_get_channel(voice);
+
+ if(channel < score->num_important_channels && score->important_channels[channel])
+ {
+ this_voice_prio += score->important;
+ }
+
+ return this_voice_prio;
+}
+
+
+void fluid_voice_set_custom_filter(fluid_voice_t *voice, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags)
+{
+ UPDATE_RVOICE_GENERIC_I2(fluid_iir_filter_init, &voice->rvoice->resonant_custom_filter, type, flags);
}
+
diff --git a/libs/fluidsynth/src/fluid_voice.h b/libs/fluidsynth/src/fluid_voice.h
index c43fe59738..6038a1a9f3 100644
--- a/libs/fluidsynth/src/fluid_voice.h
+++ b/libs/fluidsynth/src/fluid_voice.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -29,28 +29,32 @@
#include "fluid_adsr_env.h"
#include "fluid_lfo.h"
#include "fluid_rvoice.h"
+#include "fluid_rvoice_event.h"
#include "fluid_sys.h"
#define NO_CHANNEL 0xff
typedef struct _fluid_overflow_prio_t fluid_overflow_prio_t;
-struct _fluid_overflow_prio_t
+struct _fluid_overflow_prio_t
{
- fluid_real_t percussion; /**< Is this voice on the drum channel? Then add this score */
- fluid_real_t released; /**< Is this voice in release stage? Then add this score (usually negative) */
- fluid_real_t sustained; /**< Is this voice sustained? Then add this score (usually negative) */
- fluid_real_t volume; /**< Multiply current (or future) volume (a value between 0 and 1) */
- fluid_real_t age; /**< This score will be divided by the number of seconds the voice has lasted */
+ float percussion; /**< Is this voice on the drum channel? Then add this score */
+ float released; /**< Is this voice in release stage? Then add this score (usually negative) */
+ float sustained; /**< Is this voice sustained? Then add this score (usually negative) */
+ float volume; /**< Multiply current (or future) volume (a value between 0 and 1) */
+ float age; /**< This score will be divided by the number of seconds the voice has lasted */
+ float important; /**< This score will be added to all important channels */
+ char *important_channels; /**< "important" flags indexed by MIDI channel number */
+ int num_important_channels; /**< Number of elements in the important_channels array */
};
enum fluid_voice_status
{
- FLUID_VOICE_CLEAN,
- FLUID_VOICE_ON,
- FLUID_VOICE_SUSTAINED, /* Sustained by Sustain pedal */
- FLUID_VOICE_HELD_BY_SOSTENUTO, /* Sustained by Sostenuto pedal */
- FLUID_VOICE_OFF
+ FLUID_VOICE_CLEAN,
+ FLUID_VOICE_ON,
+ FLUID_VOICE_SUSTAINED, /* Sustained by Sustain pedal */
+ FLUID_VOICE_HELD_BY_SOSTENUTO, /* Sustained by Sostenuto pedal */
+ FLUID_VOICE_OFF
};
@@ -59,170 +63,135 @@ enum fluid_voice_status
*/
struct _fluid_voice_t
{
- unsigned int id; /* the id is incremented for every new noteon.
+ unsigned int id; /* the id is incremented for every new noteon.
it's used for noteoff's */
- unsigned char status;
- unsigned char chan; /* the channel number, quick access for channel messages */
- unsigned char key; /* the key, quick access for noteoff */
- unsigned char vel; /* the velocity */
- fluid_channel_t* channel;
- fluid_gen_t gen[GEN_LAST];
- fluid_mod_t mod[FLUID_NUM_MOD];
- int mod_count;
- fluid_sample_t* sample; /* Pointer to sample (dupe in rvoice) */
-
- int has_noteoff; /* Flag set when noteoff has been sent */
-
- /* basic parameters */
- fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
-
- unsigned int start_time;
- fluid_adsr_env_t volenv; /* Volume envelope (dupe in rvoice) */
-
- /* basic parameters */
- fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
- fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
- fluid_real_t root_pitch;
-
- /* master gain (dupe in rvoice) */
- fluid_real_t synth_gain;
-
- /* pan */
- fluid_real_t pan;
- fluid_real_t amp_left;
- fluid_real_t amp_right;
-
- /* reverb */
- fluid_real_t reverb_send;
- fluid_real_t amp_reverb;
-
- /* chorus */
- fluid_real_t chorus_send;
- fluid_real_t amp_chorus;
-
- /* rvoice control */
- fluid_rvoice_t* rvoice;
- fluid_rvoice_t* overflow_rvoice; /* Used temporarily and only in overflow situations */
- int can_access_rvoice; /* False if rvoice is being rendered in separate thread */
- int can_access_overflow_rvoice; /* False if overflow_rvoice is being rendered in separate thread */
-
- /* for debugging */
- int debug;
- double ref;
+ unsigned char status;
+ unsigned char chan; /* the channel number, quick access for channel messages */
+ unsigned char key; /* the key of the noteon event, quick access for noteoff */
+ unsigned char vel; /* the velocity of the noteon event */
+ fluid_channel_t *channel;
+ fluid_rvoice_eventhandler_t *eventhandler;
+ fluid_zone_range_t *zone_range; /* instrument zone range*/
+ fluid_sample_t *sample; /* Pointer to sample (dupe in rvoice) */
+
+ unsigned int start_time;
+ int mod_count;
+ fluid_mod_t mod[FLUID_NUM_MOD];
+ fluid_gen_t gen[GEN_LAST];
+
+ /* basic parameters */
+ fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
+
+ /* basic parameters */
+ fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
+ fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
+ fluid_real_t root_pitch;
+
+ /* master gain (dupe in rvoice) */
+ fluid_real_t synth_gain;
+
+ /* pan */
+ fluid_real_t pan;
+
+ /* balance */
+ fluid_real_t balance;
+
+ /* reverb */
+ fluid_real_t reverb_send;
+
+ /* chorus */
+ fluid_real_t chorus_send;
+
+ /* rvoice control */
+ fluid_rvoice_t *rvoice;
+ fluid_rvoice_t *overflow_rvoice; /* Used temporarily and only in overflow situations */
+ char can_access_rvoice; /* False if rvoice is being rendered in separate thread */
+ char can_access_overflow_rvoice; /* False if overflow_rvoice is being rendered in separate thread */
+ char has_noteoff; /* Flag set when noteoff has been sent */
+
+#ifdef WITH_PROFILING
+ /* for debugging */
+ double ref;
+#endif
};
-fluid_voice_t* new_fluid_voice(fluid_real_t output_rate);
-int delete_fluid_voice(fluid_voice_t* voice);
+fluid_voice_t *new_fluid_voice(fluid_rvoice_eventhandler_t *handler, fluid_real_t output_rate);
+void delete_fluid_voice(fluid_voice_t *voice);
-void fluid_voice_start(fluid_voice_t* voice);
-void fluid_voice_calculate_gen_pitch(fluid_voice_t* voice);
+void fluid_voice_start(fluid_voice_t *voice);
+void fluid_voice_calculate_gen_pitch(fluid_voice_t *voice);
-int fluid_voice_write (fluid_voice_t* voice, fluid_real_t *dsp_buf);
+int fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
+ fluid_zone_range_t *inst_zone_range,
+ fluid_channel_t *channel, int key, int vel,
+ unsigned int id, unsigned int time, fluid_real_t gain);
-int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
- fluid_channel_t* channel, int key, int vel,
- unsigned int id, unsigned int time, fluid_real_t gain);
-
-int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl);
-int fluid_voice_modulate_all(fluid_voice_t* voice);
+int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl);
+int fluid_voice_modulate_all(fluid_voice_t *voice);
/** Set the NRPN value of a generator. */
-int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t value, int abs);
+int fluid_voice_set_param(fluid_voice_t *voice, int gen, fluid_real_t value, int abs);
/** Set the gain. */
-int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain);
+int fluid_voice_set_gain(fluid_voice_t *voice, fluid_real_t gain);
-int fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value);
+void fluid_voice_set_output_rate(fluid_voice_t *voice, fluid_real_t value);
/** Update all the synthesis parameters, which depend on generator
'gen'. This is only necessary after changing a generator of an
already operating voice. Most applications will not need this
function.*/
-void fluid_voice_update_param(fluid_voice_t* voice, int gen);
-
-/** fluid_voice_release
- Force the voice into release stage. Usefuf anywhere a voice
- needs to be damped even if pedals (sustain sostenuto) are depressed.
- See fluid_synth_damp_voices_LOCAL(), fluid_synth_damp_voices_by_sostenuto_LOCAL,
- fluid_voice_noteoff(), fluid_synth_stop_LOCAL().
-*/
-void fluid_voice_release(fluid_voice_t* voice);
-int fluid_voice_noteoff(fluid_voice_t* voice);
-int fluid_voice_off(fluid_voice_t* voice);
-void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice);
-void fluid_voice_mix (fluid_voice_t *voice, int count, fluid_real_t* dsp_buf,
- fluid_real_t* left_buf, fluid_real_t* right_buf,
- fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
-
-int fluid_voice_kill_excl(fluid_voice_t* voice);
-fluid_real_t fluid_voice_get_overflow_prio(fluid_voice_t* voice,
- fluid_overflow_prio_t* score,
- unsigned int cur_time);
+void fluid_voice_update_param(fluid_voice_t *voice, int gen);
+
+/** legato modes */
+/* force in the attack section for legato mode multi_retrigger: 1 */
+void fluid_voice_update_multi_retrigger_attack(fluid_voice_t *voice, int tokey, int vel);
+/* Update portamento parameter */
+void fluid_voice_update_portamento(fluid_voice_t *voice, int fromkey, int tokey);
+
+
+void fluid_voice_release(fluid_voice_t *voice);
+void fluid_voice_noteoff(fluid_voice_t *voice);
+void fluid_voice_off(fluid_voice_t *voice);
+void fluid_voice_stop(fluid_voice_t *voice);
+void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice);
+
+int fluid_voice_kill_excl(fluid_voice_t *voice);
+float fluid_voice_get_overflow_prio(fluid_voice_t *voice,
+ fluid_overflow_prio_t *score,
+ unsigned int cur_time);
#define OVERFLOW_PRIO_CANNOT_KILL 999999.
/**
* Locks the rvoice for rendering, so it can't be modified directly
*/
-static FLUID_INLINE fluid_rvoice_t*
-fluid_voice_lock_rvoice(fluid_voice_t* voice)
+static FLUID_INLINE void
+fluid_voice_lock_rvoice(fluid_voice_t *voice)
{
- voice->can_access_rvoice = 0;
- return voice->rvoice;
+ voice->can_access_rvoice = 0;
}
/**
* Unlocks the rvoice for rendering, so it can be modified directly
*/
-static FLUID_INLINE void
-fluid_voice_unlock_rvoice(fluid_voice_t* voice)
+static FLUID_INLINE void
+fluid_voice_unlock_rvoice(fluid_voice_t *voice)
{
- voice->can_access_rvoice = 1;
+ voice->can_access_rvoice = 1;
}
-
-#define fluid_voice_get_channel(voice) ((voice)->channel)
-
-
-#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
-#define fluid_voice_get_chan(_voice) (_voice)->chan
-
-
-#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || \
- _SUSTAINED(voice) || \
- _HELD_BY_SOSTENUTO(voice) )
-
-/* A voice is 'ON', if it has not yet received a noteoff
- * event. Sending a noteoff event will advance the envelopes to
- * section 5 (release). */
-#define _ON(voice) ((voice)->status == FLUID_VOICE_ON && !voice->has_noteoff)
-#define _SUSTAINED(voice) ((voice)->status == FLUID_VOICE_SUSTAINED)
-#define _HELD_BY_SOSTENUTO(voice) ((voice)->status == FLUID_VOICE_HELD_BY_SOSTENUTO)
#define _AVAILABLE(voice) ((voice)->can_access_rvoice && \
(((voice)->status == FLUID_VOICE_CLEAN) || ((voice)->status == FLUID_VOICE_OFF)))
//#define _RELEASED(voice) ((voice)->chan == NO_CHANNEL)
#define _SAMPLEMODE(voice) ((int)(voice)->gen[GEN_SAMPLEMODE].val)
-/* FIXME - This doesn't seem to be used anywhere - JG */
-fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
-
-#define fluid_voice_get_loudness(voice) (fluid_adsr_env_get_max_val(&voice->volenv))
-
-#define _GEN(_voice, _n) \
- ((fluid_real_t)(_voice)->gen[_n].val \
- + (fluid_real_t)(_voice)->gen[_n].mod \
- + (fluid_real_t)(_voice)->gen[_n].nrpn)
-
-/* defined in fluid_dsp_float.c */
+fluid_real_t fluid_voice_gen_value(const fluid_voice_t *voice, int num);
+void fluid_voice_set_custom_filter(fluid_voice_t *voice, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags);
-void fluid_dsp_float_config (void);
-int fluid_dsp_float_interpolate_none (fluid_voice_t *voice);
-int fluid_dsp_float_interpolate_linear (fluid_voice_t *voice);
-int fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice);
-int fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice);
#endif /* _FLUID_VOICE_H */
diff --git a/libs/fluidsynth/src/fluidsynth_priv.h b/libs/fluidsynth/src/fluidsynth_priv.h
index b01618df26..d500f6174e 100644
--- a/libs/fluidsynth/src/fluidsynth_priv.h
+++ b/libs/fluidsynth/src/fluidsynth_priv.h
@@ -3,16 +3,16 @@
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
@@ -24,9 +24,7 @@
#include <glib.h>
-#if HAVE_CONFIG_H
#include "config.h"
-#endif
#if HAVE_STRING_H
#include <string.h>
@@ -100,40 +98,61 @@
#include <pthread.h>
#endif
+#if HAVE_OPENMP
+#include <omp.h>
+#endif
+
#if HAVE_IO_H
#include <io.h>
#endif
-#if HAVE_WINDOWS_H
-#include <windows.h>
+#if HAVE_SIGNAL_H
+#include <signal.h>
#endif
-/* MinGW32 special defines */
-#ifdef MINGW32
-
+/** Integer types */
+#if HAVE_STDINT_H
#include <stdint.h>
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
+#else
+
+/* Assume GLIB types */
+typedef gint8 int8_t;
+typedef guint8 uint8_t;
+typedef gint16 int16_t;
+typedef guint16 uint16_t;
+typedef gint32 int32_t;
+typedef guint32 uint32_t;
+typedef gint64 int64_t;
+typedef guint64 uint64_t;
+
+#endif
+
+#if defined(WIN32) && HAVE_WINDOWS_H
+//#include <winsock2.h>
+//#include <ws2tcpip.h> /* Provides also socklen_t */
+#include <windows.h>
+
+/* WIN32 special defines */
#define DSOUND_SUPPORT 1
#define WINMIDI_SUPPORT 1
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
-#elif defined _MSC_VER
-
-#define STDIN_FILENO _fileno(stdin)
-#define STDOUT_FILENO _fileno(stdout)
-#define STDERR_FILENO _fileno(stderr)
+#ifdef _MSC_VER
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4101)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4996)
+#endif
#endif
/* Darwin special defines (taken from config_macosx.h) */
#ifdef DARWIN
-#define MACINTOSH
-#define __Types__
-#define WITHOUT_SERVER 1
+# define MACINTOSH
+# define __Types__
#endif
@@ -156,7 +175,6 @@ typedef double fluid_real_t;
typedef SOCKET fluid_socket_t;
#else
typedef int fluid_socket_t;
-#define INVALID_SOCKET -1
#endif
#if defined(SUPPORTS_VLA)
@@ -168,15 +186,10 @@ typedef int fluid_socket_t;
#endif
-/** Integer types */
-//typedef gint8 sint8;
-typedef guint8 uint8;
-//typedef gint16 sint16;
-//typedef guint16 uint16;
-typedef gint32 sint32;
-typedef guint32 uint32;
-//typedef gint64 sint64;
-//typedef guint64 uint64;
+/** Atomic types */
+typedef int fluid_atomic_int_t;
+typedef unsigned int fluid_atomic_uint_t;
+typedef float fluid_atomic_float_t;
/***************************************************************
@@ -191,6 +204,25 @@ typedef struct _fluid_hashtable_t fluid_hashtable_t;
typedef struct _fluid_client_t fluid_client_t;
typedef struct _fluid_server_socket_t fluid_server_socket_t;
typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
+typedef struct _fluid_zone_range_t fluid_zone_range_t;
+typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t;
+
+/* Declare rvoice related typedefs here instead of fluid_rvoice.h, as it's needed
+ * in fluid_lfo.c and fluid_adsr.c as well */
+typedef union _fluid_rvoice_param_t
+{
+ void *ptr;
+ int i;
+ fluid_real_t real;
+} fluid_rvoice_param_t;
+enum { MAX_EVENT_PARAMS = 6 }; /**< Maximum number of #fluid_rvoice_param_t to be passed to an #fluid_rvoice_function_t */
+typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS]);
+
+/* Macro for declaring an rvoice event function (#fluid_rvoice_function_t). The functions may only access
+ * those params that were previously set in fluid_voice.c
+ */
+#define DECLARE_FLUID_RVOICE_FUNCTION(name) void name(void* obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS])
+
/***************************************************************
*
@@ -198,48 +230,84 @@ typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
*/
#define FLUID_BUFSIZE 64 /**< FluidSynth internal buffer size (in samples) */
+#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE) /**< Number of buffers that can be processed in one rendering run */
#define FLUID_MAX_EVENTS_PER_BUFSIZE 1024 /**< Maximum queued MIDI events per #FLUID_BUFSIZE */
#define FLUID_MAX_RETURN_EVENTS 1024 /**< Maximum queued synthesis thread return events */
#define FLUID_MAX_EVENT_QUEUES 16 /**< Maximum number of unique threads queuing events */
#define FLUID_DEFAULT_AUDIO_RT_PRIO 60 /**< Default setting for audio.realtime-prio */
#define FLUID_DEFAULT_MIDI_RT_PRIO 50 /**< Default setting for midi.realtime-prio */
-
-#ifndef PI
-#define PI 3.141592654
-#endif
+#define FLUID_NUM_MOD 64 /**< Maximum number of modulators in a voice */
/***************************************************************
*
* SYSTEM INTERFACE
*/
-typedef FILE* fluid_file;
+typedef FILE *fluid_file;
#define FLUID_MALLOC(_n) malloc(_n)
#define FLUID_REALLOC(_p,_n) realloc(_p,_n)
#define FLUID_NEW(_t) (_t*)malloc(sizeof(_t))
-#define FLUID_ARRAY(_t,_n) (_t*)malloc((_n)*sizeof(_t))
+#define FLUID_ARRAY_ALIGNED(_t,_n,_a) (_t*)malloc((_n)*sizeof(_t) + ((unsigned int)_a - 1u))
+#define FLUID_ARRAY(_t,_n) FLUID_ARRAY_ALIGNED(_t,_n,1u)
#define FLUID_FREE(_p) free(_p)
#define FLUID_FOPEN(_f,_m) fopen(_f,_m)
#define FLUID_FCLOSE(_f) fclose(_f)
#define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
#define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
+#define FLUID_FTELL(_f) ftell(_f)
#define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
#define FLUID_MEMSET(_s,_c,_n) memset(_s,_c,_n)
#define FLUID_STRLEN(_s) strlen(_s)
#define FLUID_STRCMP(_s,_t) strcmp(_s,_t)
#define FLUID_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n)
#define FLUID_STRCPY(_dst,_src) strcpy(_dst,_src)
-#define FLUID_STRNCPY(_dst,_src,_n) strncpy(_dst,_src,_n)
+
+#define FLUID_STRNCPY(_dst,_src,_n) \
+do { strncpy(_dst,_src,_n); \
+ (_dst)[(_n)-1]=0; \
+}while(0)
+
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
#define FLUID_STRRCHR(_s,_c) strrchr(_s,_c)
+
#ifdef strdup
-#define FLUID_STRDUP(s) strdup(s)
+#define FLUID_STRDUP(s) strdup(s)
#else
-#define FLUID_STRDUP(s) FLUID_STRCPY(FLUID_MALLOC(FLUID_STRLEN(s) + 1), s)
+#define FLUID_STRDUP(s) FLUID_STRCPY(FLUID_MALLOC(FLUID_STRLEN(s) + 1), s)
#endif
+
#define FLUID_SPRINTF sprintf
#define FLUID_FPRINTF fprintf
+#if (defined(WIN32) && _MSC_VER < 1900) || defined(MINGW32)
+/* need to make sure we use a C99 compliant implementation of (v)snprintf(),
+ * i.e. not microsofts non compliant extension _snprintf() as it doesnt
+ * reliably null-terminates the buffer
+ */
+#define FLUID_SNPRINTF g_snprintf
+#else
+#define FLUID_SNPRINTF snprintf
+#endif
+
+#if (defined(WIN32) && _MSC_VER < 1500) || defined(MINGW32)
+#define FLUID_VSNPRINTF g_vsnprintf
+#else
+#define FLUID_VSNPRINTF vsnprintf
+#endif
+
+#if defined(WIN32) && !defined(MINGW32)
+#define FLUID_STRCASECMP _stricmp
+#else
+#define FLUID_STRCASECMP strcasecmp
+#endif
+
+#if defined(WIN32) && !defined(MINGW32)
+#define FLUID_STRNCASECMP _strnicmp
+#else
+#define FLUID_STRNCASECMP strncasecmp
+#endif
+
+
#define fluid_clip(_val, _min, _max) \
{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); }
@@ -251,21 +319,38 @@ typedef FILE* fluid_file;
#define FLUID_FLUSH() fflush(stdout)
#endif
+/* People who want to reduce the size of the may do this by entirely
+ * removing the logging system. This will cause all log messages to
+ * be discarded at compile time, allowing to save about 80 KiB for
+ * the compiled binary.
+ */
+#if 0
+#define FLUID_LOG (void)sizeof
+#else
#define FLUID_LOG fluid_log
+#endif
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530941723212145818
+#endif
-#define FLUID_ASSERT(a,b)
-#define FLUID_ASSERT_P(a,b)
-
-char* fluid_error(void);
+#ifndef M_LN10
+#define M_LN10 2.3025850929940456840179914546844
+#endif
+#ifdef DEBUG
+#define FLUID_ASSERT(a) g_assert(a)
+#else
+#define FLUID_ASSERT(a)
+#endif
-/* Internationalization */
-#define _(s) s
+#define FLUID_LIKELY G_LIKELY
+#define FLUID_UNLIKELY G_UNLIKELY
+char *fluid_error(void);
#endif /* _FLUIDSYNTH_PRIV_H */
diff --git a/libs/fluidsynth/wscript b/libs/fluidsynth/wscript
index ebce6efcb4..9b6422c341 100644
--- a/libs/fluidsynth/wscript
+++ b/libs/fluidsynth/wscript
@@ -5,9 +5,9 @@ import os
import sys
# Version of this package (even if built as a child)
-MAJOR = '1'
-MINOR = '1'
-MICRO = '6'
+MAJOR = '2'
+MINOR = '0'
+MICRO = '1'
LIBFLUIDSYNTH_VERSION = "%s.%s.%s" % (MAJOR, MINOR, MICRO)
# Variables for 'waf dist'
@@ -58,7 +58,11 @@ def build(bld):
'src/fluid_hash.c',
'src/fluid_list.c',
'src/fluid_ringbuffer.c',
+ 'src/fluid_samplecache.c',
'src/fluid_settings.c',
+ 'src/fluid_sffile.c',
+ 'src/fluid_sfont.c',
+ 'src/fluid_synth_monopoly.c',
'src/fluid_sys.c'
],
cflags = [ bld.env['compiler_flags_dict']['pic'], '-fvisibility=hidden' ],