Merged fluidsynth_event_queue branch r207:223 into trunk.

This commit is contained in:
Josh Green 2009-09-22 07:04:07 +00:00
parent cf39719f5d
commit e5c832c587
34 changed files with 5735 additions and 3032 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View 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

View file

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

View file

@ -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?");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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