mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-08 00:31:11 +00:00
Merged fluidsynth_event_queue branch r207:223 into trunk.
This commit is contained in:
parent
cf39719f5d
commit
e5c832c587
34 changed files with 5735 additions and 3032 deletions
|
@ -4,6 +4,7 @@ Current development team
|
|||
Josh Green
|
||||
Bernat Arlandis i Mañó
|
||||
Pedro Lopez-Cabanillas
|
||||
David Henningsson
|
||||
|
||||
|
||||
[:Idea:]
|
||||
|
@ -72,6 +73,9 @@ summary of contributions.
|
|||
to make iiwusynth independent from any library for maximum
|
||||
portability.
|
||||
|
||||
* David Henningsson added code for fast rendering of MIDI files and
|
||||
fixed many bugs.
|
||||
|
||||
* The midi device uses code from jMax's alsarawmidi.c file and from
|
||||
Smurf's midi_alsaraw.c by Josh Green. file: iiwu_alsa.c
|
||||
|
||||
|
|
|
@ -133,6 +133,12 @@ int fluid_settings_is_realtime(fluid_settings_t* settings, char* name);
|
|||
FLUIDSYNTH_API
|
||||
int fluid_settings_setstr(fluid_settings_t* settings, char* name, char* str);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_copystr(fluid_settings_t* settings, char* name, char* str, int len);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_dupstr(fluid_settings_t* settings, char* name, char** str);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str);
|
||||
|
||||
|
|
|
@ -27,306 +27,113 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
|
||||
/** Embedded 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.
|
||||
*
|
||||
* 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(), ...
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Embedded 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.
|
||||
*
|
||||
* 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(), ...
|
||||
*/
|
||||
|
||||
|
||||
/** Creates a new synthesizer object.
|
||||
*
|
||||
* Creates a new synthesizer object. As soon as the synthesizer is
|
||||
* created, it will start playing.
|
||||
*
|
||||
* \param settings a pointer to a settings structure
|
||||
* \return a newly allocated synthesizer or NULL in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_synth_t* new_fluid_synth(fluid_settings_t* settings);
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the synthesizer previously created with new_fluid_synth.
|
||||
*
|
||||
* \param synth the synthesizer object
|
||||
* \return 0 if no error occured, -1 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API int delete_fluid_synth(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/** Get a reference to the settings of the synthesizer.
|
||||
*
|
||||
* \param synth the synthesizer object
|
||||
* \return pointer to the settings
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_settings_t* fluid_synth_get_settings(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* MIDI channel messages
|
||||
*
|
||||
*/
|
||||
/* MIDI channel messages */
|
||||
|
||||
/** Send a noteon message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/** Send a noteoff message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key);
|
||||
|
||||
/** Send a control change message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t* synth, int chan, int ctrl, int val);
|
||||
|
||||
/** Get a control value. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t* synth, int chan, int ctrl, int* pval);
|
||||
|
||||
/** Send a pitch bend message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val);
|
||||
|
||||
/** Get the pitch bend value. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend);
|
||||
|
||||
/** Set the pitch wheel sensitivity. Returns 0 if no error occurred, -1 otherwise. */
|
||||
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);
|
||||
|
||||
/** Get the pitch wheel sensitivity. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
|
||||
|
||||
/** Send a program change message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
|
||||
|
||||
/** Send a channel aftertouch message. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val);
|
||||
|
||||
/** Select a bank. Returns 0 if no error occurred, -1 otherwise. */
|
||||
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_program_select(fluid_synth_t* synth, int chan, unsigned int sfont_id,
|
||||
unsigned int bank_num, unsigned int preset_num);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
|
||||
|
||||
/** Select a sfont. Returns 0 if no error occurred, -1 otherwise. */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id);
|
||||
|
||||
/** Select a preset for a channel. The preset is specified by the
|
||||
SoundFont ID, the bank number, and the preset number. This
|
||||
allows any preset to be selected and circumvents preset masking
|
||||
due to previously loaded SoundFonts on the SoundFont stack.
|
||||
|
||||
\param synth The synthesizer
|
||||
\param chan The channel on which to set the preset
|
||||
\param sfont_id The ID of the SoundFont
|
||||
\param bank_num The bank number
|
||||
\param preset_num The preset number
|
||||
\return 0 if no errors occured, -1 otherwise
|
||||
*/
|
||||
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);
|
||||
|
||||
/** Returns the program, bank, and SoundFont number of the preset on
|
||||
a given channel. Returns 0 if no error occurred, -1 otherwise. */
|
||||
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);
|
||||
|
||||
/** Send a bank select and a program change to every channel to
|
||||
* reinitialize the preset of the channel. This function is useful
|
||||
* mainly after a SoundFont has been loaded, unloaded or
|
||||
* reloaded. . Returns 0 if no error occurred, -1 otherwise. */
|
||||
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_program_reset(fluid_synth_t* synth);
|
||||
|
||||
/** Send a reset. A reset turns all the notes off and resets the
|
||||
controller values. */
|
||||
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Low level access
|
||||
*
|
||||
*/
|
||||
|
||||
/** Create and start voices using a preset. The id passed as
|
||||
* argument will be used as the voice group id. */
|
||||
/* 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);
|
||||
|
||||
/** Stop the voices in the voice group defined by id. */
|
||||
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t* synth, unsigned int id);
|
||||
|
||||
/** Change the value of a generator of the voices in the voice group
|
||||
* defined by id. */
|
||||
/* FLUIDSYNTH_API int fluid_synth_ctrl(fluid_synth_t* synth, int id, */
|
||||
/* int gen, float value, */
|
||||
/* int absolute, int normalized); */
|
||||
|
||||
/* SoundFont management */
|
||||
|
||||
/*
|
||||
*
|
||||
* SoundFont management
|
||||
*
|
||||
*/
|
||||
|
||||
/** Loads a SoundFont file and creates a new SoundFont. The newly
|
||||
loaded SoundFont will be put on top of the SoundFont
|
||||
stack. Presets are searched starting from the SoundFont on the
|
||||
top of the stack, working the way down the stack until a preset
|
||||
is found.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param filename The file name
|
||||
\param reset_presets If non-zero, the presets on the channels will be reset
|
||||
\returns The ID of the loaded SoundFont, or -1 in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets);
|
||||
|
||||
/** Reload a SoundFont. The reloaded SoundFont retains its ID and
|
||||
index on the stack.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param id The id of the SoundFont
|
||||
\returns The ID of the loaded SoundFont, or -1 in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
|
||||
|
||||
/** Removes a SoundFont from the stack and deallocates it.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param id The id of the SoundFont
|
||||
\param reset_presets If TRUE then presets will be reset for all channels
|
||||
\returns 0 if no error, -1 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets);
|
||||
|
||||
/** Add a SoundFont. The SoundFont will be put on top of
|
||||
the SoundFont stack.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param sfont The SoundFont
|
||||
\returns The ID of the loaded SoundFont, or -1 in case of error
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
|
||||
|
||||
/** Remove a SoundFont that was previously added using
|
||||
* fluid_synth_add_sfont(). The synthesizer does not delete the
|
||||
* SoundFont; this is responsability of the caller.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param sfont The SoundFont
|
||||
*/
|
||||
FLUIDSYNTH_API void fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
|
||||
|
||||
/** Count the number of loaded SoundFonts.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\returns The number of loaded SoundFonts
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t* synth);
|
||||
|
||||
/** Get a SoundFont. The SoundFont is specified by its index on the
|
||||
stack. The top of the stack has index zero.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param num The number of the SoundFont (0 <= num < sfcount)
|
||||
\returns A pointer to the SoundFont
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num);
|
||||
|
||||
/** Get a SoundFont. The SoundFont is specified by its ID.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param id The id of the sfont
|
||||
\returns A pointer to the SoundFont
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id);
|
||||
|
||||
|
||||
/** Get the preset of a channel */
|
||||
FLUIDSYNTH_API fluid_preset_t* fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan);
|
||||
|
||||
/** Offset the bank numbers in a SoundFont. Returns -1 if an error
|
||||
* occured (out of memory or negative offset) */
|
||||
FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset);
|
||||
|
||||
/** Get the offset of the bank numbers in a SoundFont. */
|
||||
FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id);
|
||||
|
||||
|
||||
/* Reverb */
|
||||
|
||||
/*
|
||||
*
|
||||
* Reverb
|
||||
*
|
||||
*/
|
||||
|
||||
/** Set the parameters for the built-in reverb unit */
|
||||
FLUIDSYNTH_API void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize,
|
||||
double damping, double width, double level);
|
||||
|
||||
/** Turn on (1) / off (0) the built-in reverb unit */
|
||||
double damping, double width, double level);
|
||||
FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t* synth, int on);
|
||||
|
||||
|
||||
/** Query the current state of the reverb. */
|
||||
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);
|
||||
|
||||
/* Those are the default settings for the reverb */
|
||||
/* Default settings for the reverb */
|
||||
#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f
|
||||
#define FLUID_REVERB_DEFAULT_DAMP 0.0f
|
||||
#define FLUID_REVERB_DEFAULT_WIDTH 0.5f
|
||||
#define FLUID_REVERB_DEFAULT_LEVEL 0.9f
|
||||
|
||||
|
||||
/* Chorus */
|
||||
|
||||
/*
|
||||
*
|
||||
* Chorus
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Chorus modulation waveform type.
|
||||
*/
|
||||
enum fluid_chorus_mod {
|
||||
FLUID_CHORUS_MOD_SINE = 0,
|
||||
FLUID_CHORUS_MOD_TRIANGLE = 1
|
||||
FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */
|
||||
FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
|
||||
};
|
||||
|
||||
/** Set up the chorus. It should be turned on with fluid_synth_set_chorus_on.
|
||||
* If faulty parameters are given, all new settings are discarded.
|
||||
* Keep in mind, that the needed CPU time is proportional to 'nr'.
|
||||
*/
|
||||
FLUIDSYNTH_API void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
||||
double speed, double depth_ms, int type);
|
||||
|
||||
/** Turn on (1) / off (0) the built-in chorus unit */
|
||||
FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t* synth, int on);
|
||||
|
||||
/** Query the current state of the chorus. */
|
||||
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 */
|
||||
|
||||
/* Those are the default settings for the chorus. */
|
||||
/* Default settings for the chorus. */
|
||||
#define FLUID_CHORUS_DEFAULT_N 3
|
||||
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f
|
||||
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f
|
||||
|
@ -334,367 +141,122 @@ FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t* synth); /* see flu
|
|||
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
|
||||
|
||||
|
||||
/* Audio and MIDI channels */
|
||||
|
||||
/*
|
||||
*
|
||||
* Audio and MIDI channels
|
||||
*
|
||||
*/
|
||||
|
||||
/** Returns the number of MIDI channels that the synthesizer uses
|
||||
internally */
|
||||
FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t* synth);
|
||||
|
||||
/** Returns the number of audio channels that the synthesizer uses
|
||||
internally */
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t* synth);
|
||||
|
||||
/** Returns the number of audio groups that the synthesizer uses
|
||||
internally. This is usually identical to audio_channels. */
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t* synth);
|
||||
|
||||
/** Returns the number of effects channels that the synthesizer uses
|
||||
internally */
|
||||
FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/* Synthesis parameters */
|
||||
|
||||
/*
|
||||
*
|
||||
* Synthesis parameters
|
||||
*
|
||||
*/
|
||||
|
||||
/** Set the master gain */
|
||||
FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t* synth, float gain);
|
||||
|
||||
/** Get the master gain */
|
||||
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t* synth);
|
||||
|
||||
/** Set the polyphony limit (FluidSynth >= 1.0.6) */
|
||||
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony);
|
||||
|
||||
/** Get the polyphony limit (FluidSynth >= 1.0.6) */
|
||||
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t* synth);
|
||||
|
||||
/** Get the internal buffer size. The internal buffer size if not the
|
||||
same thing as the buffer size specified in the
|
||||
settings. Internally, the synth *always* uses a specific buffer
|
||||
size independent of the buffer size used by the audio driver. The
|
||||
internal buffer size is normally 64 samples. The reason why it
|
||||
uses an internal buffer size is to allow audio drivers to call the
|
||||
synthesizer with a variable buffer length. The internal buffer
|
||||
size is useful for client who want to optimize their buffer sizes.
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t* synth);
|
||||
|
||||
/** Set the interpolation method for one channel or all channels (chan = -1) */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method);
|
||||
|
||||
/* Flags to choose the interpolation method */
|
||||
/**
|
||||
* Synthesis interpolation method.
|
||||
*/
|
||||
enum fluid_interp {
|
||||
/* no interpolation: Fastest, but questionable audio quality */
|
||||
FLUID_INTERP_NONE = 0,
|
||||
/* Straight-line interpolation: A bit slower, reasonable audio quality */
|
||||
FLUID_INTERP_LINEAR = 1,
|
||||
/* Fourth-order interpolation: Requires 50 % of the whole DSP processing time, good quality
|
||||
* Default. */
|
||||
FLUID_INTERP_DEFAULT = 4,
|
||||
FLUID_INTERP_4THORDER = 4,
|
||||
FLUID_INTERP_7THORDER = 7,
|
||||
FLUID_INTERP_HIGHEST=7
|
||||
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 */
|
||||
};
|
||||
|
||||
/** Default interpolation method from #fluid_interp. */
|
||||
#define FLUID_INTERP_DEFAULT FLUID_INTERP_4THORDER
|
||||
|
||||
/** Highest interpolation method from #fluid_interp. */
|
||||
#define FLUID_INTERP_HIGHEST FLUID_INTERP_7THORDER
|
||||
|
||||
|
||||
/* Generator interface */
|
||||
|
||||
/*
|
||||
*
|
||||
* Generator interface
|
||||
*
|
||||
*/
|
||||
|
||||
/** Change the value of a generator. This function allows to control
|
||||
all synthesis parameters in real-time. The changes are additive,
|
||||
i.e. they add up to the existing parameter value. This function is
|
||||
similar to sending an NRPN message to the synthesizer. The
|
||||
function accepts a float as the value of the parameter. The
|
||||
parameter numbers and ranges are described in the SoundFont 2.01
|
||||
specification, paragraph 8.1.3, page 48. See also 'fluid_gen_type'.
|
||||
|
||||
\param synth The synthesizer object.
|
||||
\param chan The MIDI channel number.
|
||||
\param param The parameter number.
|
||||
\param value The parameter value.
|
||||
\returns Your favorite dish.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value);
|
||||
|
||||
|
||||
/** Retreive the value of a generator. This function returns the value
|
||||
set by a previous call 'fluid_synth_set_gen' or by an NRPN message.
|
||||
|
||||
\param synth The synthesizer object.
|
||||
\param chan The MIDI channel number.
|
||||
\param param The generator number.
|
||||
\returns The value of the generator.
|
||||
*/
|
||||
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
|
||||
|
||||
|
||||
/* Tuning */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Tuning
|
||||
*
|
||||
*/
|
||||
|
||||
/** Create a new key-based tuning with given name, number, and
|
||||
pitches. The array 'pitches' should have length 128 and contains
|
||||
the pitch in cents of every key in cents. However, if 'pitches' is
|
||||
NULL, a new tuning is created with the well-tempered scale.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
\param name The name of the tuning
|
||||
\param pitch The array of pitch values. The array length has to be 128.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_create_key_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
|
||||
char* name, double* pitch);
|
||||
|
||||
/** Create a new octave-based tuning with given name, number, and
|
||||
pitches. The array 'pitches' should have length 12 and contains
|
||||
derivation in cents from the well-tempered scale. For example, if
|
||||
pitches[0] equals -33, then the C-keys will be tuned 33 cents
|
||||
below the well-tempered C.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
\param name The name of the tuning
|
||||
\param pitch The array of pitch derivations. The array length has to be 12.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
|
||||
char* name, double* pitch);
|
||||
|
||||
/** Request a note tuning changes. Both they 'keys' and 'pitches'
|
||||
arrays should be of length 'num_pitches'. If 'apply' is non-zero,
|
||||
the changes should be applied in real-time, i.e. sounding notes
|
||||
will have their pitch updated. 'APPLY' IS CURRENTLY IGNORED. The
|
||||
changes will be available for newly triggered notes only.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
\param len The length of the keys and pitch arrays
|
||||
\param keys The array of keys values.
|
||||
\param pitch The array of pitch values.
|
||||
\param apply Flag to indicate whether to changes should be applied in real-time.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_tune_notes(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
|
||||
int len, int *keys, double* pitch, int apply);
|
||||
|
||||
/** Select a tuning for a channel.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param chan The channel number [0-max channels]
|
||||
\param tuning_bank The tuning bank number [0-127]
|
||||
\param tuning_prog The tuning program number [0-127]
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int tuning_bank, int tuning_prog);
|
||||
|
||||
/** Set the tuning to the default well-tempered tuning on a channel.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param chan The channel number [0-max channels]
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_reset_tuning(fluid_synth_t* synth, int chan);
|
||||
|
||||
/** Start the iteration throught the list of available tunings.
|
||||
|
||||
\param synth The synthesizer object
|
||||
*/
|
||||
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/** Get the next tuning in the iteration. This functions stores the
|
||||
bank and program number of the next tuning in the pointers given as
|
||||
arguments.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param bank Pointer to an int to store the bank number
|
||||
\param prog Pointer to an int to store the program number
|
||||
\returns 1 if there is a next tuning, 0 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog);
|
||||
|
||||
|
||||
/** Dump the data of a tuning. This functions stores the name and
|
||||
pitch values of a tuning in the pointers given as arguments. Both
|
||||
name and pitch can be NULL is the data is not needed.
|
||||
|
||||
\param synth The synthesizer object
|
||||
\param bank The tuning bank number [0-127]
|
||||
\param prog The tuning program number [0-127]
|
||||
\param name Pointer to a buffer to store the name
|
||||
\param len The length of the name buffer
|
||||
\param pitch Pointer to buffer to store the pitch values
|
||||
*/
|
||||
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
|
||||
char* name, int len, double* pitch);
|
||||
|
||||
/* Misc */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Misc
|
||||
*
|
||||
*/
|
||||
|
||||
/** Get an estimation of the CPU load due to the audio synthesis.
|
||||
Returns a percentage (0-100).
|
||||
|
||||
\param synth The synthesizer object
|
||||
*/
|
||||
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t* synth);
|
||||
|
||||
/** Get a textual representation of the last error */
|
||||
FLUIDSYNTH_API char* fluid_synth_error(fluid_synth_t* synth);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Synthesizer plugin
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Generate a number of samples. This function expects two signed
|
||||
* 16bits buffers (left and right channel) that will be filled with
|
||||
* samples.
|
||||
*
|
||||
* \param synth The synthesizer
|
||||
* \param len The number of samples to generate
|
||||
* \param lout The sample buffer for the left channel
|
||||
* \param loff The offset, in samples, in the left buffer where the writing pointer starts
|
||||
* \param lincr The increment, in samples, of the writing pointer in the left buffer
|
||||
* \param rout The sample buffer for the right channel
|
||||
* \param roff The offset, in samples, in the right buffer where the writing pointer starts
|
||||
* \param rincr The increment, in samples, of the writing pointer in the right buffer
|
||||
* \returns 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
/*
|
||||
* Synthesizer plugin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/** Generate a number of samples. This function expects two floating
|
||||
* point buffers (left and right channel) that will be filled with
|
||||
* samples.
|
||||
*
|
||||
* \param synth The synthesizer
|
||||
* \param len The number of samples to generate
|
||||
* \param lout The sample buffer for the left channel
|
||||
* \param loff The offset, in samples, in the left buffer where the writing pointer starts
|
||||
* \param lincr The increment, in samples, of the writing pointer in the left buffer
|
||||
* \param rout The sample buffer for the right channel
|
||||
* \param roff The offset, in samples, in the right buffer where the writing pointer starts
|
||||
* \param rincr The increment, in samples, of the writing pointer in the right buffer
|
||||
* \returns 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/** Generate a number of samples. This function implements the
|
||||
* default interface defined in fluidsynth/audio.h. This function
|
||||
* ignores the input buffers and expects at least two output
|
||||
* buffer.
|
||||
*
|
||||
* \param synth The synthesizer
|
||||
* \param len The number of samples to generate
|
||||
* \param nin The number of input buffers
|
||||
* \param in The array of input buffers
|
||||
* \param nout The number of output buffers
|
||||
* \param out The array of output buffers
|
||||
* \returns 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t* synth, int len,
|
||||
int nin, float** in,
|
||||
int nout, float** out);
|
||||
|
||||
|
||||
|
||||
/* Type definition of the synthesizer's audio callback function. */
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Synthesizer's interface to handle SoundFont loaders
|
||||
*/
|
||||
|
||||
|
||||
/** Add a SoundFont loader to the synthesizer. Note that SoundFont
|
||||
loader don't necessarily load SoundFonts. They can load any type
|
||||
of wavetable data but export a SoundFont interface. */
|
||||
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader);
|
||||
|
||||
/** Allocate a synthesis voice. This function is called by a
|
||||
soundfont's preset in response to a noteon event.
|
||||
The returned voice comes with default modulators installed (velocity-to-attenuation,
|
||||
velocity to filter, ...)
|
||||
Note: A single noteon event may create any number of voices, when the preset is layered.
|
||||
Typically 1 (mono) or 2 (stereo).*/
|
||||
FLUIDSYNTH_API fluid_voice_t* fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample,
|
||||
int channum, int key, int vel);
|
||||
|
||||
/** Start a synthesis voice. This function is called by a
|
||||
soundfont's preset in response to a noteon event after the voice
|
||||
has been allocated with fluid_synth_alloc_voice() and
|
||||
initialized.
|
||||
Exclusive classes are processed here.*/
|
||||
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);
|
||||
|
||||
|
||||
/** Write a list of all voices matching ID into buf, but not more than bufsize voices.
|
||||
* If ID <0, return all voices. */
|
||||
FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t* synth,
|
||||
fluid_voice_t* buf[], int bufsize, int ID);
|
||||
|
||||
|
||||
/** Callback function for the MIDI router. Any event goes through this. */
|
||||
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);
|
||||
|
||||
|
||||
/** This is a hack to get command handlers working */
|
||||
FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
|
||||
fluid_midi_router_t* router);
|
||||
FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
|
||||
fluid_midi_router_t* router);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -82,6 +82,8 @@ libfluidsynth_la_SOURCES = \
|
|||
fluid_dsp_float.c \
|
||||
fluid_event.c \
|
||||
fluid_event_priv.h \
|
||||
fluid_event_queue.c \
|
||||
fluid_event_queue.h \
|
||||
fluid_gen.c \
|
||||
fluid_gen.h \
|
||||
fluid_hash.c \
|
||||
|
|
|
@ -332,8 +332,6 @@ new_fluid_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
char* name;
|
||||
char allnames[256];
|
||||
|
||||
fluid_settings_getstr(settings, "audio.driver", &name);
|
||||
|
||||
for (i = 0; fluid_audio_drivers[i].name != NULL; i++) {
|
||||
if (fluid_settings_str_equal(settings, "audio.driver", fluid_audio_drivers[i].name)) {
|
||||
FLUID_LOG(FLUID_DBG, "Using '%s' audio driver", fluid_audio_drivers[i].name);
|
||||
|
@ -346,7 +344,10 @@ new_fluid_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
}
|
||||
|
||||
fluid_audio_driver_get_names(allnames, sizeof(allnames), ", ");
|
||||
FLUID_LOG(FLUID_ERR, "Couldn't find the requested audio driver %s. Valid drivers are: %s.", name, allnames);
|
||||
fluid_settings_dupstr(settings, "audio.driver", &name); /* ++ alloc name */
|
||||
FLUID_LOG(FLUID_ERR, "Couldn't find the requested audio driver %s. Valid drivers are: %s.",
|
||||
name ? name : "NULL", allnames);
|
||||
if (name) FLUID_FREE (name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -370,8 +371,6 @@ new_fluid_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, voi
|
|||
fluid_audio_driver_t* driver = NULL;
|
||||
char* name;
|
||||
|
||||
fluid_settings_getstr(settings, "audio.driver", &name);
|
||||
|
||||
for (i = 0; fluid_audio_drivers[i].name != NULL; i++) {
|
||||
if (fluid_settings_str_equal(settings, "audio.driver", fluid_audio_drivers[i].name) &&
|
||||
(fluid_audio_drivers[i].new2 != NULL)) {
|
||||
|
@ -384,7 +383,10 @@ new_fluid_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, voi
|
|||
}
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_ERR, "Couldn't find the requested audio driver: %s", name);
|
||||
fluid_settings_dupstr(settings, "audio.driver", &name); /* ++ alloc name */
|
||||
FLUID_LOG(FLUID_ERR, "Couldn't find the requested audio driver: %s",
|
||||
name ? name : "NULL");
|
||||
if (name) FLUID_FREE (name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
fluid_alsa_audio_driver_t* dev;
|
||||
double sample_rate;
|
||||
int periods, period_size;
|
||||
char* device;
|
||||
char* device = NULL;
|
||||
pthread_attr_t attr;
|
||||
int sched = SCHED_FIFO;
|
||||
struct sched_param priority;
|
||||
|
@ -192,7 +192,7 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
fluid_settings_getint(settings, "audio.periods", &periods);
|
||||
fluid_settings_getint(settings, "audio.period-size", &period_size);
|
||||
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
|
||||
fluid_settings_getstr(settings, "audio.alsa.device", &device);
|
||||
fluid_settings_dupstr(settings, "audio.alsa.device", &device); /* ++ dup device name */
|
||||
|
||||
dev->data = data;
|
||||
dev->callback = func;
|
||||
|
@ -200,12 +200,15 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
dev->buffer_size = period_size;
|
||||
|
||||
/* Open the PCM device */
|
||||
if ((err = snd_pcm_open(&dev->pcm, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) != 0) {
|
||||
if ((err = snd_pcm_open(&dev->pcm, device ? device : "default",
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) != 0) {
|
||||
if (err == -EBUSY) {
|
||||
FLUID_LOG(FLUID_ERR, "The \"%s\" audio device is used by another application", device);
|
||||
FLUID_LOG(FLUID_ERR, "The \"%s\" audio device is used by another application",
|
||||
device ? device : "default");
|
||||
goto error_recovery;
|
||||
} else {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to open the \"%s\" audio device", device);
|
||||
FLUID_LOG(FLUID_ERR, "Failed to open the \"%s\" audio device",
|
||||
device ? device : "default");
|
||||
goto error_recovery;
|
||||
}
|
||||
}
|
||||
|
@ -362,9 +365,12 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
break;
|
||||
}
|
||||
|
||||
if (device) FLUID_FREE (device); /* -- free device name */
|
||||
|
||||
return (fluid_audio_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
if (device) FLUID_FREE (device); /* -- free device name */
|
||||
delete_fluid_alsa_audio_driver((fluid_audio_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -661,13 +667,11 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
|
|||
}
|
||||
|
||||
/* get the device name. if none is specified, use the default device. */
|
||||
fluid_settings_getstr(settings, "midi.alsa.device", &device);
|
||||
if (device == NULL) {
|
||||
device = "default";
|
||||
}
|
||||
fluid_settings_dupstr(settings, "midi.alsa.device", &device); /* ++ alloc device name */
|
||||
|
||||
/* open the hardware device. only use midi in. */
|
||||
if ((err = snd_rawmidi_open(&dev->rawmidi_in, NULL, device, SND_RAWMIDI_NONBLOCK)) < 0) {
|
||||
if ((err = snd_rawmidi_open(&dev->rawmidi_in, NULL, device ? device : "default",
|
||||
SND_RAWMIDI_NONBLOCK)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Error opening ALSA raw MIDI port");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
@ -746,9 +750,13 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (device) FLUID_FREE (device); /* -- free device name */
|
||||
|
||||
return (fluid_midi_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
if (device) FLUID_FREE (device); /* -- free device name */
|
||||
delete_fluid_alsa_rawmidi_driver((fluid_midi_driver_t*) dev);
|
||||
return NULL;
|
||||
|
||||
|
@ -897,12 +905,11 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
|||
struct sched_param priority;
|
||||
int count;
|
||||
struct pollfd *pfd = NULL;
|
||||
char * device = NULL;
|
||||
char * id;
|
||||
char * portname;
|
||||
char *device = NULL;
|
||||
char *id = NULL;
|
||||
char *portname = NULL;
|
||||
char full_id[64];
|
||||
char full_name[64];
|
||||
char id_pid[16];
|
||||
snd_seq_port_info_t *port_info = NULL;
|
||||
int midi_channels;
|
||||
|
||||
|
@ -924,24 +931,33 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
|||
|
||||
|
||||
/* get the device name. if none is specified, use the default device. */
|
||||
fluid_settings_getstr(settings, "midi.alsa_seq.device", &device);
|
||||
if (device == NULL) {
|
||||
device = "default";
|
||||
}
|
||||
if (fluid_settings_dupstr(settings, "midi.alsa_seq.device", &device) == 0) /* ++ alloc device name */
|
||||
goto error_recovery;
|
||||
|
||||
if (fluid_settings_dupstr(settings, "midi.alsa_seq.id", &id) == 0) /* ++ alloc id string */
|
||||
goto error_recovery;
|
||||
|
||||
fluid_settings_getstr(settings, "midi.alsa_seq.id", &id);
|
||||
if (id == NULL) {
|
||||
sprintf(id_pid, "%d", getpid());
|
||||
id = id_pid;
|
||||
id = FLUID_MALLOC (32);
|
||||
if (!id)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
sprintf(id, "%d", getpid());
|
||||
}
|
||||
|
||||
/* get the midi portname */
|
||||
fluid_settings_getstr(settings, "midi.portname", &portname);
|
||||
if (!strcmp(portname, ""))
|
||||
portname = NULL;
|
||||
fluid_settings_dupstr(settings, "midi.portname", &portname);
|
||||
if (portname && FLUID_STRLEN (portname) == 0)
|
||||
{
|
||||
FLUID_FREE (portname); /* -- free port name */
|
||||
portname = NULL;
|
||||
}
|
||||
|
||||
/* open the sequencer INPUT only */
|
||||
err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT, 0);
|
||||
err = snd_seq_open(&dev->seq_handle, device ? device : "default", SND_SEQ_OPEN_INPUT, 0);
|
||||
if (err < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Error opening ALSA sequencer");
|
||||
goto error_recovery;
|
||||
|
@ -1056,10 +1072,21 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (portname) FLUID_FREE (portname);
|
||||
if (id) FLUID_FREE (id);
|
||||
if (device) FLUID_FREE (device);
|
||||
|
||||
return (fluid_midi_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
|
||||
if (portname) FLUID_FREE (portname);
|
||||
if (id) FLUID_FREE (id);
|
||||
if (device) FLUID_FREE (device);
|
||||
|
||||
delete_fluid_alsa_seq_driver((fluid_midi_driver_t*) dev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ new_fluid_file_audio_driver(fluid_settings_t* settings,
|
|||
{
|
||||
fluid_file_audio_driver_t* dev;
|
||||
int err;
|
||||
char* filename;
|
||||
char* filename = NULL;
|
||||
int msec;
|
||||
|
||||
dev = FLUID_NEW(fluid_file_audio_driver_t);
|
||||
|
@ -89,19 +89,21 @@ new_fluid_file_audio_driver(fluid_settings_t* settings,
|
|||
dev->callback = (fluid_audio_func_t) fluid_synth_process;
|
||||
dev->samples = 0;
|
||||
|
||||
if (fluid_settings_getstr(settings, "audio.file.name", &filename) == 0) {
|
||||
if (fluid_settings_dupstr(settings, "audio.file.name", &filename) == 0) { /* ++ alloc filename */
|
||||
FLUID_LOG(FLUID_ERR, "No file name specified");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->renderer = new_fluid_file_renderer(synth, filename, dev->period_size);
|
||||
if (dev->renderer == NULL) {
|
||||
if (filename) FLUID_FREE (filename); /* -- free filename */
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (filename) FLUID_FREE (filename); /* -- free filename */
|
||||
|
||||
msec = (int) (0.5 + dev->period_size / dev->sample_rate * 1000.0);
|
||||
dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void*) dev, 1, 0);
|
||||
dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void*) dev, TRUE, FALSE, TRUE);
|
||||
if (dev->timer == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
|
||||
goto error_recovery;
|
||||
|
|
|
@ -23,11 +23,24 @@
|
|||
#include "fluid_synth.h"
|
||||
#include "fluid_sfont.h"
|
||||
|
||||
/* Field shift amounts for sfont_bank_prog bit field integer */
|
||||
#define PROG_SHIFTVAL 0
|
||||
#define BANK_SHIFTVAL 7
|
||||
#define SFONT_SHIFTVAL 21
|
||||
|
||||
/* Field mask values for sfont_bank_prog bit field integer */
|
||||
#define PROG_MASKVAL 0x0000007F
|
||||
#define BANK_MASKVAL 0x001FFF80
|
||||
#define BANKLSB_MASKVAL 0x00003F80
|
||||
#define BANKMSB_MASKVAL 0x001FC000
|
||||
#define SFONT_MASKVAL 0xFFE00000
|
||||
|
||||
|
||||
#define SETCC(_c,_n,_v) _c->cc[_n] = _v
|
||||
|
||||
/*
|
||||
* new_fluid_channel
|
||||
*/
|
||||
static void fluid_channel_init(fluid_channel_t* chan);
|
||||
|
||||
|
||||
fluid_channel_t*
|
||||
new_fluid_channel(fluid_synth_t* synth, int num)
|
||||
{
|
||||
|
@ -49,15 +62,20 @@ new_fluid_channel(fluid_synth_t* synth, int num)
|
|||
return chan;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
fluid_channel_init(fluid_channel_t* chan)
|
||||
{
|
||||
chan->prognum = 0;
|
||||
chan->banknum = (chan->channum == 9)? 128 : 0; /* ?? */
|
||||
chan->sfontnum = 0;
|
||||
fluid_preset_t *newpreset;
|
||||
int prognum, banknum;
|
||||
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
chan->preset = fluid_synth_find_preset(chan->synth, chan->banknum, chan->prognum);
|
||||
prognum = 0;
|
||||
banknum = (chan->channum == 9)? 128 : 0; /* ?? */
|
||||
|
||||
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
|
||||
| prognum << PROG_SHIFTVAL;
|
||||
|
||||
newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
|
||||
fluid_channel_set_preset(chan, newpreset);
|
||||
|
||||
chan->interp_method = FLUID_INTERP_DEFAULT;
|
||||
chan->tuning = NULL;
|
||||
|
@ -142,16 +160,7 @@ fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_channel_reset(fluid_channel_t* chan)
|
||||
{
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_channel
|
||||
*/
|
||||
/* Only called by delete_fluid_synth(), so no need to queue a preset free event */
|
||||
int
|
||||
delete_fluid_channel(fluid_channel_t* chan)
|
||||
{
|
||||
|
@ -160,275 +169,158 @@ delete_fluid_channel(fluid_channel_t* chan)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_set_preset
|
||||
*/
|
||||
void
|
||||
fluid_channel_reset(fluid_channel_t* chan)
|
||||
{
|
||||
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_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
|
||||
fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);
|
||||
fluid_event_queue_elem_t *event;
|
||||
|
||||
fluid_preset_notify (chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
|
||||
|
||||
if (chan->preset) /* Queue preset free (shouldn't free() in synth context) */
|
||||
{
|
||||
event = fluid_event_queue_get_inptr (chan->synth->return_queue);
|
||||
if (!event)
|
||||
{
|
||||
FLUID_LOG (FLUID_ERR, "Synth return event queue full");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
event->type = FLUID_EVENT_QUEUE_ELEM_FREE_PRESET;
|
||||
event->pval = chan->preset;
|
||||
fluid_event_queue_next_inptr (chan->synth->return_queue);
|
||||
}
|
||||
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
chan->preset = preset;
|
||||
|
||||
fluid_preset_notify (preset, FLUID_PRESET_SELECTED, chan->channum);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_preset
|
||||
*/
|
||||
fluid_preset_t*
|
||||
fluid_channel_get_preset(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->preset;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_banknum
|
||||
*/
|
||||
unsigned int
|
||||
fluid_channel_get_banknum(fluid_channel_t* chan)
|
||||
/* 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,
|
||||
int banknum, int prognum)
|
||||
{
|
||||
return chan->banknum;
|
||||
}
|
||||
int oldval, newval, oldmask;
|
||||
|
||||
/*
|
||||
* fluid_channel_set_prognum
|
||||
*/
|
||||
int
|
||||
fluid_channel_set_prognum(fluid_channel_t* chan, int prognum)
|
||||
{
|
||||
chan->prognum = prognum;
|
||||
return FLUID_OK;
|
||||
}
|
||||
newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)
|
||||
| ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)
|
||||
| ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);
|
||||
|
||||
/*
|
||||
* fluid_channel_get_prognum
|
||||
*/
|
||||
int
|
||||
fluid_channel_get_prognum(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->prognum;
|
||||
}
|
||||
oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)
|
||||
| ((banknum != -1) ? 0 : BANK_MASKVAL)
|
||||
| ((prognum != -1) ? 0 : PROG_MASKVAL);
|
||||
|
||||
/*
|
||||
* fluid_channel_set_banknum
|
||||
*/
|
||||
int
|
||||
fluid_channel_set_banknum(fluid_channel_t* chan, unsigned int banknum)
|
||||
{
|
||||
chan->banknum = banknum;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_cc
|
||||
*/
|
||||
int
|
||||
fluid_channel_cc(fluid_channel_t* chan, int num, int value)
|
||||
{
|
||||
chan->cc[num] = value;
|
||||
|
||||
switch (num) {
|
||||
|
||||
case SUSTAIN_SWITCH:
|
||||
{
|
||||
if (value < 64) {
|
||||
/* printf("** sustain off\n"); */
|
||||
fluid_synth_damp_voices(chan->synth, chan->channum);
|
||||
} else {
|
||||
/* printf("** sustain on\n"); */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BANK_SELECT_MSB:
|
||||
{
|
||||
fluid_channel_set_banknum(chan, (((unsigned int) value & 0x7F) << 7) +
|
||||
(chan->banknum & 0x7F));
|
||||
}
|
||||
break;
|
||||
|
||||
case BANK_SELECT_LSB:
|
||||
{
|
||||
/* FIXME: according to the Downloadable Sounds II specification,
|
||||
bit 31 should be set when we receive the message on channel
|
||||
10 (drum channel) */
|
||||
fluid_channel_set_banknum(chan, ((unsigned int) value & 0x7F)
|
||||
+ (chan->banknum & ~0x7F));
|
||||
}
|
||||
break;
|
||||
|
||||
case ALL_NOTES_OFF:
|
||||
fluid_synth_all_notes_off(chan->synth, chan->channum);
|
||||
break;
|
||||
|
||||
case ALL_SOUND_OFF:
|
||||
fluid_synth_all_sounds_off(chan->synth, chan->channum);
|
||||
break;
|
||||
|
||||
case ALL_CTRL_OFF:
|
||||
fluid_channel_init_ctrl(chan, 1);
|
||||
fluid_synth_modulate_voices_all(chan->synth, chan->channum);
|
||||
break;
|
||||
|
||||
case DATA_ENTRY_MSB:
|
||||
{
|
||||
int data = (value << 7) + chan->cc[DATA_ENTRY_LSB];
|
||||
|
||||
if (chan->nrpn_active) /* NRPN is active? */
|
||||
{
|
||||
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
|
||||
if ((chan->cc[NRPN_MSB] == 120) && (chan->cc[NRPN_LSB] < 100))
|
||||
{
|
||||
if (chan->nrpn_select < GEN_LAST)
|
||||
{
|
||||
float val = fluid_gen_scale_nrpn(chan->nrpn_select, data);
|
||||
fluid_synth_set_gen(chan->synth, chan->channum, chan->nrpn_select, val);
|
||||
}
|
||||
|
||||
chan->nrpn_select = 0; /* Reset to 0 */
|
||||
}
|
||||
}
|
||||
else if (chan->cc[RPN_MSB] == 0) /* RPN is active: MSB = 0? */
|
||||
{
|
||||
switch (chan->cc[RPN_LSB])
|
||||
{
|
||||
case RPN_PITCH_BEND_RANGE:
|
||||
fluid_channel_pitch_wheel_sens (chan, value); /* Set bend range in semitones */
|
||||
/* FIXME - Handle LSB? (Fine bend range in cents) */
|
||||
break;
|
||||
case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over 1 semitone (+/- 50 cents, 8192 = center) */
|
||||
fluid_synth_set_gen(chan->synth, chan->channum, GEN_FINETUNE,
|
||||
(data - 8192) / 8192.0 * 50.0);
|
||||
break;
|
||||
case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */
|
||||
fluid_synth_set_gen(chan->synth, chan->channum, GEN_COARSETUNE,
|
||||
value - 64);
|
||||
break;
|
||||
case RPN_TUNING_PROGRAM_CHANGE:
|
||||
break;
|
||||
case RPN_TUNING_BANK_SELECT:
|
||||
break;
|
||||
case RPN_MODULATION_DEPTH_RANGE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NRPN_MSB:
|
||||
chan->cc[NRPN_LSB] = 0;
|
||||
chan->nrpn_select = 0;
|
||||
chan->nrpn_active = 1;
|
||||
break;
|
||||
|
||||
case NRPN_LSB:
|
||||
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
|
||||
if (chan->cc[NRPN_MSB] == 120) {
|
||||
if (value == 100) {
|
||||
chan->nrpn_select += 100;
|
||||
} else if (value == 101) {
|
||||
chan->nrpn_select += 1000;
|
||||
} else if (value == 102) {
|
||||
chan->nrpn_select += 10000;
|
||||
} else if (value < 100) {
|
||||
chan->nrpn_select += value;
|
||||
}
|
||||
}
|
||||
|
||||
chan->nrpn_active = 1;
|
||||
break;
|
||||
|
||||
case RPN_MSB:
|
||||
case RPN_LSB:
|
||||
chan->nrpn_active = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 1, num);
|
||||
/* Loop until SoundFont, bank and program integer is atomically assigned */
|
||||
do
|
||||
{
|
||||
oldval = fluid_atomic_int_get (&chan->sfont_bank_prog);
|
||||
newval = (newval & ~oldmask) | (oldval & oldmask);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
while (newval != oldval
|
||||
&& !fluid_atomic_int_compare_and_exchange (&chan->sfont_bank_prog,
|
||||
oldval, newval));
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_cc
|
||||
*/
|
||||
/* Set bank LSB 7 bits */
|
||||
void
|
||||
fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb)
|
||||
{
|
||||
int oldval, newval;
|
||||
|
||||
/* Loop until bank LSB is atomically assigned */
|
||||
do
|
||||
{
|
||||
oldval = fluid_atomic_int_get (&chan->sfont_bank_prog);
|
||||
newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);
|
||||
}
|
||||
while (newval != oldval
|
||||
&& !fluid_atomic_int_compare_and_exchange (&chan->sfont_bank_prog,
|
||||
oldval, newval));
|
||||
}
|
||||
|
||||
/* Set bank MSB 7 bits */
|
||||
void
|
||||
fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb)
|
||||
{
|
||||
int oldval, newval;
|
||||
|
||||
/* Loop until bank MSB is atomically assigned */
|
||||
do
|
||||
{
|
||||
oldval = fluid_atomic_int_get (&chan->sfont_bank_prog);
|
||||
newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
|
||||
}
|
||||
while (newval != oldval
|
||||
&& !fluid_atomic_int_compare_and_exchange (&chan->sfont_bank_prog,
|
||||
oldval, 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,
|
||||
int *bank, int *prog)
|
||||
{
|
||||
int sfont_bank_prog;
|
||||
|
||||
sfont_bank_prog = fluid_atomic_int_get (&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;
|
||||
}
|
||||
|
||||
/* Set MIDI custom controller value for a channel */
|
||||
void
|
||||
fluid_channel_set_cc(fluid_channel_t* chan, int num, int val)
|
||||
{
|
||||
if (num >= 0 && num < 128)
|
||||
fluid_atomic_int_set (&chan->cc[num], val);
|
||||
}
|
||||
|
||||
/* Get MIDI custom controller value for a channel */
|
||||
int
|
||||
fluid_channel_get_cc(fluid_channel_t* chan, int num)
|
||||
{
|
||||
return ((num >= 0) && (num < 128))? chan->cc[num] : 0;
|
||||
return ((num >= 0) && (num < 128)) ? fluid_atomic_int_get (&chan->cc[num]) : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_pressure
|
||||
*/
|
||||
int
|
||||
fluid_channel_pressure(fluid_channel_t* chan, int val)
|
||||
{
|
||||
chan->channel_pressure = val;
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_CHANNELPRESSURE);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_pitch_bend
|
||||
*/
|
||||
int
|
||||
fluid_channel_pitch_bend(fluid_channel_t* chan, int val)
|
||||
{
|
||||
chan->pitch_bend = val;
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_PITCHWHEEL);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_pitch_wheel_sens
|
||||
*/
|
||||
int
|
||||
fluid_channel_pitch_wheel_sens(fluid_channel_t* chan, int val)
|
||||
{
|
||||
chan->pitch_wheel_sensitivity = val;
|
||||
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_PITCHWHEELSENS);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_channel_get_num
|
||||
*/
|
||||
/* Get MIDI channel number */
|
||||
int
|
||||
fluid_channel_get_num(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->channum;
|
||||
return chan->channum; /* Set only once on channel init */
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
/*
|
||||
* Sets the index of the interpolation method used on this channel,
|
||||
* as in fluid_interp in fluidsynth.h
|
||||
*/
|
||||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method)
|
||||
{
|
||||
chan->interp_method = new_method;
|
||||
fluid_atomic_int_set (&chan->interp_method, new_method);
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
/*
|
||||
* Returns the index of the interpolation method used on this channel,
|
||||
* as in fluid_interp in fluidsynth.h
|
||||
*/
|
||||
int fluid_channel_get_interp_method(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->interp_method;
|
||||
}
|
||||
|
||||
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan)
|
||||
{
|
||||
return chan->sfontnum;
|
||||
}
|
||||
|
||||
int fluid_channel_set_sfontnum(fluid_channel_t* chan, unsigned int sfontnum)
|
||||
{
|
||||
chan->sfontnum = sfontnum;
|
||||
return FLUID_OK;
|
||||
return fluid_atomic_int_get (&chan->interp_method);
|
||||
}
|
||||
|
|
|
@ -27,36 +27,58 @@
|
|||
|
||||
/*
|
||||
* fluid_channel_t
|
||||
*
|
||||
* Mutual exclusion notes:
|
||||
*
|
||||
* Set once on init:
|
||||
* channum
|
||||
* synth
|
||||
*
|
||||
* Synthesis thread context only:
|
||||
* preset
|
||||
* key_pressure
|
||||
* tuning
|
||||
* nrpn_select
|
||||
* nrpn_active
|
||||
* gen[]
|
||||
* gen_abs[]
|
||||
*
|
||||
* Uses atomic operations:
|
||||
* sfont_bank_prog
|
||||
* channel_pressure
|
||||
* pitch_bend
|
||||
* pitch_wheel_sensitivity
|
||||
* cc[]
|
||||
* interp_method
|
||||
*/
|
||||
struct _fluid_channel_t
|
||||
{
|
||||
int channum;
|
||||
unsigned int sfontnum;
|
||||
unsigned int banknum;
|
||||
unsigned int prognum;
|
||||
fluid_preset_t* preset;
|
||||
fluid_synth_t* synth;
|
||||
short key_pressure;
|
||||
short channel_pressure;
|
||||
short pitch_bend;
|
||||
short pitch_wheel_sensitivity;
|
||||
fluid_mutex_t mutex; /* Lock for thread sensitive parameters */
|
||||
|
||||
/* controller values */
|
||||
short cc[128];
|
||||
fluid_synth_t* synth; /**> Parent synthesizer instance */
|
||||
int channum; /**> MIDI channel number */
|
||||
|
||||
int interp_method;
|
||||
int sfont_bank_prog; /**> SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
|
||||
fluid_preset_t* preset; /**> Selected preset */
|
||||
|
||||
/* the micro-tuning */
|
||||
fluid_tuning_t* tuning;
|
||||
int key_pressure; /**> MIDI key pressure */
|
||||
int channel_pressure; /**> MIDI channel pressure */
|
||||
int pitch_bend; /**> Current pitch bend value */
|
||||
int pitch_wheel_sensitivity; /**> Current pitch wheel sensitivity */
|
||||
|
||||
int cc[128]; /**> MIDI controller values */
|
||||
|
||||
int interp_method; /**> Interpolation method (enum fluid_interp) */
|
||||
fluid_tuning_t* tuning; /**> Micro tuning */
|
||||
|
||||
/* NRPN system */
|
||||
short nrpn_select;
|
||||
short nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
||||
int nrpn_select; /* Generator ID of SoundFont NRPN message */
|
||||
int nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
||||
|
||||
/* The values of the generators, set by NRPN messages, or by
|
||||
* fluid_synth_set_gen(), are cached in the channel so they can be
|
||||
* applied to future notes. They are copied to a voice's generators
|
||||
* in fluid_voice_init(), wihich calls fluid_gen_init(). */
|
||||
* 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
|
||||
|
@ -73,22 +95,18 @@ struct _fluid_channel_t
|
|||
};
|
||||
|
||||
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
|
||||
int delete_fluid_channel(fluid_channel_t* chan);
|
||||
void fluid_channel_init(fluid_channel_t* chan);
|
||||
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);
|
||||
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan);
|
||||
int fluid_channel_set_sfontnum(fluid_channel_t* chan, unsigned int sfont);
|
||||
unsigned int fluid_channel_get_banknum(fluid_channel_t* chan);
|
||||
int fluid_channel_set_banknum(fluid_channel_t* chan, unsigned int bank);
|
||||
int fluid_channel_set_prognum(fluid_channel_t* chan, int prognum);
|
||||
int fluid_channel_get_prognum(fluid_channel_t* chan);
|
||||
int fluid_channel_cc(fluid_channel_t* chan, int ctrl, int val);
|
||||
int fluid_channel_pressure(fluid_channel_t* chan, int val);
|
||||
int fluid_channel_pitch_bend(fluid_channel_t* chan, int val);
|
||||
int fluid_channel_pitch_wheel_sens(fluid_channel_t* chan, int val);
|
||||
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,
|
||||
int *bank, int *prog);
|
||||
void fluid_channel_set_cc(fluid_channel_t* chan, int num, int val);
|
||||
int fluid_channel_get_cc(fluid_channel_t* chan, int num);
|
||||
int fluid_channel_get_num(fluid_channel_t* chan);
|
||||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method);
|
||||
|
|
|
@ -134,8 +134,10 @@ struct _fluid_chorus_t {
|
|||
fluid_real_t sinc_table[INTERPOLATION_SAMPLES][INTERPOLATION_SUBSAMPLES];
|
||||
};
|
||||
|
||||
void fluid_chorus_triangle(int *buf, int len, int depth);
|
||||
void fluid_chorus_sine(int *buf, int len, int depth);
|
||||
static void fluid_chorus_update(fluid_chorus_t* chorus);
|
||||
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*
|
||||
new_fluid_chorus(fluid_real_t sample_rate)
|
||||
|
@ -202,110 +204,6 @@ new_fluid_chorus(fluid_real_t sample_rate)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
fluid_chorus_init(fluid_chorus_t* chorus)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SAMPLES; i++) {
|
||||
chorus->chorusbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
/* initialize the chorus with the default settings */
|
||||
fluid_chorus_set_nr(chorus, FLUID_CHORUS_DEFAULT_N);
|
||||
fluid_chorus_set_level(chorus, FLUID_CHORUS_DEFAULT_LEVEL);
|
||||
fluid_chorus_set_speed_Hz(chorus, FLUID_CHORUS_DEFAULT_SPEED);
|
||||
fluid_chorus_set_depth_ms(chorus, FLUID_CHORUS_DEFAULT_DEPTH);
|
||||
fluid_chorus_set_type(chorus, FLUID_CHORUS_MOD_SINE);
|
||||
|
||||
return fluid_chorus_update(chorus);
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* Sets the number of stages.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Range checking is performed there.*/
|
||||
void fluid_chorus_set_nr(fluid_chorus_t* chorus, int nr)
|
||||
{
|
||||
chorus->new_number_blocks = nr;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
int fluid_chorus_get_nr(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->number_blocks;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the mixing level of the signal from each delay line (linear).
|
||||
* Requires calling fluid_chorus_update afterwards.*/
|
||||
void fluid_chorus_set_level(fluid_chorus_t* chorus, fluid_real_t level)
|
||||
{
|
||||
chorus->new_level = level;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
fluid_real_t fluid_chorus_get_level(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->level;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the modulation frequency.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Range checking is performed there.*/
|
||||
void fluid_chorus_set_speed_Hz(fluid_chorus_t* chorus, fluid_real_t speed_Hz)
|
||||
{
|
||||
chorus->new_speed_Hz = speed_Hz;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
fluid_real_t fluid_chorus_get_speed_Hz(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->speed_Hz;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the modulation depth in ms.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Range checking is performed there.*/
|
||||
void fluid_chorus_set_depth_ms(fluid_chorus_t* chorus, fluid_real_t depth_ms)
|
||||
{
|
||||
chorus->new_depth_ms=depth_ms;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
fluid_real_t fluid_chorus_get_depth_ms(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->depth_ms;
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* Sets the type of the modulation waveform.
|
||||
* Requires call to fluid_chorus_update afterwards.
|
||||
* Check for meaningful values is performed there.*/
|
||||
void fluid_chorus_set_type(fluid_chorus_t* chorus, int type)
|
||||
{
|
||||
chorus->new_type=type;
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* API function, read the current state of the chorus
|
||||
*/
|
||||
int fluid_chorus_get_type(fluid_chorus_t* chorus)
|
||||
{
|
||||
return chorus->type;
|
||||
};
|
||||
|
||||
void
|
||||
delete_fluid_chorus(fluid_chorus_t* chorus)
|
||||
{
|
||||
|
@ -324,11 +222,56 @@ delete_fluid_chorus(fluid_chorus_t* chorus)
|
|||
FLUID_FREE(chorus);
|
||||
}
|
||||
|
||||
int
|
||||
fluid_chorus_init(fluid_chorus_t* chorus)
|
||||
{
|
||||
int i;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_chorus_reset(fluid_chorus_t* chorus)
|
||||
{
|
||||
fluid_chorus_init(chorus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more chorus parameters.
|
||||
* @param chorus Chorus instance
|
||||
* @param set Flags indicating which chorus parameters to set (#fluid_chorus_set_t)
|
||||
* @param nr Chorus voice count (0-99, CPU time consumption proportional to
|
||||
* this value)
|
||||
* @param level Chorus level (0.0-1.0)
|
||||
* @param speed Chorus speed in Hz (0.29-5.0)
|
||||
* @param depth_ms Chorus depth (max value depends on synth sample rate,
|
||||
* 0.0-21.0 is safe for sample rate values up to 96KHz)
|
||||
* @param type Chorus waveform type (#fluid_chorus_mod)
|
||||
*/
|
||||
void
|
||||
fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
|
||||
float speed, float depth_ms, int type)
|
||||
{
|
||||
if (set & FLUID_CHORUS_SET_NR) chorus->new_number_blocks = nr;
|
||||
if (set & FLUID_CHORUS_SET_LEVEL) chorus->new_level = level;
|
||||
if (set & FLUID_CHORUS_SET_SPEED) chorus->new_speed_Hz = speed;
|
||||
if (set & FLUID_CHORUS_SET_DEPTH) chorus->new_depth_ms = depth_ms;
|
||||
if (set & FLUID_CHORUS_SET_TYPE) chorus->new_type = type;
|
||||
|
||||
return fluid_chorus_update (chorus);
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
* Calculates the internal chorus parameters using the settings from
|
||||
* fluid_chorus_set_xxx. */
|
||||
int
|
||||
* Calculates the internal chorus parameters. */
|
||||
static void
|
||||
fluid_chorus_update(fluid_chorus_t* chorus)
|
||||
{
|
||||
int i;
|
||||
|
@ -408,18 +351,6 @@ fluid_chorus_update(fluid_chorus_t* chorus)
|
|||
chorus->level = chorus->new_level;
|
||||
chorus->speed_Hz = chorus->new_speed_Hz;
|
||||
chorus->number_blocks = chorus->new_number_blocks;
|
||||
return FLUID_OK;
|
||||
|
||||
/* failure: */
|
||||
/* Note: This lives on the assumption, that the last chorus values were correct.
|
||||
* If not, this will loop forever and a day. */
|
||||
/* fluid_log(FLUID_WARN, "chorus: Restoring last good settings"); */
|
||||
/* chorus->new_type = chorus->type; */
|
||||
/* chorus->new_depth_ms = chorus->depth_ms; */
|
||||
/* chorus->new_level = chorus->level; */
|
||||
/* chorus->new_speed_Hz = chorus->speed_Hz; */
|
||||
/* chorus->new_number_blocks = chorus->number_blocks; */
|
||||
/* return FLUID_FAILED; */
|
||||
}
|
||||
|
||||
|
||||
|
@ -567,7 +498,8 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
|||
* a couple of times here, the resulting (current position in
|
||||
* buffer)-(waveform sample) will always be positive.
|
||||
*/
|
||||
void fluid_chorus_sine(int *buf, int len, int depth)
|
||||
static void
|
||||
fluid_chorus_sine(int *buf, int len, int depth)
|
||||
{
|
||||
int i;
|
||||
double val;
|
||||
|
@ -584,7 +516,8 @@ void fluid_chorus_sine(int *buf, int len, int depth)
|
|||
* Calculates a modulation waveform (triangle)
|
||||
* See fluid_chorus_sine for comments.
|
||||
*/
|
||||
void fluid_chorus_triangle(int *buf, int len, int depth)
|
||||
static void
|
||||
fluid_chorus_triangle(int *buf, int len, int depth)
|
||||
{
|
||||
int i=0;
|
||||
int ii=len-1;
|
||||
|
@ -598,9 +531,3 @@ void fluid_chorus_triangle(int *buf, int len, int depth)
|
|||
buf[ii--] = (int) val2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_chorus_reset(fluid_chorus_t* chorus)
|
||||
{
|
||||
fluid_chorus_init(chorus);
|
||||
}
|
||||
|
|
|
@ -27,30 +27,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;
|
||||
|
||||
/** Value for fluid_chorus_set() which sets all chorus parameters. */
|
||||
#define FLUID_CHORUS_SET_ALL 0x1F
|
||||
|
||||
/*
|
||||
* chorus
|
||||
*/
|
||||
fluid_chorus_t* new_fluid_chorus(fluid_real_t sample_rate);
|
||||
void delete_fluid_chorus(fluid_chorus_t* chorus);
|
||||
int fluid_chorus_init(fluid_chorus_t* chorus);
|
||||
void fluid_chorus_reset(fluid_chorus_t* chorus);
|
||||
|
||||
void fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
|
||||
float speed, float depth_ms, int type);
|
||||
|
||||
void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
||||
int fluid_chorus_init(fluid_chorus_t* chorus);
|
||||
void fluid_chorus_reset(fluid_chorus_t* chorus);
|
||||
|
||||
void fluid_chorus_set_nr(fluid_chorus_t* chorus, int nr);
|
||||
void fluid_chorus_set_level(fluid_chorus_t* chorus, fluid_real_t level);
|
||||
void fluid_chorus_set_speed_Hz(fluid_chorus_t* chorus, fluid_real_t speed_Hz);
|
||||
void fluid_chorus_set_depth_ms(fluid_chorus_t* chorus, fluid_real_t depth_ms);
|
||||
void fluid_chorus_set_type(fluid_chorus_t* chorus, int type);
|
||||
int fluid_chorus_update(fluid_chorus_t* chorus);
|
||||
int fluid_chorus_get_nr(fluid_chorus_t* chorus);
|
||||
fluid_real_t fluid_chorus_get_level(fluid_chorus_t* chorus);
|
||||
fluid_real_t fluid_chorus_get_speed_Hz(fluid_chorus_t* chorus);
|
||||
fluid_real_t fluid_chorus_get_depth_ms(fluid_chorus_t* chorus);
|
||||
int fluid_chorus_get_type(fluid_chorus_t* chorus);
|
||||
|
||||
|
||||
#endif /* _FLUID_CHORUS_H */
|
||||
|
|
|
@ -260,19 +260,18 @@ void delete_fluid_shell(fluid_shell_t* shell)
|
|||
int fluid_shell_run(fluid_shell_t* shell)
|
||||
{
|
||||
char workline[FLUID_WORKLINELENGTH];
|
||||
char* prompt = "";
|
||||
char* prompt = NULL;
|
||||
int cont = 1;
|
||||
int errors = 0;
|
||||
int n;
|
||||
|
||||
if (shell->settings) {
|
||||
fluid_settings_getstr(shell->settings, "shell.prompt", &prompt);
|
||||
}
|
||||
if (shell->settings)
|
||||
fluid_settings_dupstr(shell->settings, "shell.prompt", &prompt); /* ++ alloc prompt */
|
||||
|
||||
/* handle user input */
|
||||
while (cont) {
|
||||
|
||||
n = fluid_istream_readline(shell->in, prompt, workline, FLUID_WORKLINELENGTH);
|
||||
n = fluid_istream_readline(shell->in, prompt ? prompt : "", workline, FLUID_WORKLINELENGTH);
|
||||
|
||||
if (n < 0) {
|
||||
break;
|
||||
|
@ -305,6 +304,8 @@ int fluid_shell_run(fluid_shell_t* shell)
|
|||
}
|
||||
}
|
||||
|
||||
if (prompt) FLUID_FREE (prompt); /* -- free prompt */
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
@ -684,7 +685,8 @@ fluid_handle_reverbsetroomsize(fluid_synth_t* synth, int ac, char** av, fluid_os
|
|||
fluid_ostream_printf(out, "rev_setroomsize: Room size too big!\n");
|
||||
return -1;
|
||||
}
|
||||
fluid_revmodel_setroomsize(synth->reverb, room_size);
|
||||
fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_ROOMSIZE,
|
||||
room_size, 0.0, 0.0, 0.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -704,7 +706,8 @@ fluid_handle_reverbsetdamp(fluid_synth_t* synth, int ac, char** av, fluid_ostrea
|
|||
fluid_ostream_printf(out, "rev_setdamp: damp must be between 0 and 1!\n");
|
||||
return -1;
|
||||
}
|
||||
fluid_revmodel_setdamp(synth->reverb, damp);
|
||||
fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_DAMPING,
|
||||
0.0, damp, 0.0, 0.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -724,7 +727,8 @@ fluid_handle_reverbsetwidth(fluid_synth_t* synth, int ac, char** av, fluid_ostre
|
|||
fluid_ostream_printf(out, "rev_setroomsize: Too wide! (0..100)\n");
|
||||
return 0;
|
||||
}
|
||||
fluid_revmodel_setwidth(synth->reverb, width);
|
||||
fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_WIDTH,
|
||||
0.0, 0.0, width, 0.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -744,7 +748,8 @@ fluid_handle_reverbsetlevel(fluid_synth_t* synth, int ac, char** av, fluid_ostre
|
|||
fluid_ostream_printf(out, "rev_setlevel: Value too high! (Value of 10 =+20 dB)\n");
|
||||
return 0;
|
||||
}
|
||||
fluid_revmodel_setlevel(synth->reverb, level);
|
||||
fluid_synth_set_reverb_full (synth, FLUID_REVMODEL_SET_LEVEL,
|
||||
0.0, 0.0, 0.0, level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -783,8 +788,7 @@ fluid_handle_chorusnr(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t o
|
|||
return -1;
|
||||
}
|
||||
nr = atoi(av[0]);
|
||||
fluid_chorus_set_nr(synth->chorus, nr);
|
||||
return fluid_chorus_update(synth->chorus);
|
||||
return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_NR, nr, 0.0, 0.0, 0.0, 0);
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
|
@ -798,9 +802,7 @@ fluid_handle_choruslevel(fluid_synth_t* synth, int ac, char** av, fluid_ostream_
|
|||
return -1;
|
||||
}
|
||||
level = atof(av[0]);
|
||||
fluid_chorus_set_level(synth->chorus, level);
|
||||
return fluid_chorus_update(synth->chorus);
|
||||
|
||||
return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_LEVEL, 0, level, 0.0, 0.0, 0);
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
|
@ -814,8 +816,7 @@ fluid_handle_chorusspeed(fluid_synth_t* synth, int ac, char** av, fluid_ostream_
|
|||
return -1;
|
||||
}
|
||||
speed = atof(av[0]);
|
||||
fluid_chorus_set_speed_Hz(synth->chorus, speed);
|
||||
return fluid_chorus_update(synth->chorus);
|
||||
return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_SPEED, 0, 0.0, speed, 0.0, 0);
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
|
@ -829,8 +830,7 @@ fluid_handle_chorusdepth(fluid_synth_t* synth, int ac, char** av, fluid_ostream_
|
|||
return -1;
|
||||
}
|
||||
depth = atof(av[0]);
|
||||
fluid_chorus_set_depth_ms(synth->chorus, depth);
|
||||
return fluid_chorus_update(synth->chorus);
|
||||
return fluid_synth_set_chorus_full (synth, FLUID_CHORUS_SET_DEPTH, 0, 0.0, 0.0, depth, 0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1238,8 +1238,9 @@ fluid_handle_get(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
|
|||
|
||||
case FLUID_STR_TYPE: {
|
||||
char* s;
|
||||
fluid_synth_getstr(synth, av[0], &s);
|
||||
fluid_ostream_printf(out, "%s", s);
|
||||
fluid_synth_dupstr(synth, av[0], &s); /* ++ alloc string */
|
||||
fluid_ostream_printf(out, "%s", s ? s : "NULL");
|
||||
if (s) FLUID_FREE (s); /* -- free string */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1295,8 +1296,9 @@ static void fluid_handle_settings_iter2(void* data, char* name, int type)
|
|||
|
||||
case FLUID_STR_TYPE: {
|
||||
char* s;
|
||||
fluid_synth_getstr(d->synth, name, &s);
|
||||
fluid_ostream_printf(d->out, "%s\n", s);
|
||||
fluid_synth_dupstr(d->synth, name, &s); /* ++ alloc string */
|
||||
fluid_ostream_printf(d->out, "%s\n", s ? s : "NULL");
|
||||
if (s) FLUID_FREE (s); /* -- free string */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1384,13 +1386,15 @@ fluid_handle_info(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
|
|||
|
||||
case FLUID_STR_TYPE: {
|
||||
char *s;
|
||||
fluid_settings_getstr(settings, av[0], &s);
|
||||
fluid_settings_dupstr(settings, av[0], &s); /* ++ alloc string */
|
||||
fluid_ostream_printf(out, "%s:\n", av[0]);
|
||||
fluid_ostream_printf(out, "Type: string\n");
|
||||
fluid_ostream_printf(out, "Value: %s\n", s);
|
||||
fluid_ostream_printf(out, "Value: %s\n", s ? s : "NULL");
|
||||
fluid_ostream_printf(out, "Default value: %s\n",
|
||||
fluid_settings_getstr_default(settings, av[0]));
|
||||
|
||||
if (s) FLUID_FREE (s);
|
||||
|
||||
data.out = out;
|
||||
data.first = 1;
|
||||
fluid_ostream_printf(out, "Options: ");
|
||||
|
@ -1567,9 +1571,10 @@ void delete_fluid_cmd(fluid_cmd_t* cmd)
|
|||
* Command handler
|
||||
*/
|
||||
|
||||
void fluid_cmd_handler_delete(void* value, int type)
|
||||
static void
|
||||
fluid_cmd_handler_destroy_hash_value (void *value)
|
||||
{
|
||||
delete_fluid_cmd((fluid_cmd_t*) value);
|
||||
delete_fluid_cmd ((fluid_cmd_t *)value);
|
||||
}
|
||||
|
||||
fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth)
|
||||
|
@ -1582,7 +1587,8 @@ fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth)
|
|||
"source filename Load a file and parse every line as a command"
|
||||
};
|
||||
|
||||
handler = new_fluid_hashtable(fluid_cmd_handler_delete);
|
||||
handler = new_fluid_hashtable_full (fluid_str_hash, fluid_str_equal,
|
||||
NULL, fluid_cmd_handler_destroy_hash_value);
|
||||
if (handler == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1603,13 +1609,13 @@ fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth)
|
|||
|
||||
void delete_fluid_cmd_handler(fluid_cmd_handler_t* handler)
|
||||
{
|
||||
delete_fluid_hashtable(handler);
|
||||
delete_fluid_hashtable (handler);
|
||||
}
|
||||
|
||||
int fluid_cmd_handler_register(fluid_cmd_handler_t* handler, fluid_cmd_t* cmd)
|
||||
{
|
||||
fluid_cmd_t* copy = fluid_cmd_copy(cmd);
|
||||
fluid_hashtable_insert(handler, copy->name, copy, 0);
|
||||
fluid_hashtable_insert(handler, copy->name, copy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1620,17 +1626,15 @@ int fluid_cmd_handler_unregister(fluid_cmd_handler_t* handler, char* cmd)
|
|||
|
||||
int fluid_cmd_handler_handle(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out)
|
||||
{
|
||||
void *vp; /* use a void pointer to avoid GCC "type-punned pointer" warning */
|
||||
fluid_cmd_t* cmd;
|
||||
|
||||
if (fluid_hashtable_lookup(handler, av[0], &vp, NULL)
|
||||
&& ((fluid_cmd_t *)vp)->handler) {
|
||||
cmd = vp;
|
||||
cmd = fluid_hashtable_lookup(handler, av[0]);
|
||||
|
||||
if (cmd && cmd->handler)
|
||||
return (*cmd->handler)(cmd->data, ac - 1, av + 1, out);
|
||||
} else {
|
||||
fluid_ostream_printf(out, "unknown command: %s (try help)\n", av[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fluid_ostream_printf(out, "unknown command: %s (try help)\n", av[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -91,8 +91,8 @@ new_fluid_coremidi_driver(fluid_settings_t* settings, handle_midi_event_func_t h
|
|||
goto error_recovery;
|
||||
}
|
||||
|
||||
fluid_settings_getstr(settings, "midi.coremidi.id", &id);
|
||||
if (FLUID_STRCMP(id, "pid") == 0)
|
||||
fluid_settings_dupstr(settings, "midi.coremidi.id", &id); /* ++ alloc id string */
|
||||
if (!id || FLUID_STRCMP(id, "pid") == 0)
|
||||
str_clientname = CFStringCreateWithFormat(NULL, NULL,
|
||||
CFSTR("FluidSynth %qi"),
|
||||
(long long) getpid());
|
||||
|
@ -100,8 +100,10 @@ new_fluid_coremidi_driver(fluid_settings_t* settings, handle_midi_event_func_t h
|
|||
str_clientname = CFStringCreateWithFormat(NULL, NULL,
|
||||
CFSTR("FluidSynth %s"), id);
|
||||
|
||||
fluid_settings_getstr(settings, "midi.portname", &portname);
|
||||
if (strlen(portname) == 0)
|
||||
if (id) FLUID_FREE (id); /* -- free id string */
|
||||
|
||||
fluid_settings_dupstr(settings, "midi.portname", &portname); /* ++ alloc port name */
|
||||
if (!portname || strlen(portname) == 0)
|
||||
str_portname = CFStringCreateWithFormat(NULL, NULL,
|
||||
CFSTR("FluidSynth virtual port %qi"),
|
||||
(long long) getpid());
|
||||
|
@ -109,6 +111,8 @@ new_fluid_coremidi_driver(fluid_settings_t* settings, handle_midi_event_func_t h
|
|||
str_portname = CFStringCreateWithCString(NULL, portname,
|
||||
kCFStringEncodingASCII);
|
||||
|
||||
if (portname) FLUID_FREE (portname); /* -- free port name */
|
||||
|
||||
OSStatus result = MIDIClientCreate( str_clientname, NULL, NULL, &client );
|
||||
if ( result != noErr ) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to create the MIDI input client");
|
||||
|
|
|
@ -169,11 +169,14 @@ new_fluid_dsound_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
|
||||
devsel.devGUID = NULL;
|
||||
/* get the selected device name. if none is specified, use NULL for the default device. */
|
||||
if(fluid_settings_getstr(settings, "audio.dsound.device", &devsel.devname)) {
|
||||
if(fluid_settings_dupstr(settings, "audio.dsound.device", &devsel.devname) /* ++ alloc device name */
|
||||
&& devsel.devname && strlen (devsel.devname) > 0) {
|
||||
/* look for the GUID of the selected device */
|
||||
DirectSoundEnumerate((LPDSENUMCALLBACK) fluid_dsound_enum_callback2, (void *)&devsel);
|
||||
DirectSoundEnumerate((LPDSENUMCALLBACK) fluid_dsound_enum_callback2, (void *)&devsel);
|
||||
}
|
||||
|
||||
|
||||
if (devsel.devname) FLUID_FREE (devsel.devname); /* -- free device name */
|
||||
|
||||
/* open DirectSound */
|
||||
hr = DirectSoundCreate(devsel.devGUID, &dev->direct_sound, NULL);
|
||||
if (hr != DS_OK) {
|
||||
|
|
155
fluidsynth/src/fluid_event_queue.c
Normal file
155
fluidsynth/src/fluid_event_queue.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Josh Green <josh@resonance.org>
|
||||
* 2009-05-28
|
||||
*/
|
||||
|
||||
#include "fluid_event_queue.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
|
||||
/**
|
||||
* Create a lock free queue with a fixed maximum count and size of elements.
|
||||
* @param count Count of elements in queue (fixed max number of queued elements)
|
||||
* @return New lock free queue or NULL if out of memory (error message logged)
|
||||
*
|
||||
* Lockless FIFO queues don't use any locking mechanisms and can therefore be
|
||||
* advantageous in certain situations, such as passing data between a lower
|
||||
* priority thread and a higher "real time" thread, without potential lock
|
||||
* contention which could stall the high priority thread. Note that there may
|
||||
* only be one producer thread and one consumer thread.
|
||||
*/
|
||||
fluid_event_queue_t *
|
||||
fluid_event_queue_new (int count)
|
||||
{
|
||||
fluid_event_queue_t *queue;
|
||||
|
||||
fluid_return_val_if_fail (count > 0, NULL);
|
||||
|
||||
queue = FLUID_NEW (fluid_event_queue_t);
|
||||
|
||||
if (!queue)
|
||||
{
|
||||
FLUID_LOG (FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queue->array = FLUID_ARRAY (fluid_event_queue_elem_t, count);
|
||||
|
||||
if (!queue->array)
|
||||
{
|
||||
FLUID_FREE (queue);
|
||||
FLUID_LOG (FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Clear array, in case dynamic pointer reclaiming is being done */
|
||||
FLUID_MEMSET (queue->array, 0, sizeof (fluid_event_queue_elem_t) * count);
|
||||
|
||||
queue->totalcount = count;
|
||||
queue->count = 0;
|
||||
queue->in = 0;
|
||||
queue->out = 0;
|
||||
|
||||
return (queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an event queue.
|
||||
* @param queue Lockless queue instance
|
||||
*
|
||||
* Care must be taken when freeing a queue, to ensure that the consumer and
|
||||
* producer threads will no longer access it.
|
||||
*/
|
||||
void
|
||||
fluid_event_queue_free (fluid_event_queue_t *queue)
|
||||
{
|
||||
FLUID_FREE (queue->array);
|
||||
FLUID_FREE (queue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get pointer to next input array element in queue.
|
||||
* @param queue Lockless queue instance
|
||||
* @return Pointer to array element in queue to store data to or NULL if queue is full
|
||||
*
|
||||
* This function along with fluid_queue_next_inptr() form a queue "push"
|
||||
* operation and is split into 2 functions to avoid an element copy. Note that
|
||||
* the returned array element pointer may contain the data of a previous element
|
||||
* if the queue has wrapped around. This can be used to reclaim pointers to
|
||||
* allocated memory, etc.
|
||||
*/
|
||||
FLUID_INLINE fluid_event_queue_elem_t *
|
||||
fluid_event_queue_get_inptr (fluid_event_queue_t *queue)
|
||||
{
|
||||
return fluid_atomic_int_get (&queue->count) == queue->totalcount ? NULL
|
||||
: queue->array + queue->in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the input queue index to complete a "push" operation.
|
||||
* @param queue Lockless queue instance
|
||||
*
|
||||
* This function along with fluid_queue_get_inptr() form a queue "push"
|
||||
* operation and is split into 2 functions to avoid element copy.
|
||||
*/
|
||||
FLUID_INLINE void
|
||||
fluid_event_queue_next_inptr (fluid_event_queue_t *queue)
|
||||
{
|
||||
fluid_atomic_int_inc (&queue->count);
|
||||
|
||||
if (++queue->in == queue->totalcount)
|
||||
queue->in = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pointer to next output array element in queue.
|
||||
* @param queue Lockless queue instance
|
||||
* @return Pointer to array element data in the queue or NULL if empty, can only
|
||||
* be used up until fluid_queue_next_outptr() is called.
|
||||
*
|
||||
* This function along with fluid_queue_next_outptr() form a queue "pop"
|
||||
* operation and is split into 2 functions to avoid an element copy.
|
||||
*/
|
||||
FLUID_INLINE fluid_event_queue_elem_t *
|
||||
fluid_event_queue_get_outptr (fluid_event_queue_t *queue)
|
||||
{
|
||||
return fluid_atomic_int_get (&queue->count) == 0 ? NULL
|
||||
: queue->array + queue->out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the output queue index to complete a "pop" operation.
|
||||
* @param queue Lockless queue instance
|
||||
*
|
||||
* This function along with fluid_queue_get_outptr() form a queue "pop"
|
||||
* operation and is split into 2 functions to avoid an element copy.
|
||||
*/
|
||||
FLUID_INLINE void
|
||||
fluid_event_queue_next_outptr (fluid_event_queue_t *queue)
|
||||
{
|
||||
fluid_atomic_int_dec_and_test (&queue->count);
|
||||
|
||||
if (++queue->out == queue->totalcount)
|
||||
queue->out = 0;
|
||||
}
|
130
fluidsynth/src/fluid_event_queue.h
Normal file
130
fluidsynth/src/fluid_event_queue.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_EVENT_QUEUE_H
|
||||
#define _FLUID_EVENT_QUEUE_H
|
||||
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_midi.h"
|
||||
|
||||
/**
|
||||
* Type of queued event.
|
||||
*/
|
||||
enum fluid_event_queue_elem
|
||||
{
|
||||
FLUID_EVENT_QUEUE_ELEM_MIDI, /**< MIDI event. Uses midi field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_GAIN, /**< Synth gain set or return event. Uses dval field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_POLYPHONY, /**< Synth polyphony event. Uses ival field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_GEN, /**< Generator event. Uses gen field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_PRESET, /**< Preset set event. Uses preset field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_STOP_VOICES, /**< Stop voices event. Uses ival field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_REVERB, /**< Reverb set or return event. Uses reverb field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_CHORUS, /**< Chorus set or return event. Uses chorus field of event value */
|
||||
FLUID_EVENT_QUEUE_ELEM_FREE_PRESET /**< Free a preset return event. Uses pval field of event value */
|
||||
};
|
||||
|
||||
/**
|
||||
* SoundFont generator set event structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int channel; /**< MIDI channel number */
|
||||
int param; /**< FluidSynth generator ID */
|
||||
float value; /**< Value for the generator (absolute or relative) */
|
||||
int absolute; /**< 1 if value is absolute, 0 if relative */
|
||||
} fluid_event_gen_t;
|
||||
|
||||
/**
|
||||
* Preset channel assignment event structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int channel; /**< MIDI channel number */
|
||||
fluid_preset_t *preset; /**< Preset to assign (synth thread owns) */
|
||||
} fluid_event_preset_t;
|
||||
|
||||
/**
|
||||
* Reverb assignment structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char set; /**< Bit 0: roomsize, 1: damping, 2: width, 3: level */
|
||||
float roomsize;
|
||||
float damping;
|
||||
float width;
|
||||
float level;
|
||||
} fluid_event_reverb_t;
|
||||
|
||||
/**
|
||||
* Chorus assignment structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char set; /**< Bit 0: nr, 1: type, 2: level, 3: speed, 4: depth */
|
||||
char nr;
|
||||
char type;
|
||||
float level;
|
||||
float speed;
|
||||
float depth;
|
||||
} fluid_event_chorus_t;
|
||||
|
||||
|
||||
/**
|
||||
* Event queue element structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char type; /**< #fluid_event_queue_elem */
|
||||
|
||||
union
|
||||
{
|
||||
fluid_midi_event_t midi; /**< If type == #FLUID_EVENT_QUEUE_ELEM_MIDI */
|
||||
fluid_event_gen_t gen; /**< If type == #FLUID_EVENT_QUEUE_ELEM_GEN */
|
||||
fluid_event_preset_t preset; /**< If type == #FLUID_EVENT_QUEUE_ELEM_PRESET */
|
||||
fluid_event_reverb_t reverb; /**< If type == #FLUID_EVENT_QUEUE_ELEM_REVERB */
|
||||
fluid_event_chorus_t chorus; /**< If type == #FLUID_EVENT_QUEUE_ELEM_CHORUS */
|
||||
double dval; /**< A floating point payload value */
|
||||
int ival; /**< An integer payload value */
|
||||
void *pval; /**< A pointer payload value */
|
||||
};
|
||||
} fluid_event_queue_elem_t;
|
||||
|
||||
/**
|
||||
* Lockless event queue instance.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
fluid_event_queue_elem_t *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 */
|
||||
void *synth; /**< Owning fluid_synth_t instance */
|
||||
} fluid_event_queue_t;
|
||||
|
||||
|
||||
fluid_event_queue_t *fluid_event_queue_new (int count);
|
||||
void fluid_event_queue_free (fluid_event_queue_t *queue);
|
||||
fluid_event_queue_elem_t *fluid_event_queue_get_inptr (fluid_event_queue_t *queue);
|
||||
void fluid_event_queue_next_inptr (fluid_event_queue_t *queue);
|
||||
fluid_event_queue_elem_t *fluid_event_queue_get_outptr (fluid_event_queue_t *queue);
|
||||
void fluid_event_queue_next_outptr (fluid_event_queue_t *queue);
|
||||
|
||||
#endif /* _FLUID_EVENT_QUEUE_H */
|
File diff suppressed because it is too large
Load diff
|
@ -25,40 +25,107 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Demolished by Peter Hanappe [December 2002]
|
||||
*
|
||||
* - only string as key
|
||||
* - stores additional type info
|
||||
* - removed use of GLib types (gpointer, gint, ...)
|
||||
* - reduced the number of API functions
|
||||
* 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_...
|
||||
*/
|
||||
|
||||
#ifndef _FLUID_HASH_H
|
||||
#define _FLUID_HASH_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
typedef int (*fluid_hash_iter_t)(char* key, void* value, int type, void* data);
|
||||
typedef void (*fluid_hash_delete_t)(void* value, int type);
|
||||
/* Extracted from gtypes.h */
|
||||
typedef void (*fluid_destroy_notify_t)(void *data);
|
||||
typedef unsigned int (*fluid_hash_func_t)(const void *key);
|
||||
typedef int (*fluid_equal_func_t)(const void *a, const void *b);
|
||||
/* End gtypes.h extraction */
|
||||
|
||||
fluid_hashtable_t* new_fluid_hashtable(fluid_hash_delete_t delete);
|
||||
void delete_fluid_hashtable(fluid_hashtable_t *hash_table);
|
||||
typedef int (*fluid_hr_func_t)(void *key, void *value, void *user_data);
|
||||
typedef struct _fluid_hashtable_iter_t fluid_hashtable_iter_t;
|
||||
|
||||
void fluid_hashtable_insert(fluid_hashtable_t *hash_table, char* key, void* value, int type);
|
||||
typedef struct _fluid_hashnode_t fluid_hashnode_t;
|
||||
|
||||
void fluid_hashtable_replace(fluid_hashtable_t *hash_table, char* key, void* value, int type);
|
||||
struct _fluid_hashnode_t
|
||||
{
|
||||
void *key;
|
||||
void *value;
|
||||
fluid_hashnode_t *next;
|
||||
unsigned int key_hash;
|
||||
};
|
||||
|
||||
/* Returns non-zero if found, 0 if not found */
|
||||
int fluid_hashtable_lookup(fluid_hashtable_t *hash_table, char* key, void** value, int* type);
|
||||
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_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
|
||||
};
|
||||
|
||||
/* Returns non-zero if removed, 0 if not removed */
|
||||
int fluid_hashtable_remove(fluid_hashtable_t *hash_table, char* key);
|
||||
struct _fluid_hashtable_iter_t
|
||||
{
|
||||
/*< private >*/
|
||||
void * dummy1;
|
||||
void * dummy2;
|
||||
void * dummy3;
|
||||
int dummy4;
|
||||
int dummy5; // Bool
|
||||
void * dummy6;
|
||||
};
|
||||
|
||||
void fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hash_iter_t fun, void* data);
|
||||
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);
|
||||
|
||||
unsigned int fluid_hashtable_size(fluid_hashtable_t *hash_table);
|
||||
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);
|
||||
|
||||
unsigned int fluid_str_hash(char* v);
|
||||
fluid_hashtable_t* fluid_hashtable_ref (fluid_hashtable_t *hashtable);
|
||||
void fluid_hashtable_unref (fluid_hashtable_t *hashtable);
|
||||
|
||||
void *fluid_hashtable_lookup (fluid_hashtable_t *hashtable, const void *key);
|
||||
int fluid_hashtable_lookup_extended (fluid_hashtable_t *hashtable, const void *lookup_key,
|
||||
void **orig_key, void **value);
|
||||
|
||||
void fluid_hashtable_insert (fluid_hashtable_t *hashtable, void *key, void *value);
|
||||
void fluid_hashtable_replace (fluid_hashtable_t *hashtable, void *key, void *value);
|
||||
|
||||
int fluid_hashtable_remove (fluid_hashtable_t *hashtable, void *key);
|
||||
int fluid_hashtable_steal (fluid_hashtable_t *hashtable, const void *key);
|
||||
void fluid_hashtable_remove_all (fluid_hashtable_t *hashtable);
|
||||
void fluid_hashtable_steal_all (fluid_hashtable_t *hashtable);
|
||||
unsigned int fluid_hashtable_foreach_steal (fluid_hashtable_t *hashtable,
|
||||
fluid_hr_func_t func, void *user_data);
|
||||
void fluid_hashtable_foreach (fluid_hashtable_t *hashtable, fluid_hr_func_t func,
|
||||
void *user_data);
|
||||
void *fluid_hashtable_find (fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
|
||||
void *user_data);
|
||||
unsigned int fluid_hashtable_size (fluid_hashtable_t *hashtable);
|
||||
fluid_list_t *fluid_hashtable_get_keys (fluid_hashtable_t *hashtable);
|
||||
fluid_list_t *fluid_hashtable_get_values (fluid_hashtable_t *hashtable);
|
||||
|
||||
int fluid_str_equal (const void *v1, const void *v2);
|
||||
unsigned int fluid_str_hash (const void *v);
|
||||
int fluid_direct_equal (const void *v1, const void *v2);
|
||||
unsigned int fluid_direct_hash (const void *v);
|
||||
int fluid_int_equal (const void *v1, const void *v2);
|
||||
unsigned int fluid_int_hash (const void *v);
|
||||
|
||||
#endif /* _FLUID_HASH_H */
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ new_fluid_jack_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func
|
|||
|
||||
/* try to become a client of the JACK server */
|
||||
|
||||
if (fluid_settings_getstr(settings, "audio.jack.id", &client_name)
|
||||
if (fluid_settings_dupstr(settings, "audio.jack.id", &client_name) /* ++ alloc client name */
|
||||
&& (client_name != NULL)
|
||||
&& (strlen(client_name) > 0)) {
|
||||
snprintf(name, 64, "%s", client_name);
|
||||
|
@ -137,6 +137,8 @@ new_fluid_jack_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func
|
|||
|
||||
name[63] = '\0';
|
||||
|
||||
if (client_name) FLUID_FREE (client_name); /* -- free client name */
|
||||
|
||||
if ((dev->client = jack_client_new(name)) == 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Jack server not running?");
|
||||
goto error_recovery;
|
||||
|
@ -414,7 +416,7 @@ new_fluid_jack_midi_driver (fluid_settings_t *settings,
|
|||
|
||||
/* try to become a client of the JACK server */
|
||||
|
||||
if (fluid_settings_getstr(settings, "midi.jack.id", &client_name)
|
||||
if (fluid_settings_dupstr(settings, "midi.jack.id", &client_name) /* ++ alloc client name */
|
||||
&& (client_name != NULL)
|
||||
&& (strlen(client_name) > 0))
|
||||
snprintf(name, 64, "%s", client_name);
|
||||
|
@ -422,6 +424,8 @@ new_fluid_jack_midi_driver (fluid_settings_t *settings,
|
|||
|
||||
name[63] = '\0';
|
||||
|
||||
if (client_name) FLUID_FREE (client_name); /* -- free client name */
|
||||
|
||||
if ((dev->client = jack_client_new (name)) == 0)
|
||||
{
|
||||
FLUID_LOG (FLUID_ERR, "Jack server not running?");
|
||||
|
|
|
@ -278,6 +278,10 @@ int fluid_midi_file_read_track(fluid_midi_file* mf, fluid_player_t* player, int
|
|||
}
|
||||
}
|
||||
|
||||
/* Skip remaining track data, if any */
|
||||
if (mf->trackpos < mf->tracklen)
|
||||
fluid_midi_file_skip (mf, mf->tracklen - mf->trackpos);
|
||||
|
||||
fluid_player_add_track(player, track);
|
||||
|
||||
} else {
|
||||
|
@ -1374,7 +1378,7 @@ int fluid_player_play(fluid_player_t* player)
|
|||
|
||||
if (player->use_system_timer) {
|
||||
player->system_timer = new_fluid_timer((int) player->deltatime, fluid_player_callback,
|
||||
(void*) player, 1, 0);
|
||||
(void*) player, TRUE, FALSE, TRUE);
|
||||
if (player->system_timer == NULL) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
@ -1637,7 +1641,7 @@ fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigne
|
|||
/* Purpose:
|
||||
* Returns the length of the MIDI message. */
|
||||
int fluid_midi_event_length(unsigned char event){
|
||||
switch (event && 0xF0) {
|
||||
switch (event & 0xF0) {
|
||||
case NOTE_OFF:
|
||||
case NOTE_ON:
|
||||
case KEY_PRESSURE:
|
||||
|
|
|
@ -118,7 +118,7 @@ new_fluid_oss_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
int queuesize;
|
||||
double sample_rate;
|
||||
int periods, period_size;
|
||||
char* devname;
|
||||
char* devname = NULL;
|
||||
int format;
|
||||
pthread_attr_t attr;
|
||||
int err;
|
||||
|
@ -167,8 +167,13 @@ new_fluid_oss_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (!fluid_settings_getstr(settings, "audio.oss.device", &devname)) {
|
||||
devname = "/dev/dsp";
|
||||
if (!fluid_settings_dupstr(settings, "audio.oss.device", &devname) || !devname) { /* ++ alloc device name */
|
||||
devname = FLUID_STRDUP ("/dev/dsp");
|
||||
|
||||
if (devname == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat(devname, &devstat) == -1) {
|
||||
|
@ -265,9 +270,12 @@ new_fluid_oss_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
break;
|
||||
}
|
||||
|
||||
if (devname) FLUID_FREE (devname); /* -- free device name */
|
||||
|
||||
return (fluid_audio_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
if (devname) FLUID_FREE (devname); /* -- free device name */
|
||||
delete_fluid_oss_audio_driver((fluid_audio_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -281,7 +289,7 @@ new_fluid_oss_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func,
|
|||
int queuesize;
|
||||
double sample_rate;
|
||||
int periods, period_size;
|
||||
char* devname;
|
||||
char* devname = NULL;
|
||||
int format;
|
||||
pthread_attr_t attr;
|
||||
int err;
|
||||
|
@ -310,9 +318,16 @@ new_fluid_oss_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func,
|
|||
dev->buffer_byte_size = dev->buffer_size * 2 * 2; /* 2 channels * 16 bits audio */
|
||||
|
||||
|
||||
if (!fluid_settings_getstr(settings, "audio.oss.device", &devname)) {
|
||||
devname = "/dev/dsp";
|
||||
if (!fluid_settings_dupstr(settings, "audio.oss.device", &devname) || !devname) {
|
||||
devname = FLUID_STRDUP ("/dev/dsp");
|
||||
|
||||
if (!devname)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat(devname, &devstat) == -1) {
|
||||
FLUID_LOG(FLUID_ERR, "Device <%s> does not exists", devname);
|
||||
goto error_recovery;
|
||||
|
@ -416,9 +431,12 @@ new_fluid_oss_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func,
|
|||
break;
|
||||
}
|
||||
|
||||
if (devname) FLUID_FREE (devname); /* -- free device name */
|
||||
|
||||
return (fluid_audio_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
if (devname) FLUID_FREE (devname); /* -- free device name */
|
||||
delete_fluid_oss_audio_driver((fluid_audio_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -668,7 +686,7 @@ new_fluid_oss_midi_driver(fluid_settings_t* settings,
|
|||
pthread_attr_t attr;
|
||||
int sched = SCHED_FIFO;
|
||||
struct sched_param priority;
|
||||
char* device;
|
||||
char* device = NULL;
|
||||
|
||||
/* not much use doing anything */
|
||||
if (handler == NULL) {
|
||||
|
@ -696,9 +714,16 @@ new_fluid_oss_midi_driver(fluid_settings_t* settings,
|
|||
}
|
||||
|
||||
/* get the device name. if none is specified, use the default device. */
|
||||
fluid_settings_getstr(settings, "midi.oss.device", &device);
|
||||
fluid_settings_dupstr(settings, "midi.oss.device", &device); /* ++ alloc device name */
|
||||
|
||||
if (device == NULL) {
|
||||
device = "/dev/midi";
|
||||
device = FLUID_STRDUP ("/dev/midi");
|
||||
|
||||
if (!device)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
}
|
||||
|
||||
/* open the default hardware device. only use midi in. */
|
||||
|
@ -746,9 +771,13 @@ new_fluid_oss_midi_driver(fluid_settings_t* settings,
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (device) FLUID_FREE (device); /* ++ free device */
|
||||
|
||||
return (fluid_midi_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
if (device) FLUID_FREE (device); /* ++ free device */
|
||||
delete_fluid_oss_midi_driver((fluid_midi_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
{
|
||||
fluid_portaudio_driver_t *dev = NULL;
|
||||
PaStreamParameters outputParams;
|
||||
char *device;
|
||||
char *device = NULL;
|
||||
double sample_rate;
|
||||
int period_size;
|
||||
PaError err;
|
||||
|
@ -125,7 +125,7 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
|
||||
fluid_settings_getint (settings, "audio.period-size", &period_size);
|
||||
fluid_settings_getnum (settings, "synth.sample-rate", &sample_rate);
|
||||
fluid_settings_getstr(settings, "audio.portaudio.device", &device);
|
||||
fluid_settings_dupstr(settings, "audio.portaudio.device", &device); /* ++ alloc device name */
|
||||
|
||||
bzero (&outputParams, sizeof (outputParams));
|
||||
outputParams.channelCount = 2;
|
||||
|
@ -209,9 +209,12 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
|
|||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (device) FLUID_FREE (device); /* -- free device name */
|
||||
|
||||
return (fluid_audio_driver_t *)dev;
|
||||
|
||||
error_recovery:
|
||||
if (device) FLUID_FREE (device); /* -- free device name */
|
||||
delete_fluid_portaudio_driver ((fluid_audio_driver_t *)dev);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -86,8 +86,8 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
|
|||
pa_buffer_attr bufattr;
|
||||
double sample_rate;
|
||||
int period_size, period_bytes;
|
||||
char *server;
|
||||
char *device;
|
||||
char *server = NULL;
|
||||
char *device = NULL;
|
||||
pthread_attr_t attr;
|
||||
int sched = SCHED_FIFO;
|
||||
struct sched_param priority;
|
||||
|
@ -104,11 +104,20 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
|
|||
// fluid_settings_getint(settings, "audio.periods", &periods);
|
||||
fluid_settings_getint(settings, "audio.period-size", &period_size);
|
||||
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
|
||||
fluid_settings_getstr(settings, "audio.pulseaudio.server", &server);
|
||||
fluid_settings_getstr(settings, "audio.pulseaudio.device", &device);
|
||||
fluid_settings_dupstr(settings, "audio.pulseaudio.server", &server); /* ++ alloc server string */
|
||||
fluid_settings_dupstr(settings, "audio.pulseaudio.device", &device); /* ++ alloc device string */
|
||||
|
||||
if (strcmp (server, "default") == 0) server = NULL;
|
||||
if (strcmp (device, "default") == 0) device = NULL;
|
||||
if (server && strcmp (server, "default") == 0)
|
||||
{
|
||||
FLUID_FREE (server); /* -- free server string */
|
||||
server = NULL;
|
||||
}
|
||||
|
||||
if (device && strcmp (device, "default") == 0)
|
||||
{
|
||||
FLUID_FREE (device); /* -- free device string */
|
||||
device = NULL;
|
||||
}
|
||||
|
||||
dev->data = data;
|
||||
dev->callback = func;
|
||||
|
@ -184,9 +193,14 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
|
|||
break;
|
||||
}
|
||||
|
||||
if (server) FLUID_FREE (server); /* -- free server string */
|
||||
if (device) FLUID_FREE (device); /* -- free device string */
|
||||
|
||||
return (fluid_audio_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
if (server) FLUID_FREE (server); /* -- free server string */
|
||||
if (device) FLUID_FREE (device); /* -- free device string */
|
||||
delete_fluid_pulse_audio_driver((fluid_audio_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -313,8 +313,8 @@ struct _fluid_revmodel_t {
|
|||
fluid_real_t bufallpassR4[allpasstuningR4];
|
||||
};
|
||||
|
||||
void fluid_revmodel_update(fluid_revmodel_t* rev);
|
||||
void fluid_revmodel_init(fluid_revmodel_t* rev);
|
||||
static void fluid_revmodel_update(fluid_revmodel_t* rev);
|
||||
static void fluid_revmodel_init(fluid_revmodel_t* rev);
|
||||
|
||||
fluid_revmodel_t*
|
||||
new_fluid_revmodel()
|
||||
|
@ -382,7 +382,7 @@ delete_fluid_revmodel(fluid_revmodel_t* rev)
|
|||
FLUID_FREE(rev);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
fluid_revmodel_init(fluid_revmodel_t* rev)
|
||||
{
|
||||
int i;
|
||||
|
@ -478,7 +478,7 @@ fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
fluid_revmodel_update(fluid_revmodel_t* rev)
|
||||
{
|
||||
/* Recalculate internal values after parameter change */
|
||||
|
@ -498,64 +498,34 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The following get/set functions are not inlined, because
|
||||
speed is never an issue when calling them, and also
|
||||
because as you develop the reverb model, you may
|
||||
wish to take dynamic action when they are called.
|
||||
*/
|
||||
/**
|
||||
* Set one or more reverb parameters.
|
||||
* @param rev Reverb instance
|
||||
* @param set One or more flags from #fluid_revmodel_set_t indicating what
|
||||
* parameters to set (#FLUID_REVMODEL_SET_ALL to set all parameters)
|
||||
* @param roomsize Reverb room size
|
||||
* @param damping Reverb damping
|
||||
* @param width Reverb width
|
||||
* @param level Reverb level
|
||||
*/
|
||||
void
|
||||
fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
|
||||
float damping, float width, float level)
|
||||
{
|
||||
/* fluid_clip(value, 0.0f, 1.0f); */
|
||||
rev->roomsize = (value * scaleroom) + offsetroom;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
if (set & FLUID_REVMODEL_SET_ROOMSIZE)
|
||||
rev->roomsize = (roomsize * scaleroom) + offsetroom;
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getroomsize(fluid_revmodel_t* rev)
|
||||
{
|
||||
return (rev->roomsize - offsetroom) / scaleroom;
|
||||
}
|
||||
if (set & FLUID_REVMODEL_SET_DAMPING)
|
||||
rev->damp = damping * scaledamp;
|
||||
|
||||
void
|
||||
fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
{
|
||||
/* fluid_clip(value, 0.0f, 1.0f); */
|
||||
rev->damp = value * scaledamp;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
if (set & FLUID_REVMODEL_SET_WIDTH)
|
||||
rev->width = width;
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getdamp(fluid_revmodel_t* rev)
|
||||
{
|
||||
return rev->damp / scaledamp;
|
||||
}
|
||||
if (set & FLUID_REVMODEL_SET_LEVEL)
|
||||
{
|
||||
fluid_clip(level, 0.0f, 1.0f);
|
||||
rev->wet = level * scalewet;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
{
|
||||
fluid_clip(value, 0.0f, 1.0f);
|
||||
rev->wet = value * scalewet;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getlevel(fluid_revmodel_t* rev)
|
||||
{
|
||||
return rev->wet / scalewet;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value)
|
||||
{
|
||||
/* fluid_clip(value, 0.0f, 1.0f); */
|
||||
rev->width = value;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_revmodel_getwidth(fluid_revmodel_t* rev)
|
||||
{
|
||||
return rev->width;
|
||||
fluid_revmodel_update (rev);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,30 @@
|
|||
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;
|
||||
|
||||
/** Value for fluid_revmodel_set() which sets all reverb parameters. */
|
||||
#define FLUID_REVMODEL_SET_ALL 0x0F
|
||||
|
||||
/*
|
||||
* reverb preset
|
||||
*/
|
||||
typedef struct _fluid_revmodel_presets_t {
|
||||
char* name;
|
||||
fluid_real_t roomsize;
|
||||
fluid_real_t damp;
|
||||
fluid_real_t width;
|
||||
fluid_real_t level;
|
||||
} fluid_revmodel_presets_t;
|
||||
|
||||
|
||||
/*
|
||||
* reverb
|
||||
*/
|
||||
|
@ -41,27 +65,7 @@ void fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
|
|||
|
||||
void fluid_revmodel_reset(fluid_revmodel_t* rev);
|
||||
|
||||
void fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
void fluid_revmodel_setmode(fluid_revmodel_t* rev, fluid_real_t value);
|
||||
|
||||
fluid_real_t fluid_revmodel_getroomsize(fluid_revmodel_t* rev);
|
||||
fluid_real_t fluid_revmodel_getdamp(fluid_revmodel_t* rev);
|
||||
fluid_real_t fluid_revmodel_getlevel(fluid_revmodel_t* rev);
|
||||
fluid_real_t fluid_revmodel_getwidth(fluid_revmodel_t* rev);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
} fluid_revmodel_presets_t;
|
||||
|
||||
void fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
|
||||
float damping, float width, float level);
|
||||
|
||||
#endif /* _FLUID_REV_H */
|
||||
|
|
|
@ -468,7 +468,7 @@ void fluid_sequencer_set_time_scale(fluid_sequencer_t* seq, double scale)
|
|||
|
||||
/* re-start timer */
|
||||
if (seq->useSystemTimer) {
|
||||
seq->timer = new_fluid_timer((int)(1000/seq->scale), _fluid_seq_queue_process, (void *)seq, 1, 0);
|
||||
seq->timer = new_fluid_timer((int)(1000/seq->scale), _fluid_seq_queue_process, (void *)seq, TRUE, FALSE, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ _fluid_seq_queue_init(fluid_sequencer_t* seq, int maxEvents)
|
|||
/* start timer */
|
||||
if (seq->useSystemTimer) {
|
||||
seq->timer = new_fluid_timer((int)(1000/seq->scale), _fluid_seq_queue_process,
|
||||
(void *)seq, 1, 0);
|
||||
(void *)seq, TRUE, FALSE, TRUE);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -32,6 +32,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_event_queue.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_rev.h"
|
||||
#include "fluid_voice.h"
|
||||
|
@ -76,53 +77,117 @@ enum fluid_synth_status
|
|||
#define SYNTH_REVERB_CHANNEL 0
|
||||
#define SYNTH_CHORUS_CHANNEL 1
|
||||
|
||||
typedef struct _fluid_bank_offset_t fluid_bank_offset_t;
|
||||
|
||||
struct _fluid_bank_offset_t {
|
||||
int sfont_id;
|
||||
int offset;
|
||||
};
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* Mutual exclusion notes:
|
||||
*
|
||||
* Set only once on init:
|
||||
* ----------------------
|
||||
* verbose
|
||||
* dump
|
||||
* sample_rate (will be runtime change-able in the future)
|
||||
* midi_channels
|
||||
* audio_channels
|
||||
* audio_groups
|
||||
* effects_channels
|
||||
* start
|
||||
* channel[] (Contents change)
|
||||
* nvoice
|
||||
* voice[] (Contents change)
|
||||
* nbuf
|
||||
* left_buf[], right_buf[] (Contents change)
|
||||
* fx_left_buf[], fx_right_buf[] (Contents change)
|
||||
* LADSPA_FxUnit (Contents change)
|
||||
*
|
||||
* Single thread use only (modify only prior to synthesis):
|
||||
* loaders<>
|
||||
* midi_router
|
||||
*
|
||||
* Mutex protected:
|
||||
* settings{} (has its own mutex)
|
||||
* sfont_info<>
|
||||
* tuning
|
||||
* cur_tuning
|
||||
* sfont_id
|
||||
* gain
|
||||
* reverb_roomsize, reverb_damping, reverb_width, reverb_level
|
||||
* chorus_nr, chorus_level, chorus_speed, chorus_depth, chorus_type
|
||||
*
|
||||
* Atomic int operations:
|
||||
* ----------------------
|
||||
* with_reverb
|
||||
* with_chorus
|
||||
* state
|
||||
*
|
||||
* noteid
|
||||
* storeid
|
||||
* outbuf
|
||||
* sample_timers
|
||||
*
|
||||
* Only synth thread changes
|
||||
* -------------------------
|
||||
* ticks
|
||||
* reverb{}
|
||||
* chorus{}
|
||||
* cur
|
||||
* dither_index
|
||||
* cpu_load
|
||||
* polyphony (atomic int get for non-synth threads)
|
||||
* st_gain
|
||||
*/
|
||||
|
||||
struct _fluid_synth_t
|
||||
{
|
||||
/* fluid_settings_old_t settings_old; the old synthesizer settings */
|
||||
fluid_settings_t* settings; /** the synthesizer settings */
|
||||
int polyphony; /** maximum polyphony */
|
||||
char with_reverb; /** Should the synth use the built-in reverb unit? */
|
||||
char with_chorus; /** Should the synth use the built-in chorus unit? */
|
||||
char verbose; /** Turn verbose mode on? */
|
||||
char dump; /** Dump events to stdout to hook up a user interface? */
|
||||
double sample_rate; /** The sample rate */
|
||||
int midi_channels; /** the number of MIDI channels (>= 16) */
|
||||
int audio_channels; /** the number of audio channels (1 channel=left+right) */
|
||||
int audio_groups; /** the number of (stereo) 'sub'groups from the synth.
|
||||
Typically equal to audio_channels. */
|
||||
int effects_channels; /** the number of effects channels (>= 2) */
|
||||
unsigned int state; /** the synthesizer state */
|
||||
unsigned int ticks; /** the number of audio samples since the start */
|
||||
unsigned int start; /** the start in msec, as returned by system clock */
|
||||
fluid_thread_id_t synth_thread_id; /**> ID of the synthesis thread or FLUID_THREAD_ID_NULL if not yet set */
|
||||
fluid_private_t thread_queues; /**> Thread private data for event queues for each non-synthesis thread queuing events */
|
||||
fluid_event_queue_t *queues[FLUID_MAX_EVENT_QUEUES]; /**> Thread event queues (NULL for unused elements) */
|
||||
|
||||
fluid_list_t *loaders; /** the soundfont loaders */
|
||||
fluid_list_t* sfont; /** the loaded soundfont */
|
||||
unsigned int sfont_id;
|
||||
fluid_list_t* bank_offsets; /** the offsets of the soundfont banks */
|
||||
fluid_mutex_t mutex; /**> Lock for multi-thread sensitive variables (not used by synthesis process) */
|
||||
fluid_list_t *queue_pool; /**> List of event queues whose threads have been destroyed and which can be re-used */
|
||||
fluid_event_queue_t *return_queue; /**> Event queue for events from synthesis thread to non-synthesis threads (memory frees, etc) */
|
||||
fluid_timer_t *return_queue_timer; /**> Timer thread to process return event queue */
|
||||
|
||||
#if defined(MACOS9)
|
||||
fluid_list_t* unloading; /** the soundfonts that need to be unloaded */
|
||||
#endif
|
||||
fluid_settings_t* settings; /**> the synthesizer settings */
|
||||
int polyphony; /**> maximum polyphony */
|
||||
char with_reverb; /**> Should the synth use the built-in reverb unit? */
|
||||
char with_chorus; /**> Should the synth use the built-in chorus unit? */
|
||||
char verbose; /**> Turn verbose mode on? */
|
||||
char dump; /**> Dump events to stdout to hook up a user interface? */
|
||||
double sample_rate; /**> The sample rate */
|
||||
int midi_channels; /**> the number of MIDI channels (>= 16) */
|
||||
int audio_channels; /**> the number of audio channels (1 channel=left+right) */
|
||||
int audio_groups; /**> the number of (stereo) 'sub'groups from the synth.
|
||||
Typically equal to audio_channels. */
|
||||
int effects_channels; /**> the number of effects channels (>= 2) */
|
||||
int state; /**> the synthesizer state */
|
||||
unsigned int ticks; /**> the number of audio samples since the start */
|
||||
unsigned int start; /**> the start in msec, as returned by system clock */
|
||||
|
||||
double gain; /** master gain */
|
||||
fluid_channel_t** channel; /** the channels */
|
||||
int num_channels; /** the number of channels */
|
||||
int nvoice; /** the length of the synthesis process array */
|
||||
fluid_voice_t** voice; /** the synthesis processes */
|
||||
unsigned int noteid; /** the id is incremented for every new note. it's used for noteoff's */
|
||||
fluid_list_t *loaders; /**> the SoundFont loaders */
|
||||
fluid_list_t *sfont_info; /**> List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
|
||||
fluid_hashtable_t *sfont_hash; /**> Hash of fluid_sfont_t->fluid_sfont_info_t (remains until SoundFont is deleted) */
|
||||
unsigned int sfont_id; /**> Incrementing ID assigned to each loaded SoundFont */
|
||||
|
||||
double gain; /**> master gain */
|
||||
double st_gain; /**> Synth thread gain shadow value */
|
||||
fluid_channel_t** channel; /**> the channels */
|
||||
int nvoice; /**> the length of the synthesis process array (max polyphony allowed) */
|
||||
fluid_voice_t** voice; /**> the synthesis voices */
|
||||
unsigned int noteid; /**> the id is incremented for every new note. it's used for noteoff's */
|
||||
unsigned int storeid;
|
||||
int nbuf; /** How many audio buffers are used? (depends on nr of audio channels / groups)*/
|
||||
int nbuf; /**> How many audio buffers are used? (depends on nr of audio channels / groups)*/
|
||||
|
||||
fluid_real_t** left_buf;
|
||||
fluid_real_t** right_buf;
|
||||
|
@ -131,24 +196,32 @@ struct _fluid_synth_t
|
|||
|
||||
fluid_revmodel_t* reverb;
|
||||
fluid_chorus_t* chorus;
|
||||
int cur; /** the current sample in the audio buffers to be output */
|
||||
int dither_index; /* current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
|
||||
|
||||
char outbuf[256]; /** buffer for message output */
|
||||
float reverb_roomsize; /**> Shadow of reverb roomsize */
|
||||
float reverb_damping; /**> Shadow of reverb damping */
|
||||
float reverb_width; /**> Shadow of reverb width */
|
||||
float reverb_level; /**> Shadow of reverb level */
|
||||
|
||||
int chorus_nr; /**> Shadow of chorus number */
|
||||
float chorus_level; /**> Shadow of chorus level */
|
||||
float chorus_speed; /**> Shadow of chorus speed */
|
||||
float chorus_depth; /**> Shadow of chorus depth */
|
||||
int chorus_type; /**> Shadow of chorus type */
|
||||
|
||||
int cur; /**> the current sample in the audio buffers to be output */
|
||||
int dither_index; /**> current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
|
||||
|
||||
char outbuf[256]; /**> buffer for message output */
|
||||
double cpu_load;
|
||||
|
||||
fluid_tuning_t*** tuning; /** 128 banks of 128 programs for the tunings */
|
||||
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
||||
fluid_tuning_t*** tuning; /**> 128 banks of 128 programs for the tunings */
|
||||
fluid_tuning_t* cur_tuning; /**> current tuning in the iteration */
|
||||
|
||||
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
|
||||
fluid_mutex_t busy; /* Indicates, whether the audio thread is currently running.
|
||||
* Note: This simple scheme does -not- provide 100 % protection against
|
||||
* thread problems, for example from MIDI thread and shell thread
|
||||
*/
|
||||
fluid_sample_timer_t* sample_timers; /* List of timers triggered after a block has been processed */
|
||||
fluid_midi_router_t* midi_router; /**> The midi router. Could be done nicer. */
|
||||
fluid_sample_timer_t* sample_timers; /**> List of timers triggered after a block has been processed */
|
||||
|
||||
#ifdef LADSPA
|
||||
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /** Effects unit for LADSPA support */
|
||||
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**> Effects unit for LADSPA support */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -156,7 +229,7 @@ struct _fluid_synth_t
|
|||
int fluid_synth_setstr(fluid_synth_t* synth, char* name, char* str);
|
||||
|
||||
/** returns 1 if the value exists, 0 otherwise */
|
||||
int fluid_synth_getstr(fluid_synth_t* synth, char* name, char** str);
|
||||
int fluid_synth_dupstr(fluid_synth_t* synth, char* name, char** str);
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
int fluid_synth_setnum(fluid_synth_t* synth, char* name, double val);
|
||||
|
@ -170,18 +243,12 @@ int fluid_synth_setint(fluid_synth_t* synth, char* name, int val);
|
|||
/** returns 1 if the value exists, 0 otherwise */
|
||||
int fluid_synth_getint(fluid_synth_t* synth, char* name, int* val);
|
||||
|
||||
|
||||
int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num);
|
||||
|
||||
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
|
||||
unsigned int banknum,
|
||||
unsigned int prognum);
|
||||
|
||||
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_modulate_voices(fluid_synth_t* synth, int chan, int is_cc, int ctrl);
|
||||
int fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan);
|
||||
int fluid_synth_damp_voices(fluid_synth_t* synth, int chan);
|
||||
int fluid_synth_kill_voice(fluid_synth_t* synth, fluid_voice_t * voice);
|
||||
|
||||
void fluid_synth_print_voice(fluid_synth_t* synth);
|
||||
|
@ -190,6 +257,13 @@ 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_set_reverb_preset(fluid_synth_t* synth, 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_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);
|
||||
|
||||
|
|
|
@ -386,7 +386,7 @@ DWORD WINAPI fluid_timer_run(LPVOID data);
|
|||
|
||||
fluid_timer_t*
|
||||
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
||||
int new_thread, int auto_destroy)
|
||||
int new_thread, int auto_destroy, int high_priority)
|
||||
{
|
||||
fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
|
||||
if (timer == NULL) {
|
||||
|
@ -408,7 +408,8 @@ new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
|||
FLUID_FREE(timer);
|
||||
return NULL;
|
||||
}
|
||||
SetThreadPriority(timer->thread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
if (high_priority)
|
||||
SetThreadPriority(timer->thread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
} else {
|
||||
fluid_timer_run((LPVOID) timer);
|
||||
}
|
||||
|
@ -419,7 +420,7 @@ DWORD WINAPI
|
|||
fluid_timer_run(LPVOID data)
|
||||
{
|
||||
int count = 0;
|
||||
int cont = 1;
|
||||
int cont;
|
||||
long start;
|
||||
long delay;
|
||||
fluid_timer_t* timer;
|
||||
|
@ -434,22 +435,19 @@ fluid_timer_run(LPVOID data)
|
|||
/* keep track of the start time for absolute positioning */
|
||||
start = fluid_curtime();
|
||||
|
||||
while (cont) {
|
||||
while (timer->cont) {
|
||||
|
||||
/* do whatever we have to do */
|
||||
cont = (*timer->callback)(timer->data, fluid_curtime() - start);
|
||||
|
||||
count++;
|
||||
if (!cont) break;
|
||||
|
||||
/* to avoid incremental time errors, I calculate the delay between
|
||||
two callbacks bringing in the "absolute" time (count *
|
||||
timer->msec) */
|
||||
delay = (count * timer->msec) - (fluid_curtime() - start);
|
||||
if (delay > 0) {
|
||||
Sleep(delay);
|
||||
}
|
||||
|
||||
cont &= timer->cont;
|
||||
if (delay > 0) Sleep (delay);
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Timer thread finished");
|
||||
|
@ -511,7 +509,7 @@ void fluid_timer_run(void *data);
|
|||
|
||||
fluid_timer_t*
|
||||
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
||||
int new_thread, int auto_destroy)
|
||||
int new_thread, int auto_destroy, int high_priority)
|
||||
{
|
||||
fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
|
||||
if (timer == NULL) {
|
||||
|
@ -533,7 +531,8 @@ new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
|||
FLUID_FREE(timer);
|
||||
return NULL;
|
||||
}
|
||||
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, timer->thread_id);
|
||||
if (high_priority)
|
||||
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, timer->thread_id);
|
||||
} else {
|
||||
fluid_timer_run(( void * )timer);
|
||||
}
|
||||
|
@ -544,7 +543,7 @@ void
|
|||
fluid_timer_run(void *data)
|
||||
{
|
||||
int count = 0;
|
||||
int cont = 1;
|
||||
int cont;
|
||||
long start;
|
||||
long delay;
|
||||
fluid_timer_t* timer;
|
||||
|
@ -559,22 +558,19 @@ fluid_timer_run(void *data)
|
|||
/* keep track of the start time for absolute positioning */
|
||||
start = fluid_curtime();
|
||||
|
||||
while (cont) {
|
||||
while (timer->cont) {
|
||||
|
||||
/* do whatever we have to do */
|
||||
cont = (*timer->callback)(timer->data, fluid_curtime() - start);
|
||||
|
||||
count++;
|
||||
if (!cont) break;
|
||||
|
||||
/* to avoid incremental time errors, I calculate the delay between
|
||||
two callbacks bringing in the "absolute" time (count *
|
||||
timer->msec) */
|
||||
delay = (count * timer->msec) - (fluid_curtime() - start);
|
||||
if (delay > 0) {
|
||||
DosSleep(delay);
|
||||
}
|
||||
|
||||
cont &= timer->cont;
|
||||
if (delay > 0) DosSleep (delay);
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Timer thread finished");
|
||||
|
@ -631,10 +627,10 @@ struct _fluid_timer_t
|
|||
};
|
||||
|
||||
void*
|
||||
fluid_timer_start(void *data)
|
||||
fluid_timer_run(void *data)
|
||||
{
|
||||
int count = 0;
|
||||
int cont = 1;
|
||||
int cont;
|
||||
long start;
|
||||
long delay;
|
||||
fluid_timer_t* timer;
|
||||
|
@ -643,22 +639,19 @@ fluid_timer_start(void *data)
|
|||
/* keep track of the start time for absolute positioning */
|
||||
start = fluid_curtime();
|
||||
|
||||
while (cont) {
|
||||
while (timer->cont) {
|
||||
|
||||
/* do whatever we have to do */
|
||||
cont = (*timer->callback)(timer->data, fluid_curtime() - start);
|
||||
|
||||
count++;
|
||||
if (!cont) break;
|
||||
|
||||
/* to avoid incremental time errors, calculate the delay between
|
||||
two callbacks bringing in the "absolute" time (count *
|
||||
timer->msec) */
|
||||
delay = (count * timer->msec) - (fluid_curtime() - start);
|
||||
if (delay > 0) {
|
||||
usleep(delay * 1000);
|
||||
}
|
||||
|
||||
cont &= timer->cont;
|
||||
if (delay > 0) usleep (delay * 1000);
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Timer thread finished");
|
||||
|
@ -675,7 +668,7 @@ fluid_timer_start(void *data)
|
|||
|
||||
fluid_timer_t*
|
||||
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
||||
int new_thread, int auto_destroy)
|
||||
int new_thread, int auto_destroy, int high_priority)
|
||||
{
|
||||
pthread_attr_t *attr = NULL;
|
||||
pthread_attr_t rt_attr;
|
||||
|
@ -695,35 +688,33 @@ new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
|||
timer->thread = 0;
|
||||
timer->auto_destroy = auto_destroy;
|
||||
|
||||
err = pthread_attr_init(&rt_attr);
|
||||
if (err == 0) {
|
||||
err = pthread_attr_setschedpolicy(&rt_attr, SCHED_FIFO);
|
||||
if (err == 0) {
|
||||
priority.sched_priority = 10;
|
||||
err = pthread_attr_setschedparam(&rt_attr, &priority);
|
||||
if (err == 0) {
|
||||
attr = &rt_attr;
|
||||
}
|
||||
}
|
||||
if (high_priority) {
|
||||
priority.sched_priority = 10;
|
||||
|
||||
if (pthread_attr_init (&rt_attr) == 0
|
||||
&& pthread_attr_setschedpolicy (&rt_attr, SCHED_FIFO) == 0
|
||||
&& pthread_attr_setschedparam (&rt_attr, &priority) == 0)
|
||||
attr = &rt_attr;
|
||||
}
|
||||
|
||||
if (new_thread) {
|
||||
err = pthread_create(&timer->thread, attr, fluid_timer_start, (void*) timer);
|
||||
if (err == 0) {
|
||||
FLUID_LOG(FLUID_DBG, "The timer thread was created with real-time priority");
|
||||
} else {
|
||||
/* Create the thread with default attributes */
|
||||
err = pthread_create(&timer->thread, NULL, fluid_timer_start, (void*) timer);
|
||||
if (err != 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to create the timer thread");
|
||||
FLUID_FREE(timer);
|
||||
return NULL;
|
||||
} else {
|
||||
FLUID_LOG(FLUID_DBG, "The timer thread does not have real-time priority");
|
||||
}
|
||||
}
|
||||
err = pthread_create(&timer->thread, attr, fluid_timer_run, (void*) timer);
|
||||
|
||||
if (err == 0) {
|
||||
if (attr) FLUID_LOG(FLUID_DBG, "Timer thread created with real-time priority");
|
||||
else FLUID_LOG(FLUID_DBG, "Timer thread created with normal priority");
|
||||
} else {
|
||||
if (attr == NULL
|
||||
|| pthread_create (&timer->thread, NULL, fluid_timer_run, (void*) timer) != 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to create timer thread");
|
||||
FLUID_FREE(timer);
|
||||
return NULL;
|
||||
} else {
|
||||
FLUID_LOG(FLUID_DBG, "Timer thread created, but not with real-time priority");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fluid_timer_start((void*) timer);
|
||||
fluid_timer_run((void*) timer);
|
||||
}
|
||||
return timer;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,14 @@ void fluid_log_config(void);
|
|||
void fluid_time_config(void);
|
||||
|
||||
|
||||
/* Misc */
|
||||
|
||||
#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
|
||||
|
||||
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
|
@ -64,7 +72,6 @@ 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;
|
||||
|
@ -105,7 +112,8 @@ 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);
|
||||
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);
|
||||
|
@ -113,21 +121,48 @@ int fluid_timer_stop(fluid_timer_t* timer);
|
|||
|
||||
/**
|
||||
|
||||
Muteces
|
||||
Muteces
|
||||
|
||||
*/
|
||||
|
||||
typedef GStaticMutex fluid_mutex_t;
|
||||
#define fluid_mutex_init(_m) g_static_mutex_init(&(_m))
|
||||
#define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m))
|
||||
#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))
|
||||
#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m))
|
||||
/* Recursive locks allowed */
|
||||
typedef GStaticRecMutex fluid_mutex_t;
|
||||
#define fluid_mutex_init(_m) g_static_rec_mutex_init(&(_m))
|
||||
#define fluid_mutex_destroy(_m) g_static_rec_mutex_free(&(_m))
|
||||
#define fluid_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))
|
||||
#define fluid_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))
|
||||
|
||||
|
||||
/* 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)
|
||||
#define fluid_atomic_int_compare_and_exchange(_pi, _old, _new) \
|
||||
g_atomic_int_compare_and_exchange(_pi, _old, _new)
|
||||
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
|
||||
g_atomic_int_exchange_and_add(_pi, _add)
|
||||
|
||||
#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp)
|
||||
#define fluid_atomic_pointer_compare_and_exchange(_pp, _old, _new) \
|
||||
g_atomic_pointer_compare_and_exchange(_pp, _old, _new)
|
||||
|
||||
|
||||
/* Thread private data */
|
||||
|
||||
typedef GStaticPrivate fluid_private_t;
|
||||
#define fluid_private_init(_priv) g_static_private_init(&(_priv))
|
||||
#define fluid_private_get(_priv) g_static_private_get(&(_priv))
|
||||
#define fluid_private_set(_priv, _data, _notify) g_static_private_set(&(_priv), _data, _notify)
|
||||
#define fluid_private_free(_priv) g_static_private_free(&(_priv))
|
||||
|
||||
|
||||
/**
|
||||
Threads
|
||||
Threads
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
typedef GThread fluid_thread_t;
|
||||
typedef void (*fluid_thread_func_t)(void* data);
|
||||
|
@ -138,10 +173,14 @@ fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detac
|
|||
int delete_fluid_thread(fluid_thread_t* thread);
|
||||
int fluid_thread_join(fluid_thread_t* thread);
|
||||
|
||||
/**
|
||||
Sockets and I/O
|
||||
#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 */
|
||||
|
||||
*/
|
||||
/**
|
||||
Sockets and I/O
|
||||
|
||||
*/
|
||||
|
||||
fluid_istream_t fluid_get_stdin (void);
|
||||
fluid_ostream_t fluid_get_stdout (void);
|
||||
|
|
|
@ -105,8 +105,14 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
|
|||
dev->driver.data = data;
|
||||
|
||||
/* get the device name. if none is specified, use the default device. */
|
||||
if(!fluid_settings_getstr(settings, "midi.winmidi.device", &devname)) {
|
||||
devname = "default";
|
||||
if(!fluid_settings_getstr(settings, "midi.winmidi.device", &devname) || !devname) {
|
||||
devname = FLUID_DUPSTR ("default");
|
||||
|
||||
if (!devname)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if there any midi devices installed */
|
||||
|
@ -150,9 +156,12 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
|
|||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (devname) FLUID_FREE (devname); /* -- free device name */
|
||||
|
||||
return (fluid_midi_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
if (devname) FLUID_FREE (devname); /* -- free device name */
|
||||
delete_fluid_winmidi_driver((fluid_midi_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -193,6 +202,10 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD dwInstance, DWORD msg, DWOR
|
|||
event.channel = msg_chan(msg);
|
||||
event.param1 = msg_p1(msg);
|
||||
event.param2 = msg_p2(msg);
|
||||
if(event.type==PITCH_BEND){
|
||||
event.param1 = ((event.param2 & 0x7f) << 7) | (event.param1 & 0x7f);
|
||||
event.param2 = 0;
|
||||
}
|
||||
(*dev->driver.handler)(dev->driver.data, &event);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -183,15 +183,20 @@ void fast_render_loop(fluid_settings_t* settings, fluid_synth_t* synth, fluid_pl
|
|||
int period_size = 0;
|
||||
|
||||
fluid_settings_getint(settings, "audio.period-size", &period_size);
|
||||
fluid_settings_getstr(settings, "audio.file.name", &filename);
|
||||
fluid_settings_dupstr(settings, "audio.file.name", &filename); /* ++ alloc file name */
|
||||
|
||||
if (filename == NULL || period_size <= 0) {
|
||||
fprintf(stderr, "Failed to fetch parameters for file renderer\n");
|
||||
if (filename) FLUID_FREE (filename); /* -- free file name */
|
||||
return;
|
||||
}
|
||||
|
||||
renderer = new_fluid_file_renderer(synth, filename, period_size);
|
||||
|
||||
FLUID_FREE (filename); /* -- free file name */
|
||||
|
||||
if (!renderer) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) {
|
||||
|
@ -225,7 +230,7 @@ int main(int argc, char** argv)
|
|||
int midi_in = 1;
|
||||
fluid_player_t* player = NULL;
|
||||
fluid_midi_router_t* router = NULL;
|
||||
fluid_sequencer_t* sequencer = NULL;
|
||||
//fluid_sequencer_t* sequencer = NULL;
|
||||
fluid_midi_driver_t* mdriver = NULL;
|
||||
fluid_audio_driver_t* adriver = NULL;
|
||||
fluid_synth_t* synth = NULL;
|
||||
|
@ -524,20 +529,20 @@ int main(int argc, char** argv)
|
|||
/* In dump mode, text output is generated for events going into and out of the router.
|
||||
* The example dump functions are put into the chain before and after the router..
|
||||
*/
|
||||
sequencer = new_fluid_sequencer2(0);
|
||||
//sequencer = new_fluid_sequencer2(0);
|
||||
|
||||
router = new_fluid_midi_router(
|
||||
settings,
|
||||
dump ? fluid_midi_dump_postrouter : fluid_sequencer_add_midi_event_to_buffer,
|
||||
(void*)sequencer);
|
||||
dump ? fluid_midi_dump_postrouter : fluid_synth_handle_midi_event,
|
||||
(void*)synth);
|
||||
|
||||
if (router == NULL || sequencer == NULL) {
|
||||
if (router == NULL) {
|
||||
fprintf(stderr, "Failed to create the MIDI input router; no MIDI input\n"
|
||||
"will be available. You can access the synthesizer \n"
|
||||
"through the console.\n");
|
||||
} else {
|
||||
fluid_synth_set_midi_router(synth, router); /* Fixme, needed for command handler */
|
||||
fluid_sequencer_register_fluidsynth(sequencer, synth);
|
||||
// fluid_sequencer_register_fluidsynth(sequencer, synth);
|
||||
mdriver = new_fluid_midi_driver(
|
||||
settings,
|
||||
dump ? fluid_midi_dump_prerouter : fluid_midi_router_handle_midi_event,
|
||||
|
@ -654,9 +659,9 @@ int main(int argc, char** argv)
|
|||
#endif
|
||||
}
|
||||
|
||||
if (sequencer) {
|
||||
/*if (sequencer) {
|
||||
delete_fluid_sequencer(sequencer);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (adriver) {
|
||||
delete_fluid_audio_driver(adriver);
|
||||
|
|
|
@ -198,7 +198,10 @@ typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
|
|||
* CONSTANTS
|
||||
*/
|
||||
|
||||
#define FLUID_BUFSIZE 64
|
||||
#define FLUID_BUFSIZE 64 /**< FluidSynth internal buffer size (in samples) */
|
||||
#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 */
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.141592654
|
||||
|
@ -225,6 +228,7 @@ typedef FILE* fluid_file;
|
|||
#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_STRCHR(_s,_c) strchr(_s,_c)
|
||||
#ifdef strdup
|
||||
#define FLUID_STRDUP(s) strdup(s)
|
||||
|
|
Loading…
Reference in a new issue