Update Fluidsynth to 2.0.1

This commit is contained in:
Robin Gareus
2018-10-18 00:41:02 +02:00
parent 5b280463ce
commit abf7905d5f
72 changed files with 26031 additions and 16899 deletions

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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,100 +33,84 @@ 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 */
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
};
FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
#ifdef __cplusplus
}

View File

@@ -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, ...);

View File

@@ -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 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_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);
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_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
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);
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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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 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);
int fluid_settings_get_type(fluid_settings_t *settings, const char *name);
FLUIDSYNTH_API
int fluid_settings_get_hints(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_is_realtime(fluid_settings_t* settings, const char *name);
int fluid_settings_is_realtime(fluid_settings_t *settings, const char *name);
FLUIDSYNTH_API
int fluid_settings_setstr(fluid_settings_t* settings, const char *name, const char *str);
int fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str);
FLUIDSYNTH_API
int fluid_settings_copystr(fluid_settings_t* settings, const char *name, char *str, int len);
int fluid_settings_copystr(fluid_settings_t *settings, const char *name, char *str, int len);
FLUIDSYNTH_API
int fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str);
int fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str);
FLUIDSYNTH_API
int fluid_settings_getstr(fluid_settings_t* settings, const char *name, char** str);
int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def);
FLUIDSYNTH_API
char* fluid_settings_getstr_default(fluid_settings_t* settings, const char *name);
int fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *value);
FLUIDSYNTH_API
int fluid_settings_str_equal(fluid_settings_t* settings, const char *name, const char *value);
int fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val);
FLUIDSYNTH_API
int fluid_settings_setnum(fluid_settings_t* settings, const char *name, double val);
int fluid_settings_getnum(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_default(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_range(fluid_settings_t *settings, const char *name,
double *min, double *max);
FLUIDSYNTH_API
void fluid_settings_getnum_range(fluid_settings_t* settings, const char *name,
double* min, double* max);
int fluid_settings_setint(fluid_settings_t *settings, const char *name, int val);
FLUIDSYNTH_API
int fluid_settings_setint(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(fluid_settings_t* settings, const char *name, int* val);
int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val);
FLUIDSYNTH_API
int fluid_settings_getint_default(fluid_settings_t* settings, const char *name);
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
}

View File

@@ -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 */
};
/**
* SoundFont loader structure.
*/
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);
};
/**
* Virtual SoundFont instance structure.
*/
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);
};
#define fluid_sfont_get_id(_sf) ((_sf)->id)
/**
* Virtual SoundFont preset.
*/
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);
};
/**
* Virtual SoundFont sample.
*/
struct _fluid_sample_t
enum
{
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 */
FLUID_PRESET_SELECTED, /**< Preset selected notify */
FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
FLUID_SAMPLE_DONE /**< Sample no longer needed notify */
};
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 */
/**
* Indicates the type of a sample used by the _fluid_sample_t::sampletype field.
*/
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 */
};
#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) */
/**
* 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.
*/
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);
#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 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);
FLUIDSYNTH_API fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings);
/**
* 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
*/
typedef void *(* fluid_sfloader_callback_open_t)(const char *filename);
/**
* 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.
*/
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);
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);
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
}

View File

@@ -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);
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);
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 */
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 */
};
#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. */
/* 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_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_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_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 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[]);
/**
* 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);
/* 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);
FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
fluid_midi_router_t* router);
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! */
};
/**
* Specifies optional settings to use for the custom IIR filter
*/
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. */
};
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);
#ifdef __cplusplus
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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;
fluid_env_data_t *env_data;
fluid_real_t x;
env_data = &env->data[env->section];
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;
/* 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;
}
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;
/* 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;
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);
DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data);
static inline void
fluid_adsr_env_reset(fluid_adsr_env_t* env)
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

View File

@@ -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;
}
fluid_channel_init(chan);
fluid_channel_init_ctrl(chan, 0);
chan->synth = synth;
chan->channum = num;
chan->preset = NULL;
chan->tuning = NULL;
return chan;
fluid_channel_init(chan);
fluid_channel_init_ctrl(chan, 0);
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;
fluid_preset_t *newpreset;
int i, prognum, banknum;
chan->sostenuto_orderid = 0;
chan->sostenuto_orderid = 0;
/*--- Init poly/mono modes variables --------------------------------------*/
chan->mode = 0;
chan->mode_val = 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;
/* monophonic list initialization */
for(i = 0; i < FLUID_CHANNEL_SIZE_MONOLIST; i++)
{
chan->monolist[i].next = i + 1;
}
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
| prognum << PROG_SHIFTVAL;
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 --------------------------------------*/
newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
fluid_channel_set_preset(chan, newpreset);
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->interp_method = FLUID_INTERP_DEFAULT;
chan->tuning_bank = 0;
chan->tuning_prog = 0;
chan->nrpn_select = 0;
chan->nrpn_active = 0;
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
| prognum << PROG_SHIFTVAL;
if (chan->tuning)
{
fluid_tuning_unref (chan->tuning, 1);
chan->tuning = NULL;
}
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;
int i;
chan->key_pressure = 0;
chan->channel_pressure = 0;
chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
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);
for(i = 0; i < GEN_LAST; i++)
{
chan->gen[i] = 0.0f;
chan->gen_abs[i] = 0;
}
/* Volume / initial attenuation (MSB & LSB) */
fluid_channel_set_cc (chan, VOLUME_MSB, 100);
fluid_channel_set_cc (chan, VOLUME_LSB, 0);
if(is_all_ctrl_off)
{
for(i = 0; i < ALL_SOUND_OFF; i++)
{
if(i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5)
{
continue;
}
/* Pan (MSB & LSB) */
fluid_channel_set_cc (chan, PAN_MSB, 64);
fluid_channel_set_cc (chan, PAN_LSB, 0);
if(i >= SOUND_CTRL1 && i <= SOUND_CTRL10)
{
continue;
}
/* 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 */
}
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_preset_notify (chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
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;
fluid_preset_notify (preset, FLUID_PRESET_SELECTED, chan->channum);
if(chan->preset == preset)
{
return FLUID_OK;
}
return FLUID_OK;
if(chan->preset)
{
sfont = chan->preset->sfont;
sfont->refcount--;
}
fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
chan->preset = preset;
if(preset)
{
sfont = preset->sfont;
sfont->refcount++;
}
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;
int oldval, newval, style;
style = chan->synth->bank_select;
if (style == FLUID_BANK_STYLE_GM ||
style == FLUID_BANK_STYLE_GS)
return; /* ignored */
style = chan->synth->bank_select;
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;
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;
int oldval, newval, style;
style = chan->synth->bank_select;
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_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 */
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;
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;
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);
}
}
chan->previous_cc_breath = value;
}

View File

@@ -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 */
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 */
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
fluid_preset_t* preset; /**< Selected preset */
/* 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 */
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 */
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 */
int cc[128]; /**< MIDI controller values */
unsigned char cc[128]; /**< MIDI controller values from [0;127] */
unsigned char key_pressure[128]; /**< MIDI polyphonic key pressure from [0;127] */
/* 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 */
/* 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) */
/* 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 */
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;
/* 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];
int tuning_bank; /**< Current tuning bank number */
int tuning_prog; /**< Current tuning program number */
fluid_tuning_t *tuning; /**< Micro tuning */
/* 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_preset_t *preset; /**< Selected preset */
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
int channel_type;
/* 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 */

View File

@@ -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;
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;
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];
/* 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;
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;
}
chorus = FLUID_NEW(fluid_chorus_t);
FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
if(chorus == NULL)
{
FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
return NULL;
}
chorus->sample_rate = sample_rate;
FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
/* Lookup table for the SI function (impulse response of an ideal low pass) */
chorus->sample_rate = sample_rate;
/* i: Offset in terms of whole samples */
for (i = 0; i < INTERPOLATION_SAMPLES; i++){
/* Lookup table for the SI function (impulse response of an ideal low pass) */
/* 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.;
/* i: Offset in terms of whole samples */
for(i = 0; i < INTERPOLATION_SAMPLES; i++)
{
} 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));
};
/* 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));
};
};
};
};
/* 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 lookup tables */
chorus->lookup_tab = FLUID_ARRAY(int, (int)(chorus->sample_rate / MIN_SPEED_HZ));
/* allocate sample buffer */
if(chorus->lookup_tab == NULL)
{
FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
goto error_recovery;
}
chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
if (chorus->chorusbuf == NULL) {
fluid_log(FLUID_PANIC, "chorus: Out of memory");
goto error_recovery;
}
/* allocate sample buffer */
if (fluid_chorus_init(chorus) != FLUID_OK){
goto error_recovery;
};
chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
return chorus;
if(chorus->chorusbuf == NULL)
{
FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
goto error_recovery;
}
error_recovery:
delete_fluid_chorus(chorus);
return NULL;
if(fluid_chorus_init(chorus) != FLUID_OK)
{
goto error_recovery;
};
return chorus;
error_recovery:
delete_fluid_chorus(chorus);
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;
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(set & FLUID_CHORUS_SET_NR)
{
chorus->number_blocks = nr;
}
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(set & FLUID_CHORUS_SET_LEVEL)
{
chorus->level = level;
}
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(set & FLUID_CHORUS_SET_SPEED)
{
chorus->speed_Hz = speed;
}
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(set & FLUID_CHORUS_SET_DEPTH)
{
chorus->depth_ms = depth_ms;
}
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;
}
if(set & FLUID_CHORUS_SET_TYPE)
{
chorus->type = type;
}
/* The modulating LFO goes through a full period every x samples: */
chorus->modulation_period_samples = chorus->sample_rate / chorus->speed_Hz;
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;
}
/* 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(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 (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;
}
if(chorus->depth_ms < 0.0)
{
FLUID_LOG(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
chorus->depth_ms = 0.0;
}
/* 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);
}
/* Depth: Check for too high value through 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);
}
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;
}
/* Start of the circular buffer */
chorus->counter = 0;
/* 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. */
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]++;
/* Store 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 */
/* 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;
} /* 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;
int i;
double angle, incr, mult;
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]);
}
/* 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;
int *il = buf;
int *ir = buf + len - 1;
int ival;
double val, incr;
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;
}
/* 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;
}
}

View File

@@ -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);
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_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);
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);

View File

@@ -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;
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);
}
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);
}
/* 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) */
/* 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;
/* 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[FLUID_VEL_CB_SIZE - 1] = 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. */
/* 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;
}
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 = M_PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
/* 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);
}
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.
*/
/*
* 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];
}
/* minimum attenuation: 0 dB */
if(cb < 0)
{
return 1.0;
}
/*
* 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];
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];
}

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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)? */
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 */
fluid_preset_t iter_preset; /* preset interface used in the iteration */
fluid_defpreset_t* iter_cur; /* the current preset in the iteration */
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_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 */
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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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);
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);
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_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);
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,
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);
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);
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 */

View File

@@ -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;
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? */
/* 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++)
if(iir_filter->type == FLUID_IIR_DISABLED || iir_filter->q_lin == 0)
{
/* 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;
return;
}
}
else
{
/* IIR filter sample history */
fluid_real_t dsp_hist1 = iir_filter->hist1;
fluid_real_t dsp_hist2 = iir_filter->hist2;
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;
/* 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_check_fpe ("voice_filter");
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? */
}
/* 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;
}
}
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)
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init)
{
iir_filter->hist1 = 0;
iir_filter->hist2 = 0;
iir_filter->last_fres = -1.;
iir_filter->filter_startup = 1;
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;
if(type != FLUID_IIR_DISABLED)
{
fluid_iir_filter_reset(iir_filter);
}
}
void
fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
fluid_real_t fres)
void
fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter)
{
iir_filter->fres = fres;
iir_filter->last_fres = -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_q_dB(fluid_iir_filter_t* iir_filter,
fluid_real_t q_dB)
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres)
{
fluid_iir_filter_t *iir_filter = obj;
fluid_real_t fres = param[0].real;
iir_filter->fres = fres;
iir_filter->last_fres = -1.;
}
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)
{
/*
* 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;
// 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;
/* 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;
}
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;
}
/* 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;
fluid_real_t fres;
/* calculate the frequency of the resonant filter in Hz */
fres = fluid_ct2hz(iir_filter->fres + fres_mod);
/* 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? */
/* 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. */
/* 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(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);
}
/* 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");
fluid_check_fpe("voice_write DSP coefficients");
}

View File

@@ -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 */
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.
/* 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.
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

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}
return list;
}
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;
while((n-- > 0) && list)
{
list = list->next;
}
prev = tmp;
tmp = tmp->next;
}
return list;
return list;
}
fluid_list_t*
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;
}
prev = tmp;
tmp = tmp->next;
}
return list;
}
fluid_list_t *
fluid_list_remove_link(fluid_list_t *list, fluid_list_t *link)
{
fluid_list_t *tmp;
fluid_list_t *prev;
fluid_list_t *tmp;
fluid_list_t *prev;
prev = NULL;
tmp = list;
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;
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;
}
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;
}
if(!list)
{
return NULL;
}
l1 = list;
l2 = list->next;
if(!list->next)
{
return list;
}
while ((l2 = l2->next) != NULL) {
if ((l2 = l2->next) == NULL)
break;
l1=l1->next;
}
l2 = l1->next;
l1->next = NULL;
l1 = list;
l2 = list->next;
return fluid_list_sort_merge(fluid_list_sort(list, compare_func),
fluid_list_sort(l2, compare_func),
compare_func);
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;
}

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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;
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 */
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;
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 */
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 */

View File

@@ -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 (fluid_real_t) mod->amount;
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
)
{
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;
extern fluid_mod_t default_vel2filter_mod;
if (chan == NULL) {
return 0.0f;
}
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 ((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)) {
/* '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 */
v1 = fluid_mod_transform_source_value(v1, mod->flags1, range1);
}
else
{
return 0.0;
}
/* 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;
}
} 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;
}
/* no need to go further */
if(v1 == 0.0f)
{
return 0.0f;
}
/* 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;
}
} else {
v2 = 1.0f;
}
/* get the second input source */
if(mod->src2 > 0)
{
v2 = fluid_mod_get_source_value(mod->src2, mod->flags2, &range2, voice);
/* it's as simple as that: */
return (fluid_real_t) mod->amount * v1 * v2;
/* transform the second input value */
v2 = fluid_mod_transform_source_value(v2, mod->flags2, range2);
}
else
{
v2 = 1.0f;
}
/* 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);
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()
{
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;
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 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;
#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_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);
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

View File

@@ -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 */

View File

@@ -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++. */

View File

@@ -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_revmodel_t *rev;
rev = FLUID_NEW(fluid_revmodel_t);
fluid_set_revmodel_buffers(rev, sample_rate);
if(rev == NULL)
{
return NULL;
}
/* 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);
fluid_set_revmodel_buffers(rev, sample_rate);
rev->gain = fixedgain;
fluid_revmodel_set(rev,FLUID_REVMODEL_SET_ALL,initialroom,initialdamp,initialwidth,initialwet);
/* 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);
return rev;
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]);
}
int i;
fluid_return_if_fail(rev != NULL);
FLUID_FREE(rev);
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) {
fluid_set_revmodel_buffers(fluid_revmodel_t *rev, fluid_real_t sample_rate)
{
float srfactor = sample_rate/44100.0f;
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);
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);
/* 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;
int i, k = 0;
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
for(k = 0; k < FLUID_BUFSIZE; k++)
{
outL = outR = 0;
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;
/* 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);
/* 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;
int i, k = 0;
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
for(k = 0; k < FLUID_BUFSIZE; k++)
{
outL = outR = 0;
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;
/* 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);
/* 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;
}
/* 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;
}
}
static void
fluid_revmodel_update(fluid_revmodel_t* rev)
fluid_revmodel_update(fluid_revmodel_t *rev)
{
/* Recalculate internal values after parameter change */
int i;
/* 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);
/* 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);
for (i = 0; i < numcombs; i++) {
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
}
/* 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_setdamp(&rev->combL[i], rev->damp);
fluid_comb_setdamp(&rev->combR[i], rev->damp);
}
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);
}
}
/**
@@ -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);
}

View File

@@ -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_t;
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. */
#define FLUID_REVMODEL_SET_ALL 0x0F
/** 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;
/*
* 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 */

View File

@@ -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);
}

View File

@@ -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;
if (queue->in >= queue->totalcount)
queue->in -= queue->totalcount;
queue->in += count;
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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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;
/* Note-off minimum length */
unsigned int ticks;
unsigned int noteoff_ticks;
/* vol env */
fluid_adsr_env_t volenv;
/* 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 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;
/* 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;
/* 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. */
/* interpolation method, as in fluid_interp in fluidsynth.h */
enum fluid_interp interp_method;
enum fluid_loop samplemode;
/* 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;
/* Flag that is set as soon as the first loop is completed. */
char has_looped;
/* Stuff needed for phase calculations */
/* Flag that initiates, that sample-related parameters have to be checked. */
char check_sample_sanity_flag;
fluid_real_t pitch; /* the pitch in midicents */
fluid_real_t root_pitch_hz;
fluid_real_t output_rate;
fluid_sample_t *sample;
/* Stuff needed for amplitude calculations */
/* 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) */
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
/* Stuff needed for portamento calculations */
fluid_real_t pitchoffset; /* the portamento range in midicents */
fluid_real_t pitchinc; /* the portamento increment in midicents */
/* 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 */
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 */
/* Dynamic input to the interpolator below */
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
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 */
int is_looping;
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);
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);
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp);
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_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);
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

File diff suppressed because it is too large Load Diff

View File

@@ -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; }
static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event);
#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; }
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;
fluid_rvoice_event_t local_event;
if (event == NULL) {
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
return FLUID_FAILED; // Buffer full...
}
local_event.method = method;
local_event.object = object;
local_event.param[0].i = intparam;
local_event.param[1].real = realparam;
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;
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 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;
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;
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;
}
int
fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t* handler,
void* method, void* object, void* ptr)
void
fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler, fluid_rvoice_t *rvoice)
{
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;
fluid_rvoice_t **vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
if (event == NULL) {
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
return FLUID_FAILED; // Buffer full...
}
if(vptr == NULL)
{
return; // 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;
*vptr = rvoice;
fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
}
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)
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_event_t* event;
fluid_rvoice_event_t local_event;
event = handler->is_threadsafe ?
fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
if (event == NULL) {
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
return FLUID_FAILED; // Buffer full...
}
if(eventhandler == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
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;
}
eventhandler->mixer = NULL;
eventhandler->queue = NULL;
eventhandler->finished_voices = NULL;
fluid_atomic_int_set(&eventhandler->queue_stored, 0);
static void
finished_voice_callback(void* userdata, 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);
}
eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
sizeof(fluid_rvoice_t *));
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* 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;
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->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;
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;
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);
}

View File

@@ -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);
/**
* 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
*/
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;
};
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);
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*);
static FLUID_INLINE void
fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t* handler)
struct _fluid_rvoice_event_t
{
if (handler->queue_stored > 0) {
fluid_ringbuffer_next_inptr(handler->queue, handler->queue_stored);
handler->queue_stored = 0;
}
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.
* fluid_rvoice_eventhandler_fetch_all() can be called in parallell
* with fluid_rvoice_eventhandler_push/flush()
*/
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 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 *);
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)
{
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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -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 delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *);
void fluid_rvoice_mixer_set_finished_voices_callback(
fluid_rvoice_mixer_t* mixer,
void (*func)(void*, fluid_rvoice_t*),
void* userdata);
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);
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb);
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus);
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);
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count,
fluid_real_t sample_rate);
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

View File

@@ -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;
}

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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_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_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) */
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_info; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
fluid_hashtable_t *sfont_hash; /**< Hash of fluid_sfont_t->fluid_sfont_info_t (remains until SoundFont is deleted) */
unsigned int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
fluid_list_t *loaders; /**< the SoundFont loaders */
fluid_list_t *sfont; /**< 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;
fluid_rvoice_eventhandler_t* eventhandler;
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;
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 */
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 */
float chorus_level; /**< Shadow of chorus level */
float chorus_speed; /**< Shadow of chorus speed */
float chorus_depth; /**< Shadow of chorus depth */
int chorus_type; /**< Shadow of chorus type */
int chorus_nr; /**< Shadow of chorus number */
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) */
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_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_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 */
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 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);
/**
* 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,
unsigned int banknum,
unsigned int prognum);
void fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont);
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);
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_dither_s16(int *dither_index, int len, float *lin, float *rin,
void *lout, int loff, int lincr,
void *rout, int roff, int rincr);
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,
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);
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);
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 */

View File

@@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -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)
#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
#define fluid_return_val_if_fail(cond, val) \
fluid_return_if_fail(cond) (val)
/*
* Utility functions
*/
char *fluid_strtok (char **str, char *delim);
/**
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
};
int fluid_debug(int level, char * fmt, ...);
#else
#define fluid_debug
#endif
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 */
/**
* 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
};
#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
*/
/* 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) */
#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 */
/* logging profiling data (used on synthesizer instance deletion) */
void fluid_profiling_print(void);
/** Profiling data. Keep track of min/avg/max values to execute a
/*----------------------------------------------
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 */
};
/** Macro to obtain a time refence used for the profiling */
/* 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 */
/*----------------------------------------------
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 */

View File

@@ -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;
}
return tuning;
fluid_atomic_int_set(&tuning->refcount, 1); /* Start with a refcount of 1 */
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 (tuning->name)
{
new_tuning->name = FLUID_STRDUP (tuning->name);
if (!new_tuning->name)
if(!new_tuning)
{
FLUID_FREE (new_tuning);
FLUID_LOG (FLUID_PANIC, "Out of memory");
return NULL;
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
}
else new_tuning->name = NULL;
new_tuning->bank = tuning->bank;
new_tuning->prog = tuning->prog;
FLUID_MEMSET(new_tuning, 0, sizeof(fluid_tuning_t));
for (i = 0; i < 128; i++)
new_tuning->pitch[i] = tuning->pitch[i];
if(fluid_tuning_set_name(new_tuning, tuning->name) != FLUID_OK)
{
delete_fluid_tuning(new_tuning);
return NULL;
}
new_tuning->refcount = 1; /* Start with a refcount of 1 */
new_tuning->bank = tuning->bank;
new_tuning->prog = tuning->prog;
return new_tuning;
for(i = 0; i < 128; i++)
{
new_tuning->pitch[i] = tuning->pitch[i];
}
fluid_atomic_int_set(&new_tuning->refcount, 1); /* Start with a refcount of 1 */
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);
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);
/* 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;
/* Delete when refcount reaches 0 */
if(!fluid_atomic_int_get(&tuning->refcount))
{
delete_fluid_tuning(tuning);
return TRUE;
}
else
{
return FALSE;
}
}
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name)
int fluid_tuning_set_name(fluid_tuning_t *tuning, const char *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_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;
}
char* fluid_tuning_get_name(fluid_tuning_t* tuning)
char *fluid_tuning_get_name(fluid_tuning_t *tuning)
{
return tuning->name;
return tuning->name;
}
static void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
void fluid_tuning_set_octave(fluid_tuning_t *tuning, const double *pitch_deriv)
{
tuning->pitch[key] = pitch;
int i;
for(i = 0; i < 128; i++)
{
tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12];
}
}
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)
{
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] = pitch[i];
}
}
void fluid_tuning_set_all(fluid_tuning_t* tuning, const double* pitch)
void fluid_tuning_set_pitch(fluid_tuning_t *tuning, int key, double pitch)
{
int 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)
{
if ((key >= 0) && (key < 128)) {
tuning->pitch[key] = pitch;
}
if((key >= 0) && (key < 128))
{
tuning->pitch[key] = pitch;
}
}

View File

@@ -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])

File diff suppressed because it is too large Load Diff

View File

@@ -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) */
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) */
int has_noteoff; /* Flag set when noteoff has been sent */
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 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;
/* 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;
/* master gain (dupe in rvoice) */
fluid_real_t synth_gain;
/* pan */
fluid_real_t pan;
/* pan */
fluid_real_t pan;
fluid_real_t amp_left;
fluid_real_t amp_right;
/* balance */
fluid_real_t balance;
/* reverb */
fluid_real_t reverb_send;
fluid_real_t amp_reverb;
/* reverb */
fluid_real_t reverb_send;
/* chorus */
fluid_real_t chorus_send;
fluid_real_t amp_chorus;
/* chorus */
fluid_real_t chorus_send;
/* 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 */
/* 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 */
/* for debugging */
int debug;
double ref;
#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);
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);
/** 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);
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_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);
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);
#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 */
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 */

View File

@@ -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)
#ifndef M_LN10
#define M_LN10 2.3025850929940456840179914546844
#endif
char* fluid_error(void);
#ifdef DEBUG
#define FLUID_ASSERT(a) g_assert(a)
#else
#define FLUID_ASSERT(a)
#endif
#define FLUID_LIKELY G_LIKELY
#define FLUID_UNLIKELY G_UNLIKELY
/* Internationalization */
#define _(s) s
char *fluid_error(void);
#endif /* _FLUIDSYNTH_PRIV_H */

View File

@@ -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' ],

View File

@@ -1,73 +1,74 @@
diff --git b/libs/fluidsynth/src/fluid_defsfont.c a/libs/fluidsynth/src/fluid_defsfont.c
index 3eea95c..c395218 100644
--- b/libs/fluidsynth/src/fluid_defsfont.c
+++ a/libs/fluidsynth/src/fluid_defsfont.c
@@ -109,11 +109,13 @@ char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont)
return fluid_defsfont_get_name((fluid_defsfont_t*) sfont->data);
}
diff --git b/libs/fluidsynth/fluidsynth/synth.h a/libs/fluidsynth/fluidsynth/synth.h
index 1a0046fe1..a4afb9094 100644
--- b/libs/fluidsynth/fluidsynth/synth.h
+++ a/libs/fluidsynth/fluidsynth/synth.h
@@ -265,7 +265,7 @@ FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t *synth, int len,
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);
-FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
+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,
@@ -310,7 +310,9 @@ FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int
+#if 0
fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s)
{
/* This function is here just to avoid an ABI/SONAME bump, see ticket #98. Should never be used. */
return NULL;
}
/* LADSPA */
+#ifdef LADSPA
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
+#endif
fluid_preset_t*
fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum)
/* API: Poly mono mode */
diff --git b/libs/fluidsynth/fluidsynth/types.h a/libs/fluidsynth/fluidsynth/types.h
index 47ef18336..5ad29281a 100644
--- b/libs/fluidsynth/fluidsynth/types.h
+++ a/libs/fluidsynth/fluidsynth/types.h
@@ -56,7 +56,9 @@ typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer i
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 */
diff --git b/libs/fluidsynth/src/fluid_hash.c a/libs/fluidsynth/src/fluid_hash.c
index a063e29..9d5a920 100644
index 37b0a06a4..b6586895b 100644
--- b/libs/fluidsynth/src/fluid_hash.c
+++ a/libs/fluidsynth/src/fluid_hash.c
@@ -93,7 +93,7 @@ static const guint primes[] =
static const unsigned int nprimes = sizeof (primes) / sizeof (primes[0]);
-unsigned int
+static unsigned int
spaced_primes_closest (unsigned int num)
{
unsigned int i;
@@ -984,6 +984,7 @@ fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
return deleted;
@@ -991,6 +991,7 @@ fluid_hashtable_remove_all(fluid_hashtable_t *hashtable)
fluid_hashtable_maybe_resize(hashtable);
}
+#if 0
/**
* fluid_hashtable_foreach_remove:
* fluid_hashtable_steal_all:
* @hashtable: a #fluid_hashtable_t.
@@ -1001,7 +1002,7 @@ fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
*
* Return value: the number of key/value pairs removed.
**/
-unsigned int
+static unsigned int
fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
fluid_hr_func_t func, void *user_data)
{
@@ -1010,6 +1011,7 @@ fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
return fluid_hashtable_foreach_remove_or_steal (hashtable, func, user_data, TRUE);
@@ -1008,6 +1009,7 @@ fluid_hashtable_steal_all(fluid_hashtable_t *hashtable)
fluid_hashtable_remove_all_nodes(hashtable, FALSE);
fluid_hashtable_maybe_resize(hashtable);
}
+#endif
/**
* fluid_hashtable_foreach_steal:
/*
* fluid_hashtable_foreach_remove_or_steal:
diff --git b/libs/fluidsynth/src/fluid_midi.c a/libs/fluidsynth/src/fluid_midi.c
index 5ceab01..171952f 100644
index c05f994ce..bdf72dd68 100644
--- b/libs/fluidsynth/src/fluid_midi.c
+++ a/libs/fluidsynth/src/fluid_midi.c
@@ -34,7 +34,7 @@ static int fluid_midi_event_length(unsigned char event);
static char* fluid_file_read_full(fluid_file fp, size_t* length);
#define READ_FULL_INITIAL_BUFLEN 1024
@@ -75,7 +75,7 @@ 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
/***************************************************************
*
* MIDIFILE
@@ -760,6 +760,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
@@ -1011,6 +1011,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
{
return midifile->division;
}
@@ -75,7 +76,7 @@ index 5ceab01..171952f 100644
/******************************************************
*
@@ -1030,7 +1031,7 @@ fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, int size, int dy
@@ -1330,7 +1331,7 @@ static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type,
*
* fluid_track_t
*/
@@ -84,228 +85,196 @@ index 5ceab01..171952f 100644
/*
* new_fluid_track
*/
@@ -1118,7 +1119,7 @@ fluid_track_get_duration(fluid_track_t *track)
/*
* fluid_track_count_events
*/
-int
+static int
fluid_track_count_events(fluid_track_t *track, int *on, int *off)
{
fluid_midi_event_t *evt = track->first;
@@ -1533,7 +1534,7 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
return FLUID_OK;
}
@@ -2434,3 +2435,4 @@ fluid_midi_event_length(unsigned char event)
-void
+static void
fluid_player_advancefile(fluid_player_t *player)
{
if (player->playlist == NULL) {
@@ -1553,7 +1554,7 @@ fluid_player_advancefile(fluid_player_t *player)
}
}
-void
+static void
fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
{
fluid_playlist_item* current_playitem;
@@ -1938,3 +1939,4 @@ fluid_midi_event_length(unsigned char event)
}
return 1;
}
+#endif
diff --git b/libs/fluidsynth/src/fluid_rev.c a/libs/fluidsynth/src/fluid_rev.c
index 51b0e79..166007d 100644
index 8a58d1e85..51b4faa25 100644
--- b/libs/fluidsynth/src/fluid_rev.c
+++ a/libs/fluidsynth/src/fluid_rev.c
@@ -75,7 +75,7 @@ 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);
@@ -51,7 +51,7 @@ 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
+static void
fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
{
allpass->bufidx = 0;
@@ -83,7 +83,7 @@ fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
allpass->bufsize = size;
allpass->bufidx = 0;
@@ -59,7 +59,7 @@ fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
allpass->bufsize = size;
}
-void
+static void
fluid_allpass_release(fluid_allpass* allpass)
fluid_allpass_release(fluid_allpass *allpass)
{
FLUID_FREE(allpass->buffer);
FLUID_FREE(allpass->buffer);
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.c a/libs/fluidsynth/src/fluid_rvoice_mixer.c
index 4672cb8..d5369aa 100644
index 3b264e4d9..8c5254f26 100644
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.c
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.c
@@ -24,12 +24,12 @@
@@ -24,11 +24,9 @@
#include "fluid_rev.h"
#include "fluid_chorus.h"
#include "fluidsynth_priv.h"
-#include "fluid_ladspa.h"
+//#include "fluid_ladspa.h"
#define SYNTH_REVERB_CHANNEL 0
#define SYNTH_CHORUS_CHANNEL 1
#include "fluid_synth.h"
-
-#define ENABLE_MIXER_THREADS 1
+#undef ENABLE_MIXER_THREADS // Ardour does the multithreading -- synth.cpu-cores defaults to 1
// If less than x voices, the thread overhead is larger than the gain,
// so don't activate the thread(s).
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.h a/libs/fluidsynth/src/fluid_rvoice_mixer.h
index eeb49ec..d4e41ca 100644
index 4ee072e4b..1b3fceb34 100644
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.h
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.h
@@ -24,7 +24,7 @@
@@ -24,7 +24,6 @@
#include "fluidsynth_priv.h"
#include "fluid_rvoice.h"
-#include "fluid_ladspa.h"
+//#include "fluid_ladspa.h"
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
diff --git b/libs/fluidsynth/src/fluid_settings.c a/libs/fluidsynth/src/fluid_settings.c
index 78725fb..56de8c7 100644
index d77d5ed79..05423384e 100644
--- b/libs/fluidsynth/src/fluid_settings.c
+++ a/libs/fluidsynth/src/fluid_settings.c
@@ -22,9 +22,9 @@
@@ -21,9 +21,6 @@
#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_cmd.h"
+//#include "fluid_adriver.h"
+//#include "fluid_mdriver.h"
#include "fluid_settings.h"
#include "fluid_midi.h"
@@ -294,11 +294,13 @@ fluid_settings_init(fluid_settings_t* settings)
fluid_return_if_fail (settings != NULL);
@@ -328,11 +325,13 @@ fluid_settings_init(fluid_settings_t *settings)
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
diff --git b/libs/fluidsynth/src/fluid_synth.c a/libs/fluidsynth/src/fluid_synth.c
index 84ee289..a12260c 100644
index a40ba2eaa..e8845632f 100644
--- b/libs/fluidsynth/src/fluid_synth.c
+++ a/libs/fluidsynth/src/fluid_synth.c
@@ -471,7 +471,7 @@ struct _fluid_sample_timer_t
/*
* fluid_sample_timer_process - called when synth->ticks is updated
@@ -267,7 +267,7 @@ void fluid_version(int *major, int *minor, int *micro)
* @return FluidSynth version string, which is internal and should not be
* modified or freed.
*/
-void fluid_sample_timer_process(fluid_synth_t* synth)
+static void fluid_sample_timer_process(fluid_synth_t* synth)
-char *
+const char *
fluid_version_str(void)
{
fluid_sample_timer_t* st;
long msec;
return FLUIDSYNTH_VERSION;
@@ -6435,6 +6435,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
FLUID_API_RETURN(FLUID_OK);
}
+#ifdef LADSPA
/**
* Return the LADSPA effects instance used by FluidSynth
*
@@ -6447,6 +6448,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
return synth->ladspa_fx;
}
+#endif
/**
* Configure a general-purpose IIR biquad filter.
diff --git b/libs/fluidsynth/src/fluid_synth.h a/libs/fluidsynth/src/fluid_synth.h
index 3af336d..019a8e0 100644
index 95e2c2e5f..96dc54574 100644
--- b/libs/fluidsynth/src/fluid_synth.h
+++ a/libs/fluidsynth/src/fluid_synth.h
@@ -37,8 +37,8 @@
@@ -33,8 +33,6 @@
#include "fluid_rev.h"
#include "fluid_voice.h"
#include "fluid_chorus.h"
-#include "fluid_ladspa.h"
-#include "fluid_midi_router.h"
+//#include "fluid_ladspa.h"
+//#include "fluid_midi_router.h"
#include "fluid_sys.h"
#include "fluid_rvoice_event.h"
/***************************************************************
@@ -165,7 +163,9 @@ struct _fluid_synth_t
fluid_mod_t *default_mod; /**< the (dynamic) list of default modulators */
+#ifdef LADSPA
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 */
};
diff --git b/libs/fluidsynth/src/fluid_sys.c a/libs/fluidsynth/src/fluid_sys.c
index ee7d8d9..328f255 100644
index 5a4a2dd93..c9662f778 100644
--- b/libs/fluidsynth/src/fluid_sys.c
+++ a/libs/fluidsynth/src/fluid_sys.c
@@ -686,7 +686,7 @@ fluid_thread_join(fluid_thread_t* thread)
}
-void
+static void
fluid_timer_run (void *data)
@@ -202,9 +202,10 @@ 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)
{
fluid_timer_t *timer;
@@ -950,6 +950,7 @@ fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
#endif
}
- char *s, *d, *token;
+ char *s, *token;
+ const char *d;
char c;
+#if 0 // Ardour says: no, thanks
int fluid_server_socket_join(fluid_server_socket_t *server_socket)
{
return fluid_thread_join (server_socket->thread);
@@ -1294,3 +1295,4 @@ int delete_fluid_server_socket(fluid_server_socket_t *server_socket)
}
if(str == NULL || delim == NULL || !*delim)
diff --git b/libs/fluidsynth/src/fluid_sys.h a/libs/fluidsynth/src/fluid_sys.h
index 47cc95c11..d95f6159f 100644
--- b/libs/fluidsynth/src/fluid_sys.h
+++ a/libs/fluidsynth/src/fluid_sys.h
@@ -91,7 +91,7 @@ else \
/*
* Utility functions
*/
-char *fluid_strtok(char **str, char *delim);
+char *fluid_strtok(char **str, const char *delim);
#endif
+#endif
diff --git b/libs/fluidsynth/src/fluid_tuning.c a/libs/fluidsynth/src/fluid_tuning.c
index cc440aa..8977ed6 100644
--- b/libs/fluidsynth/src/fluid_tuning.c
+++ a/libs/fluidsynth/src/fluid_tuning.c
@@ -143,7 +143,7 @@ char* fluid_tuning_get_name(fluid_tuning_t* tuning)
return tuning->name;
}
-void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
+static void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
{
tuning->pitch[key] = pitch;
}
#if defined(__OS2__)
diff --git b/libs/fluidsynth/src/fluidsynth_priv.h a/libs/fluidsynth/src/fluidsynth_priv.h
index faf2772..b01618d 100644
index 41e398398..d500f6174 100644
--- b/libs/fluidsynth/src/fluidsynth_priv.h
+++ a/libs/fluidsynth/src/fluidsynth_priv.h
@@ -28,14 +28,6 @@
@@ -26,10 +26,6 @@
#include "config.h"
#endif
-#if defined(__POWERPC__) && !(defined(__APPLE__) && defined(__MACH__))
-#include "config_maxmsp43.h"
-#endif
-
-#if defined(WIN32) && !defined(MINGW32)
-#include "config_win32.h"
-#endif
-
#if HAVE_STRING_H
#include <string.h>
#endif
@@ -113,8 +105,6 @@
@@ -133,8 +129,9 @@ typedef guint64 uint64_t;
#endif
#if HAVE_WINDOWS_H
#if defined(WIN32) && HAVE_WINDOWS_H
-#include <winsock2.h>
-#include <ws2tcpip.h>
#include <windows.h>
#endif
-#include <ws2tcpip.h> /* Provides also socklen_t */
+//#include <winsock2.h>
+//#include <ws2tcpip.h> /* Provides also socklen_t */
+#include <windows.h>
@@ -131,6 +121,12 @@
#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)
+
#endif
/* Darwin special defines (taken from config_macosx.h) */
/* WIN32 special defines */
#define DSOUND_SUPPORT 1

View File

@@ -23,7 +23,7 @@ cd $TMP
#git clone git://git.code.sf.net/p/fluidsynth/code-git fs-git
git clone git://github.com/FluidSynth/fluidsynth.git fs-git
FSR=fs-git/fluidsynth/
FSR=fs-git/
rsync -auc --info=progress2 \
${FSR}src/midi/fluid_midi.c \
@@ -48,18 +48,23 @@ rsync -auc --info=progress2 \
${FSR}src/rvoice/fluid_rvoice_mixer.h \
${FSR}src/sfloader/fluid_defsfont.c \
${FSR}src/sfloader/fluid_defsfont.h \
${FSR}src/sfloader/fluid_samplecache.c \
${FSR}src/sfloader/fluid_samplecache.h \
${FSR}src/sfloader/fluid_sffile.c \
${FSR}src/sfloader/fluid_sffile.h \
${FSR}src/sfloader/fluid_sfont.c \
${FSR}src/sfloader/fluid_sfont.h \
${FSR}src/synth/fluid_chan.c \
${FSR}src/synth/fluid_chan.h \
${FSR}src/synth/fluid_event.c \
${FSR}src/synth/fluid_event_priv.h \
${FSR}src/synth/fluid_event_queue.h \
${FSR}src/synth/fluid_event.h \
${FSR}src/synth/fluid_gen.c \
${FSR}src/synth/fluid_gen.h \
${FSR}src/synth/fluid_mod.c \
${FSR}src/synth/fluid_mod.h \
${FSR}src/synth/fluid_synth.c \
${FSR}src/synth/fluid_synth.h \
${FSR}src/synth/fluid_synth_monopoly.c \
${FSR}src/synth/fluid_tuning.c \
${FSR}src/synth/fluid_tuning.h \
${FSR}src/synth/fluid_voice.c \