updated fluidsynth to 1.0.8
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24454 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -44,39 +44,36 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
|
||||
\file fluidsynth.h
|
||||
|
||||
\brief fluidsynth is a real-time SoundFont(R) synthesizer. This is
|
||||
the header of the fluidsynth library and contains the
|
||||
synthesizer's public API.
|
||||
|
||||
Depending on how you want to use or extend the synthesizer you
|
||||
will need different API functions. You probably do not need all
|
||||
of them. Here is what you might want to do:
|
||||
|
||||
o Embedded synthesizer: create a new synthesizer and send MIDI
|
||||
events to it. The sound goes directly to the audio output of
|
||||
your system.
|
||||
|
||||
o Plugin synthesizer: create a synthesizer and send MIDI events
|
||||
but pull the audio back into your application.
|
||||
|
||||
o SoundFont plugin: create a new type of "SoundFont" and allow
|
||||
the synthesizer to load your type of SoundFonts.
|
||||
|
||||
o MIDI input: Create a MIDI handler to read the MIDI input on your
|
||||
machine and send the MIDI events directly to the synthesizer.
|
||||
|
||||
o MIDI files: Open MIDI files and send the MIDI events to the
|
||||
synthesizer.
|
||||
|
||||
o Command lines: You can send textual commands to the synthesizer.
|
||||
|
||||
|
||||
SoundFont(R) is a registered trademark of E-mu Systems, Inc.
|
||||
|
||||
/**
|
||||
* @file fluidsynth.h
|
||||
* @brief FluidSynth is a real-time synthesizer designed for SoundFont(R) files.
|
||||
*
|
||||
* This is the header of the fluidsynth library and contains the
|
||||
* synthesizer's public API.
|
||||
*
|
||||
* Depending on how you want to use or extend the synthesizer you
|
||||
* will need different API functions. You probably do not need all
|
||||
* of them. Here is what you might want to do:
|
||||
*
|
||||
* o Embedded synthesizer: create a new synthesizer and send MIDI
|
||||
* events to it. The sound goes directly to the audio output of
|
||||
* your system.
|
||||
*
|
||||
* o Plugin synthesizer: create a synthesizer and send MIDI events
|
||||
* but pull the audio back into your application.
|
||||
*
|
||||
* o SoundFont plugin: create a new type of "SoundFont" and allow
|
||||
* the synthesizer to load your type of SoundFonts.
|
||||
*
|
||||
* o MIDI input: Create a MIDI handler to read the MIDI input on your
|
||||
* machine and send the MIDI events directly to the synthesizer.
|
||||
*
|
||||
* o MIDI files: Open MIDI files and send the MIDI events to the
|
||||
* synthesizer.
|
||||
*
|
||||
* o Command lines: You can send textual commands to the synthesizer.
|
||||
*
|
||||
* SoundFont(R) is a registered trademark of E-mu Systems, Inc.
|
||||
*/
|
||||
|
||||
#include "fluidsynth/types.h"
|
||||
|
||||
@@ -25,15 +25,29 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/** Audio driver
|
||||
*
|
||||
/**
|
||||
* @file audio.h
|
||||
* @brief Functions for audio driver output.
|
||||
*
|
||||
* Defines functions for creating audio driver output. Use
|
||||
* new_fluid_audio_driver() to create a new audio driver for a given synth
|
||||
* and configuration settings. The function new_fluid_audio_driver2() can be
|
||||
* used if custom audio processing is desired before the audio is sent to the
|
||||
* audio driver (although it is not as efficient).
|
||||
*/
|
||||
|
||||
|
||||
/** The function should return non-zero if an error occured. */
|
||||
/**
|
||||
* Callback function type used with new_fluid_audio_driver2() to allow for
|
||||
* custom user audio processing before the audio is sent to the driver. This
|
||||
* function is responsible for rendering the audio to the buffers.
|
||||
* @param data The user data parameter as passed to new_fluid_audio_driver2().
|
||||
* @param len Length of the audio in frames.
|
||||
* @param nin Count of buffers in 'in'
|
||||
* @param in FIXME - Not used currently?
|
||||
* @param nout Count of arrays in 'out' (i.e., channel count)
|
||||
* @param out Output buffers, one for each channel
|
||||
* @return Should return 0 on success, non-zero if an error occured.
|
||||
*/
|
||||
typedef int (*fluid_audio_func_t)(void* data, int len,
|
||||
int nin, float** in,
|
||||
int nout, float** out);
|
||||
|
||||
@@ -25,28 +25,37 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file event.h
|
||||
* @brief Sequencer event functions and defines.
|
||||
*
|
||||
* Functions and constants for creating/processing sequencer events.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sequencer event type enumeration.
|
||||
*/
|
||||
enum fluid_seq_event_type {
|
||||
FLUID_SEQ_NOTE = 0,
|
||||
FLUID_SEQ_NOTEON,
|
||||
FLUID_SEQ_NOTEOFF,
|
||||
FLUID_SEQ_ALLSOUNDSOFF,
|
||||
FLUID_SEQ_ALLNOTESOFF,
|
||||
FLUID_SEQ_BANKSELECT,
|
||||
FLUID_SEQ_PROGRAMCHANGE,
|
||||
FLUID_SEQ_PROGRAMSELECT,
|
||||
FLUID_SEQ_PITCHBEND,
|
||||
FLUID_SEQ_PITCHWHHELSENS,
|
||||
FLUID_SEQ_MODULATION,
|
||||
FLUID_SEQ_SUSTAIN,
|
||||
FLUID_SEQ_CONTROLCHANGE,
|
||||
FLUID_SEQ_PAN,
|
||||
FLUID_SEQ_VOLUME,
|
||||
FLUID_SEQ_REVERBSEND,
|
||||
FLUID_SEQ_CHORUSSEND,
|
||||
FLUID_SEQ_TIMER,
|
||||
FLUID_SEQ_ANYCONTROLCHANGE, // used for remove_events only
|
||||
FLUID_SEQ_LASTEVENT
|
||||
FLUID_SEQ_NOTE = 0, /**< Note event (DOCME) */
|
||||
FLUID_SEQ_NOTEON, /**< Note on event */
|
||||
FLUID_SEQ_NOTEOFF, /**< Note off event */
|
||||
FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
|
||||
FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
|
||||
FLUID_SEQ_BANKSELECT, /**< Bank select message */
|
||||
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
|
||||
FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */
|
||||
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
|
||||
FLUID_SEQ_PITCHWHHELSENS, /**< Pitch wheel sensitivity set message */
|
||||
FLUID_SEQ_MODULATION, /**< Modulation controller event */
|
||||
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
|
||||
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
|
||||
FLUID_SEQ_PAN, /**< Stereo pan set event */
|
||||
FLUID_SEQ_VOLUME, /**< Volume set event */
|
||||
FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
|
||||
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
|
||||
FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
|
||||
FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
|
||||
FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
|
||||
};
|
||||
|
||||
/* Event alloc/free */
|
||||
|
||||
@@ -25,99 +25,105 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file gen.h
|
||||
* @brief Functions and defines for SoundFont generator effects.
|
||||
*/
|
||||
|
||||
/** List of generator numbers
|
||||
Soundfont 2.01 specifications section 8.1.3 */
|
||||
/**
|
||||
* Generator (effect) numbers (Soundfont 2.01 specifications section 8.1.3)
|
||||
*/
|
||||
enum fluid_gen_type {
|
||||
GEN_STARTADDROFS,
|
||||
GEN_ENDADDROFS,
|
||||
GEN_STARTLOOPADDROFS,
|
||||
GEN_ENDLOOPADDROFS,
|
||||
GEN_STARTADDRCOARSEOFS,
|
||||
GEN_MODLFOTOPITCH,
|
||||
GEN_VIBLFOTOPITCH,
|
||||
GEN_MODENVTOPITCH,
|
||||
GEN_FILTERFC,
|
||||
GEN_FILTERQ,
|
||||
GEN_MODLFOTOFILTERFC,
|
||||
GEN_MODENVTOFILTERFC,
|
||||
GEN_ENDADDRCOARSEOFS,
|
||||
GEN_MODLFOTOVOL,
|
||||
GEN_UNUSED1,
|
||||
GEN_CHORUSSEND,
|
||||
GEN_REVERBSEND,
|
||||
GEN_PAN,
|
||||
GEN_UNUSED2,
|
||||
GEN_UNUSED3,
|
||||
GEN_UNUSED4,
|
||||
GEN_MODLFODELAY,
|
||||
GEN_MODLFOFREQ,
|
||||
GEN_VIBLFODELAY,
|
||||
GEN_VIBLFOFREQ,
|
||||
GEN_MODENVDELAY,
|
||||
GEN_MODENVATTACK,
|
||||
GEN_MODENVHOLD,
|
||||
GEN_MODENVDECAY,
|
||||
GEN_MODENVSUSTAIN,
|
||||
GEN_MODENVRELEASE,
|
||||
GEN_KEYTOMODENVHOLD,
|
||||
GEN_KEYTOMODENVDECAY,
|
||||
GEN_VOLENVDELAY,
|
||||
GEN_VOLENVATTACK,
|
||||
GEN_VOLENVHOLD,
|
||||
GEN_VOLENVDECAY,
|
||||
GEN_VOLENVSUSTAIN,
|
||||
GEN_VOLENVRELEASE,
|
||||
GEN_KEYTOVOLENVHOLD,
|
||||
GEN_KEYTOVOLENVDECAY,
|
||||
GEN_INSTRUMENT,
|
||||
GEN_RESERVED1,
|
||||
GEN_KEYRANGE,
|
||||
GEN_VELRANGE,
|
||||
GEN_STARTLOOPADDRCOARSEOFS,
|
||||
GEN_KEYNUM,
|
||||
GEN_VELOCITY,
|
||||
GEN_ATTENUATION,
|
||||
GEN_RESERVED2,
|
||||
GEN_ENDLOOPADDRCOARSEOFS,
|
||||
GEN_COARSETUNE,
|
||||
GEN_FINETUNE,
|
||||
GEN_SAMPLEID,
|
||||
GEN_SAMPLEMODE,
|
||||
GEN_RESERVED3,
|
||||
GEN_SCALETUNE,
|
||||
GEN_EXCLUSIVECLASS,
|
||||
GEN_OVERRIDEROOTKEY,
|
||||
GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
|
||||
GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
|
||||
GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
|
||||
GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
|
||||
GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
|
||||
GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
|
||||
GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
|
||||
GEN_FILTERFC, /**< Filter cutoff */
|
||||
GEN_FILTERQ, /**< Filter Q */
|
||||
GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
|
||||
GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
|
||||
GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
|
||||
GEN_UNUSED1, /**< Unused */
|
||||
GEN_CHORUSSEND, /**< Chorus send amount */
|
||||
GEN_REVERBSEND, /**< Reverb send amount */
|
||||
GEN_PAN, /**< Stereo panning */
|
||||
GEN_UNUSED2, /**< Unused */
|
||||
GEN_UNUSED3, /**< Unused */
|
||||
GEN_UNUSED4, /**< Unused */
|
||||
GEN_MODLFODELAY, /**< Modulation LFO delay */
|
||||
GEN_MODLFOFREQ, /**< Modulation LFO frequency */
|
||||
GEN_VIBLFODELAY, /**< Vibrato LFO delay */
|
||||
GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
|
||||
GEN_MODENVDELAY, /**< Modulation envelope delay */
|
||||
GEN_MODENVATTACK, /**< Modulation envelope attack */
|
||||
GEN_MODENVHOLD, /**< Modulation envelope hold */
|
||||
GEN_MODENVDECAY, /**< Modulation envelope decay */
|
||||
GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
|
||||
GEN_MODENVRELEASE, /**< Modulation envelope release */
|
||||
GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
|
||||
GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
|
||||
GEN_VOLENVDELAY, /**< Volume envelope delay */
|
||||
GEN_VOLENVATTACK, /**< Volume envelope attack */
|
||||
GEN_VOLENVHOLD, /**< Volume envelope hold */
|
||||
GEN_VOLENVDECAY, /**< Volume envelope decay */
|
||||
GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
|
||||
GEN_VOLENVRELEASE, /**< Volume envelope release */
|
||||
GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
|
||||
GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
|
||||
GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
|
||||
GEN_RESERVED1, /**< Reserved */
|
||||
GEN_KEYRANGE, /**< MIDI note range */
|
||||
GEN_VELRANGE, /**< MIDI velocity range */
|
||||
GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
|
||||
GEN_KEYNUM, /**< Fixed MIDI note number */
|
||||
GEN_VELOCITY, /**< Fixed MIDI velocity value */
|
||||
GEN_ATTENUATION, /**< Initial volume attenuation */
|
||||
GEN_RESERVED2, /**< Reserved */
|
||||
GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
|
||||
GEN_COARSETUNE, /**< Coarse tuning */
|
||||
GEN_FINETUNE, /**< Fine tuning */
|
||||
GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
|
||||
GEN_SAMPLEMODE, /**< Sample mode flags */
|
||||
GEN_RESERVED3, /**< Reserved */
|
||||
GEN_SCALETUNE, /**< Scale tuning */
|
||||
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
|
||||
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
|
||||
|
||||
/* the initial pitch is not a "standard" generator. It is not
|
||||
* mentioned in the list of generator in the SF2 specifications. It
|
||||
* is used, however, as the destination for the default pitch wheel
|
||||
* modulator. */
|
||||
GEN_PITCH,
|
||||
GEN_LAST
|
||||
GEN_PITCH, /**< Pitch (NOTE: Not a real SoundFont generator) */
|
||||
GEN_LAST /**< Value defines the count of generators (#fluid_gen_type) */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* fluid_gen_t
|
||||
* Sound font generator
|
||||
/**
|
||||
* SoundFont generator structure.
|
||||
*/
|
||||
typedef struct _fluid_gen_t
|
||||
{
|
||||
unsigned char flags; /* is it used or not */
|
||||
double val; /* The nominal value */
|
||||
double mod; /* Change by modulators */
|
||||
double nrpn; /* Change by NRPN messages */
|
||||
unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
|
||||
double val; /**< The nominal value */
|
||||
double mod; /**< Change by modulators */
|
||||
double nrpn; /**< Change by NRPN messages */
|
||||
} fluid_gen_t;
|
||||
|
||||
/**
|
||||
* Enum value for 'flags' field of #_fluid_gen_t (not really flags).
|
||||
*/
|
||||
enum fluid_gen_flags
|
||||
{
|
||||
GEN_UNUSED,
|
||||
GEN_SET,
|
||||
GEN_ABS_NRPN
|
||||
GEN_UNUSED, /**< Generator value is not set */
|
||||
GEN_SET, /**< Generator value is set */
|
||||
GEN_ABS_NRPN /**< DOCME */
|
||||
};
|
||||
|
||||
/** Reset an array of generators to the SF2.01 default values */
|
||||
FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
|
||||
|
||||
|
||||
|
||||
@@ -27,57 +27,55 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Logging interface
|
||||
/**
|
||||
* @file log.h
|
||||
* @brief Logging interface
|
||||
*
|
||||
* The default logging function of the fluidsynth prints its messages
|
||||
* to the stderr. The synthesizer uses four level of messages: FLUID_PANIC,
|
||||
* ERR, WARN, and FLUID_DBG. They are commented in the definition below.
|
||||
* to the stderr. The synthesizer uses five level of messages: #FLUID_PANIC,
|
||||
* #FLUID_ERR, #FLUID_WARN, #FLUID_INFO, and #FLUID_DBG.
|
||||
*
|
||||
* A client application can install a new log function to handle the
|
||||
* messages differently. In the following example, the application
|
||||
* sets a callback function to display "FLUID_PANIC" messages in a dialog,
|
||||
* sets a callback function to display #FLUID_PANIC messages in a dialog,
|
||||
* and ignores all other messages by setting the log function to
|
||||
* NULL:
|
||||
*
|
||||
* ...
|
||||
* DOCME (formatting)
|
||||
* fluid_set_log_function(FLUID_PANIC, show_dialog, (void*) root_window);
|
||||
* fluid_set_log_function(ERR, NULL, NULL);
|
||||
* fluid_set_log_function(WARN, NULL, NULL);
|
||||
* fluid_set_log_function(FLUID_ERR, NULL, NULL);
|
||||
* fluid_set_log_function(FLUID_WARN, NULL, NULL);
|
||||
* fluid_set_log_function(FLUID_DBG, NULL, NULL);
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* FluidSynth log levels.
|
||||
*/
|
||||
enum fluid_log_level {
|
||||
FLUID_PANIC, /* the synth can't function correctly any more */
|
||||
FLUID_ERR, /* the synth can function, but with serious limitation */
|
||||
FLUID_WARN, /* the synth might not function as expected */
|
||||
FLUID_INFO, /* verbose messages */
|
||||
FLUID_DBG, /* debugging messages */
|
||||
FLUID_PANIC, /**< The synth can't function correctly any more */
|
||||
FLUID_ERR, /**< Serious error occurred */
|
||||
FLUID_WARN, /**< Warning */
|
||||
FLUID_INFO, /**< Verbose informational messages */
|
||||
FLUID_DBG, /**< Debugging messages */
|
||||
LAST_LOG_LEVEL
|
||||
};
|
||||
|
||||
/**
|
||||
* Log function handler callback type used by fluid_set_log_function().
|
||||
* @param level Log level (#fluid_log_level)
|
||||
* @param message Log message text
|
||||
* @param data User data pointer supplied to fluid_set_log_function().
|
||||
*/
|
||||
typedef void (*fluid_log_function_t)(int level, char* message, void* data);
|
||||
|
||||
/** fluid_set_log_function installs a new log function for the
|
||||
* specified level. It returns the previously installed function.
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void* data);
|
||||
|
||||
|
||||
/** fluid_default_log_function is the fluid's default log function. It
|
||||
* prints to the stderr. */
|
||||
FLUIDSYNTH_API void fluid_default_log_function(int level, char* message, void* data);
|
||||
|
||||
/** print a message to the log */
|
||||
FLUIDSYNTH_API int fluid_log(int level, char * fmt, ...);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,7 +25,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @file midi.h
|
||||
* @brief Functions for MIDI events, drivers and MIDI file playback.
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API fluid_midi_event_t* new_fluid_midi_event(void);
|
||||
FLUIDSYNTH_API int delete_fluid_midi_event(fluid_midi_event_t* event);
|
||||
@@ -48,7 +51,12 @@ FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val);
|
||||
|
||||
|
||||
/* Generic callback function for MIDI events.
|
||||
/**
|
||||
* Generic callback function for MIDI events.
|
||||
* @param data User defined data pointer
|
||||
* @param event The MIDI event
|
||||
* @return DOCME
|
||||
*
|
||||
* Will be used between
|
||||
* - MIDI driver and MIDI router
|
||||
* - MIDI router and synth
|
||||
@@ -57,49 +65,27 @@ FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val);
|
||||
*/
|
||||
typedef int (*handle_midi_event_func_t)(void* data, fluid_midi_event_t* event);
|
||||
|
||||
/*
|
||||
*
|
||||
/*
|
||||
* MIDI router
|
||||
*
|
||||
* The MIDI handler forwards incoming MIDI events to the synthesizer
|
||||
*
|
||||
*/
|
||||
|
||||
/** Create a new midi router. A midi handler connects to a midi input
|
||||
* device and forwards incoming midi events to the synthesizer.
|
||||
*/
|
||||
FLUIDSYNTH_API fluid_midi_router_t* new_fluid_midi_router(fluid_settings_t* settings,
|
||||
handle_midi_event_func_t handler,
|
||||
void* event_handler_data);
|
||||
|
||||
/** Delete the midi router.
|
||||
*
|
||||
* \param handler a pointer to the midi handler
|
||||
* \return 0 if no error occured, -1 otherwise
|
||||
*/
|
||||
FLUIDSYNTH_API int delete_fluid_midi_router(fluid_midi_router_t* handler);
|
||||
|
||||
/** The standard handler function. Every MIDI event goes through
|
||||
this. */
|
||||
FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event);
|
||||
|
||||
/** An optional link in the MIDI chain to dump MIDI data between MIDI
|
||||
driver and router */
|
||||
FLUIDSYNTH_API int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event);
|
||||
|
||||
/** An optional link in the MIDI chain to dump MIDI data between MIDI
|
||||
router and the synthesizer */
|
||||
FLUIDSYNTH_API int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event);
|
||||
|
||||
/*
|
||||
*
|
||||
* MIDI driver
|
||||
*
|
||||
* The MIDI handler forwards incoming MIDI events to the synthesizer
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
FLUIDSYNTH_API
|
||||
fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings,
|
||||
handle_midi_event_func_t handler,
|
||||
@@ -110,11 +96,9 @@ FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t* driver);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* MIDI file player
|
||||
*
|
||||
* The MIDI player allows you to play MIDI files with the FLUID Synth
|
||||
*
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API fluid_player_t* new_fluid_player(fluid_synth_t* synth);
|
||||
|
||||
@@ -144,9 +144,9 @@ struct _fluid_sample_t
|
||||
{
|
||||
char name[21];
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
unsigned int end; /* Note: Index of last valid sample point (contrary to SF spec) */
|
||||
unsigned int loopstart;
|
||||
unsigned int loopend;
|
||||
unsigned int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||
unsigned int samplerate;
|
||||
int origpitch;
|
||||
int pitchadj;
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FLUIDSYNTH_VERSION "1.0.7"
|
||||
#define FLUIDSYNTH_VERSION "1.0.8"
|
||||
#define FLUIDSYNTH_VERSION_MAJOR 1
|
||||
#define FLUIDSYNTH_VERSION_MINOR 0
|
||||
#define FLUIDSYNTH_VERSION_MICRO 7
|
||||
#define FLUIDSYNTH_VERSION_MICRO 8
|
||||
|
||||
|
||||
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
[:Development:]
|
||||
|
||||
Many people contributed to FluidSynth, send suggestions or bug
|
||||
Many people contributed to FluidSynth, sent suggestions or bug
|
||||
fixes. The project was started by Peter Hanappe who is the main
|
||||
author. Josh Green is the current maintainer. Below you'll find a
|
||||
summery of contributions.
|
||||
summary of contributions.
|
||||
|
||||
|
||||
* Peter Hanappe. Initiated the project. files: sticked his nose in all
|
||||
@@ -24,10 +24,6 @@ summery of contributions.
|
||||
(the blue waves with FluidSynth letters partially submerged).
|
||||
files: iiwu_defsfont.{c,h}, iiwu_alsa{c,h} and others.
|
||||
|
||||
* Stephane Letz from Grame wrote most of the MidiShare driver, all of
|
||||
the PortAudio driver, ported iiwusynth to MacOS X, and sent in many
|
||||
fixes. files: iiwu_midishare.c, iiwu_portaudio.c
|
||||
|
||||
* Markus Nentwig (re-)designed the resonant filter, the chorus, the
|
||||
LADSPA subsystem, the MIDI router, optimized for SSE, made many
|
||||
changes and bug fixes and got the synthesizer to actually work. Most
|
||||
@@ -36,6 +32,10 @@ summery of contributions.
|
||||
iiwu_sse.h, iiwu_dsp_core.h, iiwu_rev.{c,h}, and basically all the
|
||||
other files.
|
||||
|
||||
* Stephane Letz from Grame wrote most of the MidiShare driver, all of
|
||||
the PortAudio driver, ported iiwusynth to MacOS X, and sent in many
|
||||
fixes. files: iiwu_midishare.c, iiwu_portaudio.c
|
||||
|
||||
* Antoine Schmitt added the sequencer support, support for sample
|
||||
loading (RAM Sfont), developed the
|
||||
MacroMedia Director Xtra, and send in many many bug reports. Thanks
|
||||
@@ -67,8 +67,7 @@ summery of contributions.
|
||||
portability.
|
||||
|
||||
* The midi device uses code from jMax's alsarawmidi.c file and from
|
||||
Smurf's midi_alsaraw.c by Josh Green. Josh also added support for
|
||||
the alsa sequencer interface. file: iiwu_alsa.c
|
||||
Smurf's midi_alsaraw.c by Josh Green. file: iiwu_alsa.c
|
||||
|
||||
* The reverb algorithm was written by Jezar
|
||||
(http://www.dreampoint.co.uk). His code is public domain. The code
|
||||
@@ -115,3 +114,7 @@ Gerald Pye
|
||||
Rui Nuno Capela
|
||||
Frieder Bürzele
|
||||
Henri Manson
|
||||
Mihail Zenkov
|
||||
Paul Millar
|
||||
Nick Daly
|
||||
David Hilvert
|
||||
|
||||
@@ -14,6 +14,7 @@ SharedLibrary libfluidsynth.so :
|
||||
fluid_cmd.c
|
||||
fluid_conv.c
|
||||
fluid_defsfont.c
|
||||
fluid_dsp_float.c
|
||||
fluid_event.c
|
||||
fluid_gen.c
|
||||
fluid_hash.c
|
||||
@@ -28,7 +29,6 @@ SharedLibrary libfluidsynth.so :
|
||||
fluid_seq.c
|
||||
fluid_seqbind.c
|
||||
fluid_settings.c
|
||||
fluid_strtok.c
|
||||
fluid_synth.c
|
||||
fluid_sys.c
|
||||
fluid_tuning.c
|
||||
|
||||
@@ -245,6 +245,16 @@ void fluid_audio_driver_settings(fluid_settings_t* settings)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new audio driver.
|
||||
* @param settings Configuration settings used to select and create the audio
|
||||
* driver.
|
||||
* @param synth Synthesizer instance for which the audio driver is created for.
|
||||
* @return The new audio driver instance.
|
||||
*
|
||||
* Creates a new audio driver for a given 'synth' instance with a defined set
|
||||
* of configuration 'settings'.
|
||||
*/
|
||||
fluid_audio_driver_t*
|
||||
new_fluid_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
||||
{
|
||||
@@ -269,6 +279,19 @@ new_fluid_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new audio driver.
|
||||
* @param settings Configuration settings used to select and create the audio
|
||||
* driver.
|
||||
* @param func Function called to fill audio buffers for audio playback
|
||||
* @param data User defined data pointer to pass to 'func'
|
||||
* @return The new audio driver instance.
|
||||
*
|
||||
* Like new_fluid_audio_driver() but allows for custom audio processing before
|
||||
* audio is sent to audio driver. It is the responsibility of the callback
|
||||
* 'func' to render the audio into the buffers.
|
||||
* NOTE: Not as efficient as new_fluid_audio_driver().
|
||||
*/
|
||||
fluid_audio_driver_t*
|
||||
new_fluid_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data)
|
||||
{
|
||||
@@ -294,6 +317,12 @@ new_fluid_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, voi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an audio driver instance.
|
||||
* @param driver Audio driver instance to delete
|
||||
*
|
||||
* Shuts down an audio driver and deletes its instance.
|
||||
*/
|
||||
void
|
||||
delete_fluid_audio_driver(fluid_audio_driver_t* driver)
|
||||
{
|
||||
|
||||
@@ -157,39 +157,22 @@ int delete_fluid_file_audio_driver(fluid_audio_driver_t* p)
|
||||
static int fluid_file_audio_run_s16(void* d, unsigned int clock_time)
|
||||
{
|
||||
fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) d;
|
||||
float* handle[2];
|
||||
int i, k, n, offset;
|
||||
float s;
|
||||
int n, offset;
|
||||
unsigned int sample_time;
|
||||
|
||||
handle[0] = dev->left;
|
||||
handle[1] = dev->right;
|
||||
|
||||
|
||||
sample_time = (unsigned int) (dev->samples / dev->sample_rate * 1000.0);
|
||||
if (sample_time > clock_time) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
(*dev->callback)(dev->data, dev->period_size, 0, NULL, 2, handle);
|
||||
|
||||
for (i = 0, k = 0; i < dev->period_size; i++, k += 2) {
|
||||
s = 32768.0f * dev->left[i];
|
||||
fluid_clip(s, -32768.0f, 32767.0f);
|
||||
dev->buf[k] = (short) s;
|
||||
}
|
||||
|
||||
for (i = 0, k = 1; i < dev->period_size; i++, k += 2) {
|
||||
s = 32768.0f * dev->right[i];
|
||||
fluid_clip(s, -32768.0f, 32767.0f);
|
||||
dev->buf[k] = (short) s;
|
||||
}
|
||||
fluid_synth_write_s16(dev->data, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2);
|
||||
|
||||
for (offset = 0; offset < dev->buf_size; offset += n) {
|
||||
|
||||
n = fwrite((char*) dev->buf + offset, 1, dev->buf_size - offset, dev->file);
|
||||
if (n < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Audio file error");
|
||||
FLUID_LOG(FLUID_ERR, "Audio output file write error: %s",
|
||||
strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -197,8 +180,4 @@ static int fluid_file_audio_run_s16(void* d, unsigned int clock_time)
|
||||
dev->samples += dev->period_size;
|
||||
|
||||
return 1;
|
||||
|
||||
error_recovery:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ new_fluid_channel(fluid_synth_t* synth, int num)
|
||||
|
||||
chan->synth = synth;
|
||||
chan->channum = num;
|
||||
chan->preset = NULL;
|
||||
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan);
|
||||
@@ -54,7 +55,10 @@ fluid_channel_init(fluid_channel_t* chan)
|
||||
chan->prognum = (chan->channum == 9)? 0 : chan->channum;
|
||||
chan->banknum = (chan->channum == 9)? 128 : 0;
|
||||
chan->sfontnum = 0;
|
||||
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
chan->preset = fluid_synth_find_preset(chan->synth, chan->banknum, chan->prognum);
|
||||
|
||||
chan->interp_method = FLUID_INTERP_DEFAULT;
|
||||
chan->tuning = NULL;
|
||||
chan->nrpn_select = 0;
|
||||
@@ -106,6 +110,7 @@ fluid_channel_reset(fluid_channel_t* chan)
|
||||
int
|
||||
delete_fluid_channel(fluid_channel_t* chan)
|
||||
{
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
FLUID_FREE(chan);
|
||||
return FLUID_OK;
|
||||
}
|
||||
@@ -119,6 +124,7 @@ 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);
|
||||
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
chan->preset = preset;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
@@ -467,8 +467,8 @@ void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
|
||||
/* The & in chorusbuf[...] is equivalent to a division modulo
|
||||
MAX_SAMPLES, only faster. */
|
||||
d_out += (chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
|
||||
* chorus->sinc_table[ii][pos_subsamples]);
|
||||
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
|
||||
* chorus->sinc_table[ii][pos_subsamples];
|
||||
|
||||
pos_samples--;
|
||||
};
|
||||
@@ -490,7 +490,7 @@ void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
} /* foreach sample */
|
||||
}
|
||||
|
||||
/* Duplication of code ... */
|
||||
/* Duplication of code ... (replaces sample data instead of mixing) */
|
||||
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
@@ -535,7 +535,8 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
|
||||
/* The & in chorusbuf[...] is equivalent to a division modulo
|
||||
MAX_SAMPLES, only faster. */
|
||||
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK] * chorus->sinc_table[ii][pos_subsamples];
|
||||
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
|
||||
* chorus->sinc_table[ii][pos_subsamples];
|
||||
|
||||
pos_samples--;
|
||||
};
|
||||
@@ -546,7 +547,7 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
|
||||
d_out *= chorus->level;
|
||||
|
||||
/* Add the chorus sum d_out to output */
|
||||
/* Store the chorus sum d_out to output */
|
||||
left_out[sample_index] = d_out;
|
||||
right_out[sample_index] = d_out;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_cmd.h"
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_strtok.h"
|
||||
#include "fluid_settings.h"
|
||||
#include "fluid_io.h"
|
||||
#include "fluid_hash.h"
|
||||
@@ -36,6 +35,7 @@
|
||||
#endif
|
||||
|
||||
#define MAX_TOKENS 100 /* LADSPA plugins need lots of parameters */
|
||||
#define MAX_COMMAND_LEN 1024 /* max command length accepted by fluid_command() */
|
||||
#define FLUID_WORKLINELENGTH 1024 /* LADSPA plugins use long command lines */
|
||||
|
||||
void fluid_shell_settings(fluid_settings_t* settings)
|
||||
@@ -157,43 +157,42 @@ fluid_cmd_t fluid_commands[] = {
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int fluid_command2(fluid_strtok_t* strtok, fluid_cmd_handler_t* handler,
|
||||
char* cmd, fluid_ostream_t out);
|
||||
|
||||
/**
|
||||
* Process a string command.
|
||||
* NOTE: FluidSynth 1.0.8+ no longer modifies the 'cmd' string.
|
||||
* @param handle FluidSynth command handler
|
||||
* @param cmd Command string (NOTE: Gets modified by FluidSynth prior to 1.0.8)
|
||||
* @param out Output stream to display command response to
|
||||
* @return Integer value corresponding to: -1 on command error, 0 on success,
|
||||
* 1 if 'cmd' is a comment or is empty and -2 if quit was issued
|
||||
*/
|
||||
int
|
||||
fluid_command(fluid_cmd_handler_t* handler, char* cmd, fluid_ostream_t out)
|
||||
{
|
||||
int ret;
|
||||
|
||||
fluid_strtok_t* st = new_fluid_strtok(cmd, " \t\n\r");
|
||||
if (st == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fluid_command2(st, handler, cmd, out);
|
||||
delete_fluid_strtok(st);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
fluid_command2(fluid_strtok_t* st, fluid_cmd_handler_t* handler, char* cmd, fluid_ostream_t out)
|
||||
{
|
||||
char* token[MAX_TOKENS];
|
||||
char buf[MAX_COMMAND_LEN+1];
|
||||
char *strtok, *tok;
|
||||
int num_tokens = 0;
|
||||
|
||||
if (cmd[0] == '#') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* tokenize the input line */
|
||||
fluid_strtok_set(st, cmd, " \t\n\r");
|
||||
while (fluid_strtok_has_more(st)) {
|
||||
token[num_tokens++] = fluid_strtok_next_token(st);
|
||||
if (strlen (cmd) > MAX_COMMAND_LEN)
|
||||
{
|
||||
fluid_ostream_printf(out, "Command exceeded max length of %d chars\n",
|
||||
MAX_COMMAND_LEN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num_tokens == 0) {
|
||||
return 1;
|
||||
}
|
||||
FLUID_STRCPY(buf, cmd); /* copy - since fluid_strtok thrashes it */
|
||||
strtok = buf;
|
||||
|
||||
/* tokenize the input line */
|
||||
while ((tok = fluid_strtok (&strtok, " \t\n\r")))
|
||||
token[num_tokens++] = tok;
|
||||
|
||||
if (num_tokens == 0) return 1;
|
||||
|
||||
/* handle the command */
|
||||
return fluid_cmd_handler_handle(handler, num_tokens, &token[0], out);
|
||||
@@ -203,7 +202,6 @@ struct _fluid_shell_t {
|
||||
fluid_settings_t* settings;
|
||||
fluid_cmd_handler_t* handler;
|
||||
fluid_thread_t* thread;
|
||||
fluid_strtok_t* st;
|
||||
fluid_istream_t in;
|
||||
fluid_ostream_t out;
|
||||
};
|
||||
@@ -247,7 +245,6 @@ void fluid_shell_init(fluid_shell_t* shell,
|
||||
{
|
||||
shell->settings = settings;
|
||||
shell->handler = handler;
|
||||
shell->st = new_fluid_strtok(NULL, NULL);
|
||||
shell->in = in;
|
||||
shell->out = out;
|
||||
}
|
||||
@@ -257,6 +254,7 @@ void delete_fluid_shell(fluid_shell_t* shell)
|
||||
if (shell->thread != NULL) {
|
||||
delete_fluid_thread(shell->thread);
|
||||
}
|
||||
|
||||
FLUID_FREE(shell);
|
||||
}
|
||||
|
||||
@@ -289,7 +287,7 @@ int fluid_shell_run(fluid_shell_t* shell)
|
||||
#endif
|
||||
|
||||
/* handle the command */
|
||||
switch (fluid_command2(shell->st, shell->handler, workline, shell->out)) {
|
||||
switch (fluid_command(shell->handler, workline, shell->out)) {
|
||||
|
||||
case 1: /* empty line or comment */
|
||||
break;
|
||||
|
||||
@@ -159,7 +159,9 @@ int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* pr
|
||||
int fluid_defpreset_preset_delete(fluid_preset_t* preset)
|
||||
{
|
||||
FLUID_FREE(preset);
|
||||
/* printf("TODO: free modulators\n"); */
|
||||
|
||||
/* TODO: free modulators */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -301,21 +303,20 @@ int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file)
|
||||
sfont->samplesize = sfdata->samplesize;
|
||||
|
||||
/* load sample data in one block */
|
||||
if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK)
|
||||
goto err_exit;
|
||||
|
||||
/* Create all the sample headers */
|
||||
p = sfdata->sample;
|
||||
while (p != NULL) {
|
||||
sfsample = (SFSample *) p->data;
|
||||
|
||||
sample = new_fluid_sample();
|
||||
if (sample == NULL) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
if (sample == NULL) goto err_exit;
|
||||
|
||||
if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK)
|
||||
goto err_exit;
|
||||
|
||||
fluid_defsfont_add_sample(sfont, sample);
|
||||
fluid_voice_optimize_sample(sample);
|
||||
p = fluid_list_next(p);
|
||||
@@ -326,18 +327,21 @@ int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file)
|
||||
while (p != NULL) {
|
||||
sfpreset = (SFPreset *) p->data;
|
||||
preset = new_fluid_defpreset(sfont);
|
||||
if (preset == NULL) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK) {
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
if (preset == NULL) goto err_exit;
|
||||
|
||||
if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK)
|
||||
goto err_exit;
|
||||
|
||||
fluid_defsfont_add_preset(sfont, preset);
|
||||
p = fluid_list_next(p);
|
||||
}
|
||||
sfont_free_data(sfdata);
|
||||
sfont_close (sfdata);
|
||||
|
||||
return FLUID_OK;
|
||||
|
||||
err_exit:
|
||||
sfont_close (sfdata);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* fluid_defsfont_add_sample
|
||||
@@ -949,6 +953,18 @@ new_fluid_preset_zone(char *name)
|
||||
int
|
||||
delete_fluid_preset_zone(fluid_preset_zone_t* zone)
|
||||
{
|
||||
fluid_mod_t *mod, *tmp;
|
||||
|
||||
mod = zone->mod;
|
||||
while (mod) /* delete the modulators */
|
||||
{
|
||||
tmp = mod;
|
||||
mod = mod->next;
|
||||
fluid_mod_delete (tmp);
|
||||
}
|
||||
|
||||
if (zone->name) FLUID_FREE (zone->name);
|
||||
if (zone->inst) delete_fluid_inst (zone->inst);
|
||||
FLUID_FREE(zone);
|
||||
return FLUID_OK;
|
||||
}
|
||||
@@ -1331,6 +1347,17 @@ new_fluid_inst_zone(char* name)
|
||||
int
|
||||
delete_fluid_inst_zone(fluid_inst_zone_t* zone)
|
||||
{
|
||||
fluid_mod_t *mod, *tmp;
|
||||
|
||||
mod = zone->mod;
|
||||
while (mod) /* delete the modulators */
|
||||
{
|
||||
tmp = mod;
|
||||
mod = mod->next;
|
||||
fluid_mod_delete (tmp);
|
||||
}
|
||||
|
||||
if (zone->name) FLUID_FREE (zone->name);
|
||||
FLUID_FREE(zone);
|
||||
return FLUID_OK;
|
||||
}
|
||||
@@ -1770,8 +1797,12 @@ sfload_file (const char * fname)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!(sf = safe_malloc (sizeof (SFData))))
|
||||
if (!(sf = FLUID_NEW (SFData)))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
err = TRUE;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
memset (sf, 0, sizeof (SFData)); /* zero sfdata */
|
||||
@@ -1942,8 +1973,11 @@ process_info (int size, SFData * sf, FILE * fd)
|
||||
" of %d bytes"), &chunk.id, chunk.size));
|
||||
|
||||
/* alloc for chunk id and da chunk */
|
||||
if (!(item = safe_malloc (chunk.size + 1)))
|
||||
if (!(item = FLUID_MALLOC (chunk.size + 1)))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return (FAIL);
|
||||
}
|
||||
|
||||
/* attach to INFO list, sfont_close will cleanup if FAIL occurs */
|
||||
sf->info = fluid_list_append (sf->info, item);
|
||||
@@ -2979,21 +3013,15 @@ unsigned short badpgen[] = { Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddr
|
||||
Gen_OverrideRootKey, 0
|
||||
};
|
||||
|
||||
/* close SoundFont file and delete a SoundFont structure */
|
||||
void
|
||||
sfont_close (SFData * sf)
|
||||
{
|
||||
fluid_list_t *p, *p2;
|
||||
|
||||
if (sf->sffd)
|
||||
fclose (sf->sffd);
|
||||
|
||||
sfont_free_data (sf);
|
||||
}
|
||||
|
||||
/* delete a sound font structure */
|
||||
void
|
||||
sfont_free_data (SFData * sf)
|
||||
{
|
||||
fluid_list_t *p, *p2;
|
||||
|
||||
if (sf->fname)
|
||||
free (sf->fname);
|
||||
|
||||
@@ -3035,8 +3063,19 @@ sfont_free_data (SFData * sf)
|
||||
FLUID_FREE (p->data);
|
||||
p = fluid_list_next (p);
|
||||
}
|
||||
delete_fluid_list (sf->inst);
|
||||
sf->inst = NULL;
|
||||
|
||||
p = sf->sample;
|
||||
while (p)
|
||||
{
|
||||
FLUID_FREE (p->data);
|
||||
p = fluid_list_next (p);
|
||||
}
|
||||
delete_fluid_list (sf->sample);
|
||||
sf->sample = NULL;
|
||||
|
||||
FLUID_FREE (sf);
|
||||
}
|
||||
|
||||
/* free all elements of a zone (Preset or Instrument) */
|
||||
@@ -3173,13 +3212,3 @@ safe_fseek (FILE * fd, long ofs, int whence)
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
|
||||
void *
|
||||
safe_malloc (size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (!(ptr = malloc (size)))
|
||||
FLUID_LOG (FLUID_ERR, _("Attempted to allocate %d bytes"), (int) size);
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,6 @@ extern unsigned short badpgen[]; /* list of bad preset generators */
|
||||
void sfont_init_chunks (void);
|
||||
|
||||
void sfont_close (SFData * sf);
|
||||
void sfont_free_data (SFData * sf);
|
||||
void sfont_free_zone (SFZone * zone);
|
||||
int sfont_preset_compare_func (void* a, void* b);
|
||||
|
||||
@@ -427,7 +426,6 @@ enum
|
||||
#define ErrnoEnd ErrWrite
|
||||
|
||||
int gerr (int ev, char * fmt, ...);
|
||||
void *safe_malloc (size_t size);
|
||||
int safe_fread (void *buf, int count, FILE * fd);
|
||||
int safe_fwrite (void *buf, int count, FILE * fd);
|
||||
int safe_fseek (FILE * fd, long ofs, int whence);
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/* 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
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_SSE
|
||||
#include "fluid_dsp_sse.c"
|
||||
#else
|
||||
/* #include "fluid_dsp_simple.c" */
|
||||
#include "fluid_dsp_float.c"
|
||||
#endif
|
||||
@@ -18,43 +18,16 @@
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_phase.h"
|
||||
|
||||
/* Purpose:
|
||||
* Low-level voice processing:
|
||||
*
|
||||
* - interpolates (obtains values between the samples of the original waveform data)
|
||||
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
|
||||
* - mixes the processed sample to left and right output using the pan setting
|
||||
* - sends the processed sample to chorus and reverb
|
||||
* Interpolates audio data (obtains values between the samples of the original
|
||||
* waveform data).
|
||||
*
|
||||
*
|
||||
* This file does -not- generate an object file.
|
||||
* Instead, it is #included in several places in fluid_voice.c.
|
||||
* The motivation for this is
|
||||
* - Calling it as a subroutine may be time consuming, especially with optimization off
|
||||
* - The previous implementation as a macro was clumsy to handle
|
||||
*
|
||||
*
|
||||
* Fluid_voice.c sets a couple of variables before #including this:
|
||||
* Variables loaded from the voice structure (assigned in fluid_voice_write()):
|
||||
* - dsp_data: Pointer to the original waveform data
|
||||
* - dsp_left_buf: The generated signal goes here, left channel
|
||||
* - dsp_right_buf: right channel
|
||||
* - dsp_reverb_buf: Send to reverb unit
|
||||
* - dsp_chorus_buf: Send to chorus unit
|
||||
* - dsp_start: Start processing at this output buffer index
|
||||
* - dsp_end: End processing just before this output buffer index
|
||||
* - dsp_a1: Coefficient for the filter
|
||||
* - dsp_a2: same
|
||||
* - dsp_b0: same
|
||||
* - dsp_b1: same
|
||||
* - dsp_b2: same
|
||||
* - dsp_filter_flag: Set, the filter is needed (many sound fonts don't use
|
||||
* the filter at all. If it is left at its default setting
|
||||
* of roughly 20 kHz, there is no need to apply filterling.)
|
||||
* - dsp_interp_method: Which interpolation method to use.
|
||||
* - voice holds the voice structure
|
||||
*
|
||||
* Some variables are set and modified:
|
||||
* - dsp_phase: The position in the original waveform data.
|
||||
* This has an integer and a fractional part (between samples).
|
||||
* - dsp_phase_incr: For each output sample, the position in the original
|
||||
@@ -67,215 +40,648 @@
|
||||
*
|
||||
* A couple of variables are used internally, their results are discarded:
|
||||
* - dsp_i: Index through the output buffer
|
||||
* - dsp_phase_fractional: The fractional part of dsp_phase
|
||||
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
|
||||
* Used to interpolate between samples.
|
||||
* - dsp_process_buffer: Holds the processed signal between stages
|
||||
* - dsp_centernode: delay line for the IIR filter
|
||||
* - dsp_hist1: same
|
||||
* - dsp_hist2: same
|
||||
*
|
||||
* - dsp_buf: Output buffer of floating point values (FLUID_BUFSIZE in length)
|
||||
*/
|
||||
|
||||
/* Purpose:
|
||||
* zap_almost_zero will return a number, as long as its
|
||||
* absolute value is over a certain threshold. Otherwise 0. See
|
||||
* fluid_rev.c for documentation (denormal numbers)
|
||||
*/
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_voice.h"
|
||||
|
||||
# if defined(WITH_FLOAT)
|
||||
# define zap_almost_zero(_sample) \
|
||||
((((*(unsigned int*)&(_sample))&0x7f800000) < 0x08000000)? 0.0f : (_sample))
|
||||
# else
|
||||
/* 1e-20 was chosen as an arbitrary (small) threshold. */
|
||||
#define zap_almost_zero(_sample) ((abs(_sample) < 1e-20)? 0.0f : (_sample))
|
||||
#endif
|
||||
|
||||
/* Interpolation (find a value between two samples of the original waveform) */
|
||||
|
||||
if ((fluid_phase_fract(dsp_phase) == 0)
|
||||
&& (fluid_phase_fract(dsp_phase_incr) == 0)
|
||||
&& (fluid_phase_index(dsp_phase_incr) == 1)) {
|
||||
/* Linear interpolation table (2 coefficients centered on 1st) */
|
||||
static fluid_real_t interp_coeff_linear[FLUID_INTERP_MAX][2];
|
||||
|
||||
/* Check for a special case: The current phase falls directly on an
|
||||
* original sample. Also, the stepsize per output sample is exactly
|
||||
* one sample, no fractional part. In other words: The sample is
|
||||
* played back at normal phase and root pitch. => No interpolation
|
||||
* needed.
|
||||
*/
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
/* Mix to the buffer and advance the phase by one sample */
|
||||
dsp_buf[dsp_i] = dsp_amp * dsp_data[fluid_phase_index_plusplus(dsp_phase)];
|
||||
dsp_amp += dsp_amp_incr;
|
||||
/* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */
|
||||
static fluid_real_t interp_coeff[FLUID_INTERP_MAX][4];
|
||||
|
||||
/* 7th order interpolation (7 coefficients centered on 3rd) */
|
||||
static fluid_real_t sinc_table7[FLUID_INTERP_MAX][7];
|
||||
|
||||
|
||||
#define SINC_INTERP_ORDER 7 /* 7th order constant */
|
||||
|
||||
|
||||
/* Initializes interpolation tables */
|
||||
void fluid_dsp_float_config (void)
|
||||
{
|
||||
int i, i2;
|
||||
double x, v;
|
||||
double i_shifted;
|
||||
|
||||
/* Initialize the coefficients for the interpolation. The math comes
|
||||
* from a mail, posted by Olli Niemitalo to the music-dsp mailing
|
||||
* list (I found it in the music-dsp archives
|
||||
* http://www.smartelectronix.com/musicdsp/). */
|
||||
|
||||
for (i = 0; i < FLUID_INTERP_MAX; i++)
|
||||
{
|
||||
x = (double) i / (double) FLUID_INTERP_MAX;
|
||||
|
||||
interp_coeff[i][0] = (fluid_real_t)(x * (-0.5 + x * (1 - 0.5 * x)));
|
||||
interp_coeff[i][1] = (fluid_real_t)(1.0 + x * x * (1.5 * x - 2.5));
|
||||
interp_coeff[i][2] = (fluid_real_t)(x * (0.5 + x * (2.0 - 1.5 * x)));
|
||||
interp_coeff[i][3] = (fluid_real_t)(0.5 * x * x * (x - 1.0));
|
||||
|
||||
interp_coeff_linear[i][0] = (fluid_real_t)(1.0 - x);
|
||||
interp_coeff_linear[i][1] = (fluid_real_t)x;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* i: Offset in terms of whole samples */
|
||||
for (i = 0; i < SINC_INTERP_ORDER; i++)
|
||||
{ /* i2: Offset in terms of fractional samples ('subsamples') */
|
||||
for (i2 = 0; i2 < FLUID_INTERP_MAX; i2++)
|
||||
{
|
||||
/* center on middle of table */
|
||||
i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
|
||||
+ (double)i2 / (double)FLUID_INTERP_MAX;
|
||||
|
||||
/* wave table interpolation: Choose the interpolation method */
|
||||
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
|
||||
if (fabs (i_shifted) > 0.000001)
|
||||
{
|
||||
v = (fluid_real_t)sin (i_shifted * M_PI) / (M_PI * i_shifted);
|
||||
/* Hamming window */
|
||||
v *= (fluid_real_t)0.5 * (1.0 + cos (2.0 * M_PI * i_shifted / (fluid_real_t)SINC_INTERP_ORDER));
|
||||
}
|
||||
else v = 1.0;
|
||||
|
||||
switch(dsp_interp_method){
|
||||
case FLUID_INTERP_NONE:
|
||||
/* No interpolation. Just take the sample, which is closest to
|
||||
sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < FLUID_INTERP_MAX; i++)
|
||||
{
|
||||
printf ("%d %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",
|
||||
i, sinc_table7[0][i], sinc_table7[1][i], sinc_table7[2][i],
|
||||
sinc_table7[3][i], sinc_table7[4][i], sinc_table7[5][i], sinc_table7[6][i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
fluid_check_fpe("interpolation table calculation");
|
||||
}
|
||||
|
||||
|
||||
/* No interpolation. Just take the sample, which is closest to
|
||||
* the playback pointer. Questionable quality, but very
|
||||
* efficient. */
|
||||
int
|
||||
fluid_dsp_float_interpolate_none (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr, end_phase;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int end_index;
|
||||
int looping;
|
||||
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
end_index = looping ? voice->loopend - 1 : voice->end;
|
||||
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
|
||||
|
||||
/* interpolate sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
};
|
||||
break;
|
||||
|
||||
case FLUID_INTERP_LINEAR:
|
||||
/* Straight line interpolation. */
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
dsp_coeff = &interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)];
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
dsp_buf[dsp_i] = (dsp_amp *
|
||||
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
|
||||
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]));
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
};
|
||||
break;
|
||||
|
||||
case FLUID_INTERP_4THORDER:
|
||||
default:
|
||||
/* Default interpolation loop using floats */
|
||||
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
dsp_coeff = &interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
|
||||
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
dsp_buf[dsp_i] = (dsp_amp *
|
||||
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
|
||||
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]
|
||||
+ dsp_coeff->a2 * dsp_data[dsp_phase_index+2]
|
||||
+ dsp_coeff->a3 * dsp_data[dsp_phase_index+3]));
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
break;
|
||||
|
||||
/* break out if not looping (buffer may not be full) */
|
||||
if (!looping) break;
|
||||
|
||||
case FLUID_INTERP_7THORDER:
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
int fract = fluid_phase_fract_to_tablerow(dsp_phase);
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
dsp_buf[dsp_i] = (dsp_amp *
|
||||
(sinc_table7[0][fract] * (fluid_real_t) dsp_data[dsp_phase_index]
|
||||
+ sinc_table7[1][fract] * (fluid_real_t) dsp_data[dsp_phase_index+1]
|
||||
+ sinc_table7[2][fract] * (fluid_real_t) dsp_data[dsp_phase_index+2]
|
||||
+ sinc_table7[3][fract] * (fluid_real_t) dsp_data[dsp_phase_index+3]
|
||||
+ sinc_table7[4][fract] * (fluid_real_t) dsp_data[dsp_phase_index+4]
|
||||
+ sinc_table7[5][fract] * (fluid_real_t) dsp_data[dsp_phase_index+5]
|
||||
+ sinc_table7[6][fract] * (fluid_real_t) dsp_data[dsp_phase_index+6]));
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
/* go back to loop start */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
voice->has_looped = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
} /* switch interpolation method */
|
||||
} /* If interpolation is needed */
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
}
|
||||
|
||||
/* filter (implement the voice filter according to Soundfont standard) */
|
||||
if (dsp_use_filter_flag) {
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
/* Check for denormal number (too close to zero) once in a
|
||||
* while. This is not a big concern here - why would someone play a
|
||||
* sample with an empty tail? */
|
||||
dsp_hist1 = zap_almost_zero(dsp_hist1);
|
||||
return (dsp_i);
|
||||
}
|
||||
|
||||
/* Two versions of the filter loop. One, while the filter is
|
||||
* changing towards its new setting. The other, if the filter
|
||||
* doesn't change.
|
||||
/* Straight line interpolation.
|
||||
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
|
||||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_dsp_float_interpolate_linear (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr, end_phase;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int end_index;
|
||||
short int point;
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
|
||||
if (dsp_filter_coeff_incr_count > 0) {
|
||||
/* The increment is added to each filter coefficient
|
||||
filter_coeff_incr_count times. */
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
/* The filter is implemented in Direct-II form. */
|
||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
||||
dsp_hist2 = dsp_hist1;
|
||||
dsp_hist1 = dsp_centernode;
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
if (dsp_filter_coeff_incr_count-- > 0){
|
||||
dsp_a1 += dsp_a1_incr;
|
||||
dsp_a2 += dsp_a2_incr;
|
||||
dsp_b02 += dsp_b02_incr;
|
||||
dsp_b1 += dsp_b1_incr;
|
||||
/* last index before 2nd interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
|
||||
|
||||
/* 2nd interpolation point to use at end of loop or sample */
|
||||
if (looping) point = dsp_data[voice->loopstart]; /* loop start */
|
||||
else point = dsp_data[voice->end]; /* duplicate end for samples no longer looping */
|
||||
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
|
||||
/* interpolate the sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index+1]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
} /* for dsp_i */
|
||||
|
||||
} else {
|
||||
/* break out if buffer filled */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
/* The filter parameters are constant. This is duplicated to save
|
||||
* time. */
|
||||
end_index++; /* we're now interpolating the last point */
|
||||
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
/* The filter is implemented in Direct-II form. */
|
||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
||||
dsp_hist2 = dsp_hist1;
|
||||
dsp_hist1 = dsp_centernode;
|
||||
/* interpolate within last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[1] * point);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr; /* increment amplitude */
|
||||
}
|
||||
} /* if filter is fixed */
|
||||
} /* if filter is enabled */
|
||||
|
||||
if (!looping) break; /* break out if not looping (end of sample) */
|
||||
|
||||
/* go back to loop start (if past */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
voice->has_looped = 1;
|
||||
}
|
||||
|
||||
/* pan (Copy the signal to the left and right output buffer) The voice
|
||||
* panning generator has a range of -500 .. 500. If it is centered,
|
||||
* it's close to 0. voice->amp_left and voice->amp_right are then the
|
||||
* same, and we can save one multiplication per voice and sample.
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index--; /* set end back to second to last sample point */
|
||||
}
|
||||
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
return (dsp_i);
|
||||
}
|
||||
|
||||
/* 4th order (cubic) interpolation.
|
||||
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
|
||||
* smaller if end of sample occurs).
|
||||
*/
|
||||
if ((-0.5 < voice->pan) && (voice->pan < 0.5)) {
|
||||
int
|
||||
fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr, end_phase;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int start_index, end_index;
|
||||
short int start_point, end_point1, end_point2;
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
|
||||
/* The voice is centered. Use voice->amp_left twice. */
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
float v = voice->amp_left * dsp_buf[dsp_i];
|
||||
dsp_left_buf[dsp_i] += v;
|
||||
dsp_right_buf[dsp_i] += v;
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
/* last index before 4th interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
|
||||
|
||||
if (voice->has_looped) /* set start_index and start point if looped or not */
|
||||
{
|
||||
start_index = voice->loopstart;
|
||||
start_point = dsp_data[voice->loopend - 1]; /* last point in loop (wrap around) */
|
||||
}
|
||||
else
|
||||
{
|
||||
start_index = voice->start;
|
||||
start_point = dsp_data[voice->start]; /* just duplicate the point */
|
||||
}
|
||||
|
||||
} else {
|
||||
/* get points off the end (loop start if looping, duplicate point if end) */
|
||||
if (looping)
|
||||
{
|
||||
end_point1 = dsp_data[voice->loopstart];
|
||||
end_point2 = dsp_data[voice->loopstart + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
end_point1 = dsp_data[voice->end];
|
||||
end_point2 = end_point1;
|
||||
}
|
||||
|
||||
/* The voice is not centered. For stereo samples, one of the
|
||||
* amplitudes will be zero. */
|
||||
if (voice->amp_left != 0.0){
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
dsp_left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i];
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
|
||||
/* interpolate first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * start_point
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* interpolate the sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* break out if buffer filled */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index++; /* we're now interpolating the 2nd to last point */
|
||||
|
||||
/* interpolate within 2nd to last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[3] * end_point1);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
end_index++; /* we're now interpolating the last point */
|
||||
|
||||
/* interpolate within the last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[1] * dsp_data[dsp_phase_index]
|
||||
+ coeffs[2] * end_point1
|
||||
+ coeffs[3] * end_point2);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
if (!looping) break; /* break out if not looping (end of sample) */
|
||||
|
||||
/* go back to loop start */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
|
||||
if (!voice->has_looped)
|
||||
{
|
||||
voice->has_looped = 1;
|
||||
start_index = voice->loopstart;
|
||||
start_point = dsp_data[voice->loopend - 1];
|
||||
}
|
||||
}
|
||||
if (voice->amp_right != 0.0){
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
dsp_right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i];
|
||||
}
|
||||
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index -= 2; /* set end back to third to last sample point */
|
||||
}
|
||||
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
return (dsp_i);
|
||||
}
|
||||
|
||||
/* reverb send. Buffer may be NULL. */
|
||||
if ((dsp_reverb_buf != NULL) && (voice->amp_reverb != 0.0)) {
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i];
|
||||
}
|
||||
}
|
||||
/* 7th order interpolation.
|
||||
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
|
||||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr, end_phase;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int start_index, end_index;
|
||||
short int start_points[3];
|
||||
short int end_points[3];
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
|
||||
/* chorus send. Buffer may be NULL. */
|
||||
if ((dsp_chorus_buf != NULL) && (voice->amp_chorus != 0)) {
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i];
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* add 1/2 sample to dsp_phase since 7th order interpolation is centered on
|
||||
* the 4th sample point */
|
||||
fluid_phase_incr (dsp_phase, (fluid_phase_t)0x80000000);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|
||||
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
/* last index before 7th interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
|
||||
|
||||
if (voice->has_looped) /* set start_index and start point if looped or not */
|
||||
{
|
||||
start_index = voice->loopstart;
|
||||
start_points[0] = dsp_data[voice->loopend - 1];
|
||||
start_points[1] = dsp_data[voice->loopend - 2];
|
||||
start_points[2] = dsp_data[voice->loopend - 3];
|
||||
}
|
||||
else
|
||||
{
|
||||
start_index = voice->start;
|
||||
start_points[0] = dsp_data[voice->start]; /* just duplicate the start point */
|
||||
start_points[1] = start_points[0];
|
||||
start_points[2] = start_points[0];
|
||||
}
|
||||
|
||||
/* get the 3 points off the end (loop start if looping, duplicate point if end) */
|
||||
if (looping)
|
||||
{
|
||||
end_points[0] = dsp_data[voice->loopstart];
|
||||
end_points[1] = dsp_data[voice->loopstart + 1];
|
||||
end_points[2] = dsp_data[voice->loopstart + 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
end_points[0] = dsp_data[voice->end];
|
||||
end_points[1] = end_points[0];
|
||||
end_points[2] = end_points[0];
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
|
||||
/* interpolate first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)start_points[2]
|
||||
+ coeffs[1] * (fluid_real_t)start_points[1]
|
||||
+ coeffs[2] * (fluid_real_t)start_points[0]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
start_index++;
|
||||
|
||||
/* interpolate 2nd to first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)start_points[1]
|
||||
+ coeffs[1] * (fluid_real_t)start_points[0]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
start_index++;
|
||||
|
||||
/* interpolate 3rd to first sample point (start or loop start) if needed */
|
||||
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)start_points[0]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
start_index -= 2; /* set back to original start index */
|
||||
|
||||
|
||||
/* interpolate the sequence of sample points */
|
||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
/* break out if buffer filled */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index++; /* we're now interpolating the 3rd to last point */
|
||||
|
||||
/* interpolate within 3rd to last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
|
||||
+ coeffs[6] * (fluid_real_t)end_points[0]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
end_index++; /* we're now interpolating the 2nd to last point */
|
||||
|
||||
/* interpolate within 2nd to last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
|
||||
+ coeffs[5] * (fluid_real_t)end_points[0]
|
||||
+ coeffs[6] * (fluid_real_t)end_points[1]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
end_index++; /* we're now interpolating the last point */
|
||||
|
||||
/* interpolate within last point */
|
||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||
|
||||
dsp_buf[dsp_i] = dsp_amp
|
||||
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
|
||||
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
|
||||
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
|
||||
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
|
||||
+ coeffs[4] * (fluid_real_t)end_points[0]
|
||||
+ coeffs[5] * (fluid_real_t)end_points[1]
|
||||
+ coeffs[6] * (fluid_real_t)end_points[2]);
|
||||
|
||||
/* increment phase and amplitude */
|
||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||
dsp_phase_index = fluid_phase_index (dsp_phase);
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
if (!looping) break; /* break out if not looping (end of sample) */
|
||||
|
||||
/* go back to loop start */
|
||||
if (dsp_phase_index > end_index)
|
||||
{
|
||||
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
|
||||
|
||||
if (!voice->has_looped)
|
||||
{
|
||||
voice->has_looped = 1;
|
||||
start_index = voice->loopstart;
|
||||
start_points[0] = dsp_data[voice->loopend - 1];
|
||||
start_points[1] = dsp_data[voice->loopend - 2];
|
||||
start_points[2] = dsp_data[voice->loopend - 3];
|
||||
}
|
||||
}
|
||||
|
||||
/* break out if filled buffer */
|
||||
if (dsp_i >= FLUID_BUFSIZE) break;
|
||||
|
||||
end_index -= 3; /* set end back to 4th to last sample point */
|
||||
}
|
||||
|
||||
/* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on
|
||||
* the 4th sample point (correct back to real value) */
|
||||
fluid_phase_decr (dsp_phase, (fluid_phase_t)0x80000000);
|
||||
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
|
||||
return (dsp_i);
|
||||
}
|
||||
|
||||
@@ -1,387 +0,0 @@
|
||||
/* 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
|
||||
*/
|
||||
|
||||
|
||||
/* Purpose:
|
||||
* Low-level voice processing:
|
||||
*
|
||||
* - interpolates (obtains values between the samples of the original waveform data)
|
||||
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
|
||||
* - mixes the processed sample to left and right output using the pan setting
|
||||
* - sends the processed sample to chorus and reverb
|
||||
*
|
||||
*
|
||||
* This file does -not- generate an object file.
|
||||
* Instead, it is #included in several places in fluid_voice.c.
|
||||
* The motivation for this is
|
||||
* - Calling it as a subroutine may be time consuming, especially with optimization off
|
||||
* - The previous implementation as a macro was clumsy to handle
|
||||
*
|
||||
*
|
||||
* Fluid_voice.c sets a couple of variables before #including this:
|
||||
* - dsp_data: Pointer to the original waveform data
|
||||
* - dsp_left_buf: The generated signal goes here, left channel
|
||||
* - dsp_right_buf: right channel
|
||||
* - dsp_reverb_buf: Send to reverb unit
|
||||
* - dsp_chorus_buf: Send to chorus unit
|
||||
* - dsp_start: Start processing at this output buffer index
|
||||
* - dsp_end: End processing just before this output buffer index
|
||||
* - dsp_a1: Coefficient for the filter
|
||||
* - dsp_a2: same
|
||||
* - dsp_b0: same
|
||||
* - dsp_b1: same
|
||||
* - dsp_b2: same
|
||||
* - dsp_filter_flag: Set, the filter is needed (many sound fonts don't use
|
||||
* the filter at all. If it is left at its default setting
|
||||
* of roughly 20 kHz, there is no need to apply filterling.)
|
||||
* - dsp_interp_method: Which interpolation method to use.
|
||||
* - voice holds the voice structure
|
||||
*
|
||||
* Some variables are set and modified:
|
||||
* - dsp_phase: The position in the original waveform data.
|
||||
* This has an integer and a fractional part (between samples).
|
||||
* - dsp_phase_incr: For each output sample, the position in the original
|
||||
* waveform advances by dsp_phase_incr. This also has an integer
|
||||
* part and a fractional part.
|
||||
* If a sample is played at root pitch (no pitch change),
|
||||
* dsp_phase_incr is integer=1 and fractional=0.
|
||||
* - dsp_amp: The current amplitude envelope value.
|
||||
* - dsp_amp_incr: The changing rate of the amplitude envelope.
|
||||
*
|
||||
* A couple of variables are used internally, their results are discarded:
|
||||
* - dsp_i: Index through the output buffer
|
||||
* - dsp_phase_fractional: The fractional part of dsp_phase
|
||||
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
|
||||
* Used to interpolate between samples.
|
||||
* - dsp_process_buffer: Holds the processed signal between stages
|
||||
* - dsp_centernode: delay line for the IIR filter
|
||||
* - dsp_hist1: same
|
||||
* - dsp_hist2: same
|
||||
*
|
||||
*/
|
||||
|
||||
/* Purpose:
|
||||
* zap_almost_zero will return a number, as long as its
|
||||
* absolute value is over a certain threshold. Otherwise 0. See
|
||||
* fluid_rev.c for documentation (denormal numbers)
|
||||
*/
|
||||
|
||||
# if defined(WITH_FLOAT)
|
||||
# define zap_almost_zero(_sample) \
|
||||
((((*(unsigned int*)&(_sample))&0x7f800000) < 0x08000000)? 0.0f : (_sample))
|
||||
# else
|
||||
/* 1e-20 was chosen as an arbitrary (small) threshold. */
|
||||
#define zap_almost_zero(_sample) ((abs(_sample) < 1e-20)? 0.0f : (_sample))
|
||||
#endif
|
||||
|
||||
/* Interpolation (find a value between two samples of the original waveform) */
|
||||
|
||||
if ((fluid_phase_fract(dsp_phase) == 0)
|
||||
&& (fluid_phase_fract(dsp_phase_incr) == 0)
|
||||
&& (fluid_phase_index(dsp_phase_incr) == 1)) {
|
||||
|
||||
/* Check for a special case: The current phase falls directly on an
|
||||
* original sample. Also, the stepsize per output sample is exactly
|
||||
* one sample, no fractional part. In other words: The sample is
|
||||
* played back at normal phase and root pitch. => No interpolation
|
||||
* needed.
|
||||
*/
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
/* Mix to the buffer and advance the phase by one sample */
|
||||
dsp_buf[dsp_i] = dsp_amp * dsp_data[fluid_phase_index_plusplus(dsp_phase)];
|
||||
dsp_amp += dsp_amp_incr;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* wave table interpolation: Choose the interpolation method */
|
||||
/* !!! SSE interpolation is less efficient that normal interpolation. */
|
||||
|
||||
|
||||
/* Initialize amplitude increase */
|
||||
sse_b->sf[0] = sse_b->sf[1] = sse_b->sf[2] = sse_b->sf[3] = 4.*dsp_amp_incr;
|
||||
|
||||
/* Initialize amplitude => xmm7
|
||||
* The amplitude is kept in xmm7 throughout the whole process
|
||||
*/
|
||||
|
||||
sse_a->sf[0]=sse_a->sf[1]=sse_a->sf[2]=sse_a->sf[3]=dsp_amp;
|
||||
sse_a->sf[1] += dsp_amp_incr;
|
||||
sse_a->sf[2] += 2.* dsp_amp_incr;
|
||||
sse_a->sf[3] += 3.* dsp_amp_incr;
|
||||
movaps_m2r(*sse_a,xmm7);
|
||||
|
||||
/* Where to store the result */
|
||||
sse_dest=(sse_t*)&dsp_buf[0];
|
||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i += 4) {
|
||||
/* Note / fixme: The coefficients are first copied to
|
||||
* sse_c, then to the xmm register. Can't get it through
|
||||
* the compiler differently... */
|
||||
|
||||
/* Load the four source samples for the 1st output sample */
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
||||
movaps_m2r(*sse_a,xmm0);
|
||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
||||
mulps_m2r(*sse_c,xmm0);
|
||||
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
|
||||
/* Load the four source samples for the 2nd output sample */
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
||||
movaps_m2r(*sse_a,xmm1);
|
||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
||||
mulps_m2r(*sse_c,xmm1);
|
||||
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
|
||||
/* Load the four source samples for the 3rd output sample */
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
||||
movaps_m2r(*sse_a,xmm2);
|
||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
||||
mulps_m2r(*sse_c,xmm2);
|
||||
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
|
||||
/* Load the four source samples for the 4th output sample */
|
||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
||||
movaps_m2r(*sse_a,xmm3);
|
||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
||||
mulps_m2r(*sse_c,xmm3);
|
||||
|
||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
||||
|
||||
#if 0
|
||||
/*Testcase for horizontal add */
|
||||
sse_a->sf[0]=0.1;sse_a->sf[1]=0.01;sse_a->sf[2]=0.001;sse_a->sf[3]=0.0001;
|
||||
movaps_m2r(*sse_a,xmm0);
|
||||
sse_a->sf[0]=0.2;sse_a->sf[1]=0.02;sse_a->sf[2]=0.002;sse_a->sf[3]=0.0002;
|
||||
movaps_m2r(*sse_a,xmm1);
|
||||
sse_a->sf[0]=0.3;sse_a->sf[1]=0.03;sse_a->sf[2]=0.003;sse_a->sf[3]=0.0003;
|
||||
movaps_m2r(*sse_a,xmm2);
|
||||
sse_a->sf[0]=0.4;sse_a->sf[1]=0.04;sse_a->sf[2]=0.004;sse_a->sf[3]=0.0004;
|
||||
movaps_m2r(*sse_a,xmm3);
|
||||
#endif /* #if 0 */
|
||||
|
||||
#if 1
|
||||
/* Horizontal add
|
||||
* xmm4[0]:=xmm0[0]+xmm1[0]+xmm2[0]+xmm3[0]
|
||||
* xmm4[1]:=xmm0[1]+xmm1[1]+xmm2[1]+xmm3[1]
|
||||
* etc.
|
||||
* The only register, which is unused, is xmm7.
|
||||
*/
|
||||
movaps_r2r(xmm0,xmm5);
|
||||
movaps_r2r(xmm2,xmm6);
|
||||
movlhps_r2r(xmm1,xmm5);
|
||||
movlhps_r2r(xmm3,xmm6);
|
||||
movhlps_r2r(xmm0,xmm1);
|
||||
movhlps_r2r(xmm2,xmm3);
|
||||
addps_r2r(xmm1,xmm5);
|
||||
addps_r2r(xmm3,xmm6);
|
||||
movaps_r2r(xmm5,xmm4);
|
||||
shufps_r2r(xmm6,xmm5,0xDD);
|
||||
shufps_r2r(xmm6,xmm4,0x88);
|
||||
addps_r2r(xmm5,xmm4);
|
||||
|
||||
/* movaps_r2m(xmm4,*sse_a); */
|
||||
/* printf("xmm4 (Result): %f %f %f %f\n", */
|
||||
/* sse_a->sf[0], sse_a->sf[1], */
|
||||
/* sse_a->sf[2], sse_a->sf[3]); */
|
||||
#else
|
||||
/* Add using normal FPU */
|
||||
movaps_r2m(xmm0,*sse_a);
|
||||
sse_c->sf[0]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
||||
movaps_r2m(xmm1,*sse_a);
|
||||
sse_c->sf[1]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
||||
movaps_r2m(xmm2,*sse_a);
|
||||
sse_c->sf[2]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
||||
movaps_r2m(xmm3,*sse_a);
|
||||
sse_c->sf[3]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
||||
movaps_m2r(*sse_c,xmm4);
|
||||
#endif /* #if 1 */
|
||||
/* end horizontal add. Result in xmm6. */
|
||||
|
||||
|
||||
/* Multiply xmm4 with amplitude */
|
||||
mulps_r2r(xmm7,xmm4);
|
||||
|
||||
/* Store the result */
|
||||
movaps_r2m(xmm4,*sse_dest); // ++
|
||||
|
||||
/* Advance the position in the output buffer */
|
||||
sse_dest++;
|
||||
|
||||
/* Change the amplitude */
|
||||
addps_m2r(*sse_b,xmm7);
|
||||
|
||||
} /* for dsp_i in steps of four */
|
||||
|
||||
movaps_r2m(xmm7,*sse_a);
|
||||
|
||||
/* Retrieve the last amplitude value. */
|
||||
dsp_amp=sse_a->sf[3];
|
||||
|
||||
|
||||
} /* If interpolation is needed */
|
||||
|
||||
/* filter (implement the voice filter according to Soundfont standard) */
|
||||
if (dsp_use_filter_flag) {
|
||||
|
||||
/* Check for denormal number (too close to zero) once in a
|
||||
* while. This is not a big concern here - why would someone play a
|
||||
* sample with an empty tail? */
|
||||
dsp_hist1 = zap_almost_zero(dsp_hist1);
|
||||
|
||||
/* Two versions of the filter loop. One, while the filter is
|
||||
* changing towards its new setting. The other, if the filter
|
||||
* doesn't change.
|
||||
*/
|
||||
|
||||
if (dsp_filter_coeff_incr_count > 0) {
|
||||
/* The increment is added to each filter coefficient
|
||||
filter_coeff_incr_count times. */
|
||||
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
/* The filter is implemented in Direct-II form. */
|
||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
||||
dsp_hist2 = dsp_hist1;
|
||||
dsp_hist1 = dsp_centernode;
|
||||
|
||||
if (dsp_filter_coeff_incr_count-- > 0){
|
||||
dsp_a1 += dsp_a1_incr;
|
||||
dsp_a2 += dsp_a2_incr;
|
||||
dsp_b02 += dsp_b02_incr;
|
||||
dsp_b1 += dsp_b1_incr;
|
||||
}
|
||||
} /* for dsp_i */
|
||||
|
||||
} else {
|
||||
|
||||
/* The filter parameters are constant. This is duplicated to save
|
||||
* time. */
|
||||
|
||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
||||
/* The filter is implemented in Direct-II form. */
|
||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
||||
dsp_hist2 = dsp_hist1;
|
||||
dsp_hist1 = dsp_centernode;
|
||||
}
|
||||
} /* if filter is fixed */
|
||||
} /* if filter is enabled */
|
||||
|
||||
|
||||
/* The following optimization will process a whole buffer using the
|
||||
* SSE extension of the Pentium processor.
|
||||
*/
|
||||
|
||||
if (voice->amp_left != 0.0) {
|
||||
sse_a->sf[0]=voice->amp_left;
|
||||
sse_a->sf[1]=voice->amp_left;
|
||||
sse_a->sf[2]=voice->amp_left;
|
||||
sse_a->sf[3]=voice->amp_left;
|
||||
movaps_m2r(*sse_a,xmm0);
|
||||
|
||||
sse_src=(sse_t*)dsp_buf;
|
||||
sse_dest=(sse_t*)&dsp_left_buf[0];
|
||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
||||
sse_src++;
|
||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
||||
sse_dest++;
|
||||
}
|
||||
}
|
||||
|
||||
if (voice->amp_right != 0.0){
|
||||
sse_a->sf[0]=voice->amp_right;
|
||||
sse_a->sf[1]=voice->amp_right;
|
||||
sse_a->sf[2]=voice->amp_right;
|
||||
sse_a->sf[3]=voice->amp_right;
|
||||
movaps_m2r(*sse_a,xmm0);
|
||||
|
||||
sse_src=(sse_t*)dsp_buf;
|
||||
sse_dest=(sse_t*)&dsp_right_buf[0];
|
||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
||||
sse_src++;
|
||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
||||
sse_dest++;
|
||||
}
|
||||
}
|
||||
|
||||
/* reverb send. Buffer may be NULL. */
|
||||
if (dsp_reverb_buf && voice->amp_reverb != 0.0){
|
||||
sse_a->sf[0]=voice->amp_reverb;
|
||||
sse_a->sf[1]=voice->amp_reverb;
|
||||
sse_a->sf[2]=voice->amp_reverb;
|
||||
sse_a->sf[3]=voice->amp_reverb;
|
||||
movaps_m2r(*sse_a,xmm0);
|
||||
|
||||
sse_src=(sse_t*)dsp_buf;
|
||||
sse_dest=(sse_t*)&dsp_reverb_buf[0];
|
||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
||||
sse_src++;
|
||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
||||
sse_dest++;
|
||||
}
|
||||
}
|
||||
|
||||
/* chorus send. Buffer may be NULL. */
|
||||
if (dsp_chorus_buf && voice->amp_chorus != 0){
|
||||
sse_a->sf[0]=voice->amp_chorus;
|
||||
sse_a->sf[1]=voice->amp_chorus;
|
||||
sse_a->sf[2]=voice->amp_chorus;
|
||||
sse_a->sf[3]=voice->amp_chorus;
|
||||
movaps_m2r(*sse_a,xmm0);
|
||||
|
||||
sse_src=(sse_t*)dsp_buf;
|
||||
sse_dest=(sse_t*)&dsp_chorus_buf[0];
|
||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
||||
sse_src++;
|
||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
||||
sse_dest++;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,10 @@
|
||||
|
||||
/* Event alloc/free */
|
||||
|
||||
/**
|
||||
* Create a new sequencer event structure.
|
||||
* @return New sequencer event structure or NULL if out of memory
|
||||
*/
|
||||
fluid_event_t*
|
||||
new_fluid_event()
|
||||
{
|
||||
@@ -59,6 +63,10 @@ new_fluid_event()
|
||||
return(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a sequencer event structure.
|
||||
* @param evt Sequencer event structure created by new_fluid_event().
|
||||
*/
|
||||
void
|
||||
delete_fluid_event(fluid_event_t* evt)
|
||||
{
|
||||
@@ -70,26 +78,45 @@ delete_fluid_event(fluid_event_t* evt)
|
||||
FLUID_FREE(evt);
|
||||
}
|
||||
|
||||
/* Initializing events */
|
||||
/**
|
||||
* Set the time field of a sequencer event.
|
||||
* @internal
|
||||
* @param evt Sequencer event structure
|
||||
* @param time Time value to assign
|
||||
*/
|
||||
void
|
||||
fluid_event_set_time(fluid_event_t* evt, unsigned int time)
|
||||
{
|
||||
evt->time = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set source of a sequencer event (DOCME).
|
||||
* @param evt Sequencer event structure
|
||||
* @param src DOCME
|
||||
*/
|
||||
void
|
||||
fluid_event_set_source(fluid_event_t* evt, short src)
|
||||
{
|
||||
evt->src = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set destination of a sequencer event (DOCME).
|
||||
* @param evt Sequencer event structure
|
||||
* @param dest DOCME
|
||||
*/
|
||||
void
|
||||
fluid_event_set_dest(fluid_event_t* evt, short dest)
|
||||
{
|
||||
evt->dest = dest;
|
||||
}
|
||||
|
||||
/* Timer events */
|
||||
/**
|
||||
* Set a sequencer event to be a timer event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param data DOCME
|
||||
*/
|
||||
void
|
||||
fluid_event_timer(fluid_event_t* evt, void* data)
|
||||
{
|
||||
@@ -97,8 +124,13 @@ fluid_event_timer(fluid_event_t* evt, void* data)
|
||||
evt->data = data;
|
||||
}
|
||||
|
||||
|
||||
/* Note events */
|
||||
/**
|
||||
* Set a sequencer event to be a note on event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param key MIDI note number (0-127)
|
||||
* @param vel MIDI velocity value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
|
||||
{
|
||||
@@ -108,6 +140,12 @@ fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
|
||||
evt->vel = vel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a note off event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param key MIDI note number (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_noteoff(fluid_event_t* evt, int channel, short key)
|
||||
{
|
||||
@@ -116,6 +154,14 @@ fluid_event_noteoff(fluid_event_t* evt, int channel, short key)
|
||||
evt->key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a note duration event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param key MIDI note number (0-127)
|
||||
* @param vel MIDI velocity value (0-127)
|
||||
* @param duration Duration of note (DOCME units?)
|
||||
*/
|
||||
void
|
||||
fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration)
|
||||
{
|
||||
@@ -126,6 +172,11 @@ fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned
|
||||
evt->duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be an all sounds off event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
*/
|
||||
void
|
||||
fluid_event_all_sounds_off(fluid_event_t* evt, int channel)
|
||||
{
|
||||
@@ -133,6 +184,11 @@ fluid_event_all_sounds_off(fluid_event_t* evt, int channel)
|
||||
evt->channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a all notes off event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
*/
|
||||
void
|
||||
fluid_event_all_notes_off(fluid_event_t* evt, int channel)
|
||||
{
|
||||
@@ -140,6 +196,12 @@ fluid_event_all_notes_off(fluid_event_t* evt, int channel)
|
||||
evt->channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a bank select event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param bank_num MIDI bank number (0-16383)
|
||||
*/
|
||||
void
|
||||
fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
|
||||
{
|
||||
@@ -148,6 +210,12 @@ fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
|
||||
evt->control = bank_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a program change event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param val MIDI program number (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_program_change(fluid_event_t* evt, int channel, short val)
|
||||
{
|
||||
@@ -156,6 +224,14 @@ fluid_event_program_change(fluid_event_t* evt, int channel, short val)
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a program select event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param sfont_id SoundFont ID number
|
||||
* @param bank_num MIDI bank number (0-16383)
|
||||
* @param preset_num MIDI preset number (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_program_select(fluid_event_t* evt, int channel,
|
||||
unsigned int sfont_id, short bank_num, short preset_num)
|
||||
@@ -167,6 +243,12 @@ fluid_event_program_select(fluid_event_t* evt, int channel,
|
||||
evt->control = bank_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be an any control change event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* DOCME
|
||||
*/
|
||||
void
|
||||
fluid_event_any_control_change(fluid_event_t* evt, int channel)
|
||||
{
|
||||
@@ -174,6 +256,12 @@ fluid_event_any_control_change(fluid_event_t* evt, int channel)
|
||||
evt->channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a pitch bend event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param pitch MIDI pitch bend value (0-16383, 8192 = no bend)
|
||||
*/
|
||||
void
|
||||
fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch)
|
||||
{
|
||||
@@ -184,6 +272,12 @@ fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch)
|
||||
evt->pitch = pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a pitch wheel sensitivity event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param value MIDI pitch wheel sensitivity value (DOCME units?)
|
||||
*/
|
||||
void
|
||||
fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
|
||||
{
|
||||
@@ -192,6 +286,12 @@ fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
|
||||
evt->value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a modulation event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param val MIDI modulation value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_modulation(fluid_event_t* evt, int channel, short val)
|
||||
{
|
||||
@@ -202,6 +302,12 @@ fluid_event_modulation(fluid_event_t* evt, int channel, short val)
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a MIDI sustain event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param val MIDI sustain value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_sustain(fluid_event_t* evt, int channel, short val)
|
||||
{
|
||||
@@ -212,6 +318,13 @@ fluid_event_sustain(fluid_event_t* evt, int channel, short val)
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a MIDI control change event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param control MIDI control number (0-127)
|
||||
* @param val MIDI control value (0-16383 DOCME is that true?)
|
||||
*/
|
||||
void
|
||||
fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val)
|
||||
{
|
||||
@@ -221,6 +334,12 @@ fluid_event_control_change(fluid_event_t* evt, int channel, short control, short
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a stereo pan event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param val MIDI panning value (0-127, 0=left, 64 = middle, 127 = right)
|
||||
*/
|
||||
void
|
||||
fluid_event_pan(fluid_event_t* evt, int channel, short val)
|
||||
{
|
||||
@@ -231,6 +350,12 @@ fluid_event_pan(fluid_event_t* evt, int channel, short val)
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a volume event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param val Volume value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_volume(fluid_event_t* evt, int channel, short val)
|
||||
{
|
||||
@@ -241,6 +366,12 @@ fluid_event_volume(fluid_event_t* evt, int channel, short val)
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a reverb send event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param val Reverb amount (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
|
||||
{
|
||||
@@ -251,6 +382,12 @@ fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a chorus send event.
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
* @param val Chorus amount (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
|
||||
{
|
||||
@@ -261,75 +398,178 @@ fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
|
||||
evt->value = val;
|
||||
}
|
||||
|
||||
/* Accessing event data */
|
||||
|
||||
/*
|
||||
* Accessing event data
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the event type (#fluid_seq_event_type) field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return Event type (#fluid_seq_event_type).
|
||||
*/
|
||||
int fluid_event_get_type(fluid_event_t* evt)
|
||||
{
|
||||
return evt->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return Time value (DOCME units?)
|
||||
*/
|
||||
unsigned int fluid_event_get_time(fluid_event_t* evt)
|
||||
{
|
||||
return evt->time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return DOCME
|
||||
*/
|
||||
short fluid_event_get_source(fluid_event_t* evt)
|
||||
{
|
||||
return evt->src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dest field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return DOCME
|
||||
*/
|
||||
short fluid_event_get_dest(fluid_event_t* evt)
|
||||
{
|
||||
return evt->dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIDI channel field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return MIDI channel number (DOCME 0-15 or more?)
|
||||
*/
|
||||
int fluid_event_get_channel(fluid_event_t* evt)
|
||||
{
|
||||
return evt->channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIDI note field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return MIDI note number (0-127)
|
||||
*/
|
||||
short fluid_event_get_key(fluid_event_t* evt)
|
||||
{
|
||||
return evt->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIDI velocity field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return MIDI velocity value (0-127)
|
||||
*/
|
||||
short fluid_event_get_velocity(fluid_event_t* evt)
|
||||
|
||||
{
|
||||
return evt->vel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIDI control number field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return MIDI control number (0-127)
|
||||
*/
|
||||
short fluid_event_get_control(fluid_event_t* evt)
|
||||
{
|
||||
return evt->control;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return Value field of event.
|
||||
*
|
||||
* The Value field is used by the following event types:
|
||||
* #FLUID_SEQ_PROGRAMCHANGE, #FLUID_SEQ_PROGRAMSELECT (preset_num),
|
||||
* #FLUID_SEQ_PITCHWHHELSENS, #FLUID_SEQ_MODULATION, #FLUID_SEQ_SUSTAIN,
|
||||
* #FLUID_SEQ_CONTROLCHANGE, #FLUID_SEQ_PAN, #FLUID_SEQ_VOLUME,
|
||||
* #FLUID_SEQ_REVERBSEND, #FLUID_SEQ_CHORUSSEND.
|
||||
*/
|
||||
short fluid_event_get_value(fluid_event_t* evt)
|
||||
{
|
||||
return evt->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return Data field of event.
|
||||
*
|
||||
* Used by the #FLUID_SEQ_TIMER event type.
|
||||
*/
|
||||
void* fluid_event_get_data(fluid_event_t* evt)
|
||||
{
|
||||
return evt->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the duration field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return Note duration value (DOCME units?)
|
||||
*
|
||||
* Used by the #FLUID_SEQ_NOTE event type.
|
||||
*/
|
||||
unsigned int fluid_event_get_duration(fluid_event_t* evt)
|
||||
{
|
||||
return evt->duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIDI bank field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return MIDI bank number (0-16383)
|
||||
*
|
||||
* Used by the #FLUID_SEQ_BANKSELECT and #FLUID_SEQ_PROGRAMSELECT
|
||||
* event types.
|
||||
*/
|
||||
short fluid_event_get_bank(fluid_event_t* evt)
|
||||
{
|
||||
return evt->control;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pitch field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return MIDI pitch bend pitch value (0-16383, 8192 = no bend)
|
||||
*
|
||||
* Used by the #FLUID_SEQ_PITCHBEND event type.
|
||||
*/
|
||||
int fluid_event_get_pitch(fluid_event_t* evt)
|
||||
{
|
||||
return evt->pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIDI program field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return MIDI program number (0-127)
|
||||
*
|
||||
* Used by the #FLUID_SEQ_PROGRAMCHANGE and #FLUID_SEQ_PROGRAMSELECT
|
||||
* event types.
|
||||
*/
|
||||
short
|
||||
fluid_event_get_program(fluid_event_t* evt)
|
||||
{
|
||||
return evt->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SoundFont ID field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return SoundFont identifier value.
|
||||
*
|
||||
* Used by the #FLUID_SEQ_PROGRAMSELECT event type.
|
||||
*/
|
||||
unsigned int
|
||||
fluid_event_get_sfont_id(fluid_event_t* evt)
|
||||
{
|
||||
|
||||
@@ -89,9 +89,10 @@ fluid_gen_info_t fluid_gen_info[] = {
|
||||
};
|
||||
|
||||
|
||||
/* fluid_gen_set_default_values
|
||||
*
|
||||
* Set an array of generators to their initial value
|
||||
/**
|
||||
* Set an array of generators to their default values.
|
||||
* @param gen Array of generators (should be #GEN_LAST in size).
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int
|
||||
fluid_gen_set_default_values(fluid_gen_t* gen)
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LASH) || defined(HAVE_LADCCA)
|
||||
|
||||
|
||||
@@ -151,7 +151,14 @@ void fluid_midi_driver_settings(fluid_settings_t* settings)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new MIDI driver instance.
|
||||
* @param settings Settings used to configure new MIDI driver.
|
||||
* @param handler MIDI handler callback (for example: fluid_midi_router_handle_midi_event()
|
||||
* for MIDI router)
|
||||
* @param event_handler_data Caller defined data to pass to 'handler'
|
||||
* @return New MIDI driver instance or NULL on error
|
||||
*/
|
||||
fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings, handle_midi_event_func_t handler, void* event_handler_data)
|
||||
{
|
||||
int i;
|
||||
@@ -171,6 +178,10 @@ fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings, handle_mi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a MIDI driver instance.
|
||||
* @param driver MIDI driver to delete
|
||||
*/
|
||||
void delete_fluid_midi_driver(fluid_midi_driver_t* driver)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -55,8 +55,12 @@ static int remains_80e0[] = {
|
||||
*
|
||||
* MIDIFILE
|
||||
*/
|
||||
/*
|
||||
* new_fluid_midi_file
|
||||
|
||||
/**
|
||||
* Open a MIDI file and return a new MIDI file handle.
|
||||
* @internal
|
||||
* @param filename Path of file to open.
|
||||
* @return New MIDI file handle or NULL on error.
|
||||
*/
|
||||
fluid_midi_file* new_fluid_midi_file(char* filename)
|
||||
{
|
||||
@@ -86,8 +90,10 @@ fluid_midi_file* new_fluid_midi_file(char* filename)
|
||||
return mf;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_midi_file
|
||||
/**
|
||||
* Delete a MIDI file handle.
|
||||
* @internal
|
||||
* @param mf MIDI file handle to close and free.
|
||||
*/
|
||||
void delete_fluid_midi_file(fluid_midi_file* mf)
|
||||
{
|
||||
@@ -102,7 +108,7 @@ void delete_fluid_midi_file(fluid_midi_file* mf)
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_file_getc
|
||||
* Get the next byte in a MIDI file.
|
||||
*/
|
||||
int fluid_midi_file_getc(fluid_midi_file* mf)
|
||||
{
|
||||
@@ -660,8 +666,9 @@ int fluid_midi_file_get_division(fluid_midi_file* midifile)
|
||||
* fluid_track_t
|
||||
*/
|
||||
|
||||
/*
|
||||
* new_fluid_midi_event
|
||||
/**
|
||||
* Create a MIDI event structure.
|
||||
* @return New MIDI event structure or NULL when out of memory.
|
||||
*/
|
||||
fluid_midi_event_t* new_fluid_midi_event()
|
||||
{
|
||||
@@ -680,8 +687,10 @@ fluid_midi_event_t* new_fluid_midi_event()
|
||||
return evt;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_midi_event
|
||||
/**
|
||||
* Delete MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int delete_fluid_midi_event(fluid_midi_event_t* evt)
|
||||
{
|
||||
@@ -696,16 +705,23 @@ int delete_fluid_midi_event(fluid_midi_event_t* evt)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_type
|
||||
/**
|
||||
* Get the event type field of a MIDI event structure.
|
||||
* DOCME - Event type enum appears to be internal (fluid_midi.h)
|
||||
* @param evt MIDI event structure
|
||||
* @return Event type field
|
||||
*/
|
||||
int fluid_midi_event_get_type(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->type;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_type
|
||||
/**
|
||||
* Set the event type field of a MIDI event structure.
|
||||
* DOCME - Event type enum appears to be internal (fluid_midi.h)
|
||||
* @param evt MIDI event structure
|
||||
* @param type Event type field
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_type(fluid_midi_event_t* evt, int type)
|
||||
{
|
||||
@@ -713,16 +729,21 @@ int fluid_midi_event_set_type(fluid_midi_event_t* evt, int type)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_channel
|
||||
/**
|
||||
* Get the channel field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return Channel field
|
||||
*/
|
||||
int fluid_midi_event_get_channel(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->channel;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_channel
|
||||
/**
|
||||
* Set the channel field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @param chan MIDI channel field
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_channel(fluid_midi_event_t* evt, int chan)
|
||||
{
|
||||
@@ -730,16 +751,21 @@ int fluid_midi_event_set_channel(fluid_midi_event_t* evt, int chan)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_key
|
||||
/**
|
||||
* Get the key field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return MIDI note number (0-127)
|
||||
*/
|
||||
int fluid_midi_event_get_key(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->param1;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_key
|
||||
/**
|
||||
* Set the key field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @param v MIDI note number (0-127)
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_key(fluid_midi_event_t* evt, int v)
|
||||
{
|
||||
@@ -747,16 +773,21 @@ int fluid_midi_event_set_key(fluid_midi_event_t* evt, int v)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_velocity
|
||||
/**
|
||||
* Get the velocity field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return MIDI velocity number (0-127)
|
||||
*/
|
||||
int fluid_midi_event_get_velocity(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->param2;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_velocity
|
||||
/**
|
||||
* Set the velocity field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @param v MIDI velocity value
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_velocity(fluid_midi_event_t* evt, int v)
|
||||
{
|
||||
@@ -764,16 +795,21 @@ int fluid_midi_event_set_velocity(fluid_midi_event_t* evt, int v)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_control
|
||||
/**
|
||||
* Get the control number of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return MIDI control number
|
||||
*/
|
||||
int fluid_midi_event_get_control(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->param1;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_control
|
||||
/**
|
||||
* Set the control field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @param v MIDI control number
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_control(fluid_midi_event_t* evt, int v)
|
||||
{
|
||||
@@ -781,16 +817,21 @@ int fluid_midi_event_set_control(fluid_midi_event_t* evt, int v)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_get_value
|
||||
/**
|
||||
* Get the value field from a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return Value field
|
||||
*/
|
||||
int fluid_midi_event_get_value(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->param2;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_midi_event_set_value
|
||||
/**
|
||||
* Set the value field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @param v Value to assign
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_value(fluid_midi_event_t* evt, int v)
|
||||
{
|
||||
@@ -798,22 +839,44 @@ int fluid_midi_event_set_value(fluid_midi_event_t* evt, int v)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the program field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return MIDI program number (0-127)
|
||||
*/
|
||||
int fluid_midi_event_get_program(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->param1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the program field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @param val MIDI program number (0-127)
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_program(fluid_midi_event_t* evt, int val)
|
||||
{
|
||||
evt->param1 = val;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pitch field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @return Pitch value (DOCME units?)
|
||||
*/
|
||||
int fluid_midi_event_get_pitch(fluid_midi_event_t* evt)
|
||||
{
|
||||
return evt->param1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pitch field of a MIDI event structure.
|
||||
* @param evt MIDI event structure
|
||||
* @param val Pitch value (DOCME units?)
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val)
|
||||
{
|
||||
evt->param1 = val;
|
||||
@@ -1046,8 +1109,11 @@ fluid_track_send_events(fluid_track_t* track,
|
||||
*
|
||||
* fluid_player
|
||||
*/
|
||||
/*
|
||||
* new_fluid_player
|
||||
|
||||
/**
|
||||
* Create a new MIDI player.
|
||||
* @param synth Fluid synthesizer instance to create player for
|
||||
* @return New MIDI player instance or NULL on error (out of memory)
|
||||
*/
|
||||
fluid_player_t* new_fluid_player(fluid_synth_t* synth)
|
||||
{
|
||||
@@ -1075,8 +1141,10 @@ fluid_player_t* new_fluid_player(fluid_synth_t* synth)
|
||||
return player;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_player
|
||||
/**
|
||||
* Delete a MIDI player instance.
|
||||
* @param player MIDI player instance
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int delete_fluid_player(fluid_player_t* player)
|
||||
{
|
||||
@@ -1240,8 +1308,10 @@ int fluid_player_callback(void* data, unsigned int msec)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_player_play
|
||||
/**
|
||||
* Activates play mode for a MIDI player if not already playing.
|
||||
* @param player MIDI player instance
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int fluid_player_play(fluid_player_t* player)
|
||||
{
|
||||
@@ -1263,8 +1333,10 @@ int fluid_player_play(fluid_player_t* player)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_player_stop
|
||||
/**
|
||||
* Stops a MIDI player.
|
||||
* @param player MIDI player instance
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_player_stop(fluid_player_t* player)
|
||||
{
|
||||
@@ -1276,8 +1348,13 @@ int fluid_player_stop(fluid_player_t* player)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_player_set_loop
|
||||
/* FIXME - Looping seems to not actually be implemented? */
|
||||
|
||||
/**
|
||||
* Enable looping of a MIDI player (DOCME - Does this actually work?)
|
||||
* @param player MIDI player instance
|
||||
* @param loop Value for looping (DOCME - What would this value be, boolean/time index?)
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_player_set_loop(fluid_player_t* player, int loop)
|
||||
{
|
||||
@@ -1285,8 +1362,12 @@ int fluid_player_set_loop(fluid_player_t* player, int loop)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_player_set_midi_tempo
|
||||
/**
|
||||
* Set the tempo of a MIDI player.
|
||||
* @param player MIDI player instance
|
||||
* @param tempo Tempo to set playback speed to (DOCME - Units?)
|
||||
* @return Always returns 0
|
||||
*
|
||||
*/
|
||||
int fluid_player_set_midi_tempo(fluid_player_t* player, int tempo)
|
||||
{
|
||||
@@ -1301,16 +1382,22 @@ int fluid_player_set_midi_tempo(fluid_player_t* player, int tempo)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_player_set_bpm
|
||||
/**
|
||||
* Set the tempo of a MIDI player in beats per minute.
|
||||
* @param player MIDI player instance
|
||||
* @param bpm Tempo in beats per minute
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int fluid_player_set_bpm(fluid_player_t* player, int bpm)
|
||||
{
|
||||
return fluid_player_set_midi_tempo(player, (int)((double) 60 * 1e6 / bpm));
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_player_join
|
||||
/**
|
||||
* Wait for a MIDI player to terminate (when done playing).
|
||||
* @param player MIDI player instance
|
||||
* @return 0 on success, -1 otherwise
|
||||
*
|
||||
*/
|
||||
int fluid_player_join(fluid_player_t* player)
|
||||
{
|
||||
@@ -1525,5 +1612,3 @@ int fluid_midi_send_event(fluid_synth_t* synth, fluid_player_t* player, fluid_mi
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,14 +26,22 @@
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_io.h"
|
||||
|
||||
/*
|
||||
* new_fluid_midi_router
|
||||
/**
|
||||
* Create a new midi router.
|
||||
* @param settings Settings used to configure MIDI router
|
||||
* @param handler MIDI event callback
|
||||
* @param event_handler_data Caller defined data pointer which gets passed to 'handler'
|
||||
* @return New MIDI router instance or NULL on error
|
||||
*
|
||||
* A midi handler connects to a midi input
|
||||
* device and forwards incoming midi events to the synthesizer.
|
||||
*/
|
||||
fluid_midi_router_t*
|
||||
new_fluid_midi_router(fluid_settings_t* settings, handle_midi_event_func_t handler, void* event_handler_data)
|
||||
{
|
||||
fluid_midi_router_t* router=NULL;
|
||||
fluid_midi_router_rule_t* rule=NULL;;
|
||||
fluid_midi_router_rule_t* rule=NULL;
|
||||
|
||||
/* create the router */
|
||||
router = FLUID_NEW(fluid_midi_router_t); if (router == NULL){
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
@@ -68,8 +76,10 @@ new_fluid_midi_router(fluid_settings_t* settings, handle_midi_event_func_t handl
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_midi_router
|
||||
/**
|
||||
* Delete a MIDI router instance.
|
||||
* @param router MIDI router to delete
|
||||
* @return Always returns 0
|
||||
*/
|
||||
int
|
||||
delete_fluid_midi_router(fluid_midi_router_t* router)
|
||||
@@ -239,8 +249,12 @@ int fluid_midi_router_end(fluid_midi_router_t* router){
|
||||
return FLUID_FAILED;
|
||||
};
|
||||
|
||||
/*
|
||||
* fluid_midi_router_send_event
|
||||
/**
|
||||
* Handle a MIDI event through a MIDI router instance.
|
||||
* @param data MIDI router instance #fluid_midi_router_t (DOCME why is it a void *?)
|
||||
* @param event MIDI event to handle
|
||||
* @return 0 on success, -1 otherwise
|
||||
*
|
||||
* Purpose: The midi router is called for each event, that is received
|
||||
* via the 'physical' midi input. Each event can trigger an arbitrary number
|
||||
* of generated events.
|
||||
@@ -786,11 +800,15 @@ void fluid_midi_router_free_unused_rules(fluid_midi_router_t* router)
|
||||
};
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* This function demonstrates, how to access incoming MIDI messages.
|
||||
* It prints a message to stdout (which can be used to hook up an external user interface),
|
||||
* and hands the event on to the MIDI router.
|
||||
* It is not a part of the MIDI router, but an added link in the MIDI chain.
|
||||
/**
|
||||
* MIDI event callback function to display event information to stdout
|
||||
* @param data MIDI router instance
|
||||
* @param event MIDI event data
|
||||
* @return 0 on success, -1 otherwise
|
||||
*
|
||||
* An implementation of the #handle_midi_event_func_t function type, used for
|
||||
* displaying MIDI event information between the MIDI driver and router to
|
||||
* stdout. Useful for adding into a MIDI router chain for debugging MIDI events.
|
||||
*/
|
||||
int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
|
||||
{
|
||||
@@ -798,35 +816,27 @@ int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
|
||||
case NOTE_ON:
|
||||
fprintf(stdout, "event_pre_noteon %i %i %i\n",
|
||||
event->channel, event->param1, event->param2);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case NOTE_OFF:
|
||||
fprintf(stdout, "event_pre_noteoff %i %i %i\n",
|
||||
event->channel, event->param1, event->param2);
|
||||
fflush(stdout);
|
||||
break;
|
||||
break;
|
||||
case CONTROL_CHANGE:
|
||||
fprintf(stdout, "event_pre_cc %i %i %i\n",
|
||||
event->channel, event->param1, event->param2);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case PROGRAM_CHANGE:
|
||||
fprintf(stdout, "event_pre_prog %i %i\n", event->channel, event->param1);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case PITCH_BEND:
|
||||
fprintf(stdout, "event_pre_pitch %i %i\n", event->channel, event->param1);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case CHANNEL_PRESSURE:
|
||||
fprintf(stdout, "event_pre_cpress %i %i\n", event->channel, event->param1);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case KEY_PRESSURE:
|
||||
fprintf(stdout, "event_pre_kpress %i %i %i\n",
|
||||
event->channel, event->param1, event->param2);
|
||||
fflush(stdout);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -834,11 +844,15 @@ int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
|
||||
return fluid_midi_router_handle_midi_event((fluid_midi_router_t*) data, event);
|
||||
};
|
||||
|
||||
/* Purpose:
|
||||
* This function demonstrates, how to access MIDI messages going from the MIDI
|
||||
* router to the synth.
|
||||
* Again, it prints a message to stdout and hands the event on to the synth.
|
||||
* It is not a part of the MIDI router, but an added link in the MIDI chain.
|
||||
/**
|
||||
* MIDI event callback function to display event information to stdout
|
||||
* @param data MIDI router instance
|
||||
* @param event MIDI event data
|
||||
* @return 0 on success, -1 otherwise
|
||||
*
|
||||
* An implementation of the #handle_midi_event_func_t function type, used for
|
||||
* displaying MIDI event information between the MIDI driver and router to
|
||||
* stdout. Useful for adding into a MIDI router chain for debugging MIDI events.
|
||||
*/
|
||||
int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event)
|
||||
{
|
||||
@@ -846,18 +860,14 @@ int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event)
|
||||
case NOTE_ON:
|
||||
fprintf(stdout, "event_post_noteon %i %i %i\n",
|
||||
event->channel, event->param1, event->param2);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case NOTE_OFF:
|
||||
fprintf(stdout, "event_post_noteoff %i %i %i\n",
|
||||
event->channel, event->param1, event->param2);
|
||||
fflush(stdout);
|
||||
break;
|
||||
break;
|
||||
case CONTROL_CHANGE:
|
||||
fprintf(stdout, "event_post_cc %i %i %i\n",
|
||||
event->channel, event->param1, event->param2);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case PROGRAM_CHANGE:
|
||||
fprintf(stdout, "event_post_prog %i %i\n", event->channel, event->param1);
|
||||
|
||||
@@ -46,61 +46,41 @@
|
||||
* This playing pointer is implemented using fluid_phase_t.
|
||||
* It is a 64 bit number. The higher 32 bits contain the 'index' (number of
|
||||
* the current sample), the lower 32 bits the fractional part.
|
||||
* Access is possible in two ways:
|
||||
* -through the 64 bit part 'b64', if the architecture supports 64 bit integers
|
||||
* -through 'index' and 'fract'
|
||||
* Note: b64 and index / fract share the same memory location!
|
||||
*/
|
||||
typedef union {
|
||||
struct{
|
||||
/* Note, that the two 32-bit ints form a 64-bit int! */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
sint32 index;
|
||||
uint32 fract;
|
||||
#else
|
||||
uint32 fract;
|
||||
sint32 index;
|
||||
#endif
|
||||
} b32;
|
||||
#ifdef USE_LONGLONG
|
||||
long long b64;
|
||||
#endif
|
||||
} fluid_phase_t;
|
||||
typedef unsigned long long fluid_phase_t;
|
||||
|
||||
/* Purpose:
|
||||
* Set a to b.
|
||||
* a: fluid_phase_t
|
||||
* b: fluid_phase_t
|
||||
*/
|
||||
#ifdef USE_LONGLONG
|
||||
#define fluid_phase_set(a,b) a=b;
|
||||
#else
|
||||
#define fluid_phase_set(a, b) { \
|
||||
(a).b32.fract = (b).b32.fract; \
|
||||
(a).b32.index = (b).b32.index; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define fluid_phase_set_int(a, b) { \
|
||||
(a).b32.index = (sint32) (b); \
|
||||
(a).b32.fract = 0; \
|
||||
}
|
||||
#define fluid_phase_set_int(a, b) ((a) = ((unsigned long long)(b)) << 32)
|
||||
|
||||
/* Purpose:
|
||||
* Sets the phase a to a phase increment given in b.
|
||||
* For example, assume b is 0.9. After setting a to it, adding a to
|
||||
* the playing pointer will advance it by 0.9 samples. */
|
||||
#define fluid_phase_set_float(a, b) { \
|
||||
(a).b32.index = (sint32) (b); \
|
||||
(a).b32.fract = (uint32) (((double)(b) - (double)((a).b32.index)) * (double)FLUID_FRACT_MAX); \
|
||||
}
|
||||
#define fluid_phase_set_float(a, b) \
|
||||
(a) = (((unsigned long long)(b)) << 32) \
|
||||
| (uint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX)
|
||||
|
||||
/* create a fluid_phase_t from an index and a fraction value */
|
||||
#define fluid_phase_from_index_fract(index, fract) \
|
||||
((((unsigned long long)(index)) << 32) + (fract))
|
||||
|
||||
/* Purpose:
|
||||
* Return the index and the fractional part, respectively. */
|
||||
#define fluid_phase_index(_x) \
|
||||
((int)(_x).b32.index)
|
||||
((unsigned int)((_x) >> 32))
|
||||
#define fluid_phase_fract(_x) \
|
||||
((_x).b32.fract)
|
||||
((uint32)((_x) & 0xFFFFFFFF))
|
||||
|
||||
/* Get the phase index with fractional rounding */
|
||||
#define fluid_phase_index_round(_x) \
|
||||
((unsigned int)(((_x) + 0x80000000) >> 32))
|
||||
|
||||
|
||||
/* Purpose:
|
||||
* Takes the fractional part of the argument phase and
|
||||
@@ -110,68 +90,28 @@ typedef union {
|
||||
* coefficients for each possible fractional part...
|
||||
*/
|
||||
#define fluid_phase_fract_to_tablerow(_x) \
|
||||
((int)(((_x).b32.fract & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT))
|
||||
((unsigned int)(fluid_phase_fract(_x) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT)
|
||||
|
||||
#define fluid_phase_double(_x) \
|
||||
((double)((_x).b32.index) + ((double)((_x).b32.fract) / FLUID_FRACT_MAX))
|
||||
((double)(fluid_phase_index(_x)) + ((double)fluid_phase_fract(_x) / FLUID_FRACT_MAX))
|
||||
|
||||
/* Purpose:
|
||||
* Advance a by a step of b (both are fluid_phase_t).
|
||||
*/
|
||||
#ifdef USE_LONGLONG
|
||||
#define fluid_phase_incr(a, b) (a).b64 += (b).b64;
|
||||
#else
|
||||
/* The idea to use (a).index += (b).index + ((a).fract < (b).fract) to
|
||||
handle wrap-arounds comes from Mozilla's macros to handle 64-bit
|
||||
integer on 32-bit platforms. Header prlong.h in the NSPR
|
||||
library. www.mozilla.org. */
|
||||
#define fluid_phase_incr(a, b) { \
|
||||
(a).b32.fract += (b).b32.fract; \
|
||||
(a).b32.index += (b).b32.index + ((a).b32.fract < (b).b32.fract); \
|
||||
}
|
||||
#endif
|
||||
#define fluid_phase_incr(a, b) a += b
|
||||
|
||||
/* Purpose:
|
||||
* Subtract b from a (both are fluid_phase_t).
|
||||
*/
|
||||
#ifdef USE_LONGLONG
|
||||
#define fluid_phase_decr(a, b) a-=b;
|
||||
#else
|
||||
#define fluid_phase_decr(a, b) { \
|
||||
(a).b32.index -= b.b32.index - ((a).b32.fract < (b).b32.fract); \
|
||||
(a).b32.fract -= b.b32.fract; \
|
||||
}
|
||||
#endif
|
||||
#define fluid_phase_decr(a, b) a -= b
|
||||
|
||||
/* Purpose:
|
||||
* Subtract b samples from a.
|
||||
*/
|
||||
#define fluid_phase_sub_int(a, b) { (a).b32.index -= b; }
|
||||
|
||||
#if 0
|
||||
#define fluid_phase_fract(_x) \
|
||||
((fluid_real_t)((double)((_x).fract) / FLUID_FRACT_MAX))
|
||||
|
||||
#define fluid_phase_lt(a, b) \
|
||||
(((a).index < (b).index) || (((a).index == (b).index) && ((a).fract < (b).fract)))
|
||||
|
||||
#define fluid_phase_gt(a, b) \
|
||||
(((a).index > (b).index) || (((a).index == (b).index) && ((a).fract > (b).fract)))
|
||||
|
||||
#define fluid_phase_eq(a, b) \
|
||||
(((a).index == (b).index) && ((a).fract == (b).fract))
|
||||
#endif
|
||||
#define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32)
|
||||
|
||||
/* Purpose:
|
||||
* The playing pointer is _phase. How many output samples are produced, until the point _p1 in the sample is reached,
|
||||
* if _phase advances in steps of _incr?
|
||||
*/
|
||||
#define fluid_phase_steps(_phase,_index,_incr) \
|
||||
(int)(((double)(_index) - fluid_phase_double(_phase)) / (double)_incr)
|
||||
|
||||
/* Purpose:
|
||||
* Creates the expression a.index++.
|
||||
* It is slightly different, when USE_LONGLONG is turned on. */
|
||||
#define fluid_phase_index_plusplus(a) (((a).b32.index)++)
|
||||
* Creates the expression a.index++. */
|
||||
#define fluid_phase_index_plusplus(a) (((a) += 0x100000000LL)
|
||||
|
||||
#endif /* _FLUID_PHASE_H */
|
||||
|
||||
@@ -130,7 +130,9 @@ int fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* pr
|
||||
int fluid_rampreset_preset_delete(fluid_preset_t* preset)
|
||||
{
|
||||
FLUID_FREE(preset);
|
||||
printf("TODO: free modulators\n");
|
||||
|
||||
/* TODO: free modulators */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,11 +227,11 @@ fluid_comb_getfeedback(fluid_comb* comb)
|
||||
#define numallpasses 4
|
||||
#define fixedgain 0.015f
|
||||
#define scalewet 3.0f
|
||||
#define scaledamp 0.4f
|
||||
#define scaledamp 1.0f
|
||||
#define scaleroom 0.28f
|
||||
#define offsetroom 0.7f
|
||||
#define initialroom 0.5f
|
||||
#define initialdamp 0.5f
|
||||
#define initialdamp 0.2f
|
||||
#define initialwet 1
|
||||
#define initialdry 0
|
||||
#define initialwidth 1
|
||||
@@ -491,6 +491,7 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
|
||||
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
|
||||
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
|
||||
}
|
||||
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_setdamp(&rev->combL[i], rev->damp);
|
||||
fluid_comb_setdamp(&rev->combR[i], rev->damp);
|
||||
@@ -534,9 +535,9 @@ fluid_revmodel_getdamp(fluid_revmodel_t* rev)
|
||||
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_clip(value, 0.0f, 1.0f);
|
||||
rev->wet = value * scalewet;
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
|
||||
@@ -19,18 +19,21 @@
|
||||
*/
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_settings.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_hash.h"
|
||||
#include "fluid_strtok.h"
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_cmd.h"
|
||||
#include "fluid_adriver.h"
|
||||
#include "fluid_mdriver.h"
|
||||
#include "fluid_settings.h"
|
||||
|
||||
/* maximum allowed components of a settings variable (separated by '.') */
|
||||
#define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */
|
||||
#define MAX_SETTINGS_LABEL 256 /* max length of a settings variable label */
|
||||
|
||||
static void fluid_settings_init(fluid_settings_t* settings);
|
||||
static void fluid_settings_hash_delete(void* value, int type);
|
||||
static int fluid_settings_tokenize(char* s, char* buf, char** ptr);
|
||||
static int fluid_settings_tokenize(char* s, char *buf, char** ptr);
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -66,6 +69,13 @@ static void delete_fluid_str_setting(fluid_str_setting_t* str)
|
||||
FLUID_FREE(str->def);
|
||||
}
|
||||
if (str->options) {
|
||||
fluid_list_t* list = str->options;
|
||||
|
||||
while (list) {
|
||||
FLUID_FREE (list->data);
|
||||
list = fluid_list_next(list);
|
||||
}
|
||||
|
||||
delete_fluid_list(str->options);
|
||||
}
|
||||
FLUID_FREE(str);
|
||||
@@ -189,22 +199,31 @@ void fluid_settings_init(fluid_settings_t* settings)
|
||||
fluid_midi_driver_settings(settings);
|
||||
}
|
||||
|
||||
static fluid_strtok_t* fluid_settings_strtok = NULL;
|
||||
|
||||
int fluid_settings_tokenize(char* s, char* buf, char** ptr)
|
||||
static int fluid_settings_tokenize(char* s, char *buf, char** ptr)
|
||||
{
|
||||
char *tokstr, *tok;
|
||||
int n = 0;
|
||||
|
||||
FLUID_STRCPY(buf, s);
|
||||
|
||||
if (fluid_settings_strtok == NULL) {
|
||||
fluid_settings_strtok = new_fluid_strtok(buf, ".");
|
||||
} else {
|
||||
fluid_strtok_set(fluid_settings_strtok, buf, ".");
|
||||
if (strlen (s) > MAX_SETTINGS_LABEL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
|
||||
MAX_SETTINGS_LABEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (fluid_strtok_has_more(fluid_settings_strtok)) {
|
||||
ptr[n++] = fluid_strtok_next_token(fluid_settings_strtok);
|
||||
FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
|
||||
tokstr = buf;
|
||||
|
||||
while ((tok = fluid_strtok (&tokstr, ".")))
|
||||
{
|
||||
if (n > MAX_SETTINGS_TOKENS)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d",
|
||||
MAX_SETTINGS_TOKENS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr[n++] = tok;
|
||||
}
|
||||
|
||||
return n;
|
||||
@@ -244,7 +263,6 @@ static int fluid_settings_get(fluid_settings_t* settings,
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** returns 1 if the value has been set, zero otherwise */
|
||||
static int fluid_settings_set(fluid_settings_t* settings,
|
||||
char** name, int len,
|
||||
@@ -281,15 +299,15 @@ static int fluid_settings_set(fluid_settings_t* settings,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** returns 1 if the value has been resgister correctly, 0
|
||||
/** returns 1 if the value has been registered correctly, 0
|
||||
otherwise */
|
||||
int fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, int hints,
|
||||
fluid_str_update_t fun, void* data)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
fluid_str_setting_t* setting;
|
||||
|
||||
@@ -323,8 +341,8 @@ int fluid_settings_register_num(fluid_settings_t* settings, char* name, double d
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -363,8 +381,8 @@ int fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -395,13 +413,12 @@ int fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int fluid_settings_get_type(fluid_settings_t* settings, char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -409,13 +426,12 @@ int fluid_settings_get_type(fluid_settings_t* settings, char* name)
|
||||
return (fluid_settings_get(settings, tokens, ntokens, &value, &type))? type : FLUID_NO_TYPE;
|
||||
}
|
||||
|
||||
|
||||
int fluid_settings_get_hints(fluid_settings_t* settings, char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -439,8 +455,8 @@ int fluid_settings_is_realtime(fluid_settings_t* settings, char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -461,11 +477,10 @@ int fluid_settings_is_realtime(fluid_settings_t* settings, char* name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int fluid_settings_setstr(fluid_settings_t* settings, char* name, char* str)
|
||||
{
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
int type;
|
||||
void* value;
|
||||
@@ -504,8 +519,8 @@ int fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -520,13 +535,12 @@ int fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int fluid_settings_str_equal(fluid_settings_t* settings, char* name, char* s)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -539,14 +553,13 @@ int fluid_settings_str_equal(fluid_settings_t* settings, char* name, char* s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
fluid_settings_getstr_default(fluid_settings_t* settings, char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -564,8 +577,8 @@ int fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -585,8 +598,8 @@ int fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -600,6 +613,7 @@ int fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s
|
||||
while (list) {
|
||||
char* option = (char*) fluid_list_get(list);
|
||||
if (FLUID_STRCMP(s, option) == 0) {
|
||||
FLUID_FREE (option);
|
||||
setting->options = fluid_list_remove_link(setting->options, list);
|
||||
return 1;
|
||||
}
|
||||
@@ -612,14 +626,13 @@ int fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int fluid_settings_setnum(fluid_settings_t* settings, char* name, double val)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
fluid_num_setting_t* setting;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -659,8 +672,8 @@ int fluid_settings_getnum(fluid_settings_t* settings, char* name, double* val)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -679,8 +692,8 @@ void fluid_settings_getnum_range(fluid_settings_t* settings, char* name, double*
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -698,8 +711,8 @@ fluid_settings_getnum_default(fluid_settings_t* settings, char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -719,8 +732,8 @@ int fluid_settings_setint(fluid_settings_t* settings, char* name, int val)
|
||||
int type;
|
||||
void* value;
|
||||
fluid_int_setting_t* setting;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -760,8 +773,8 @@ int fluid_settings_getint(fluid_settings_t* settings, char* name, int* val)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -780,8 +793,8 @@ void fluid_settings_getint_range(fluid_settings_t* settings, char* name, int* mi
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -799,8 +812,8 @@ fluid_settings_getint_default(fluid_settings_t* settings, char* name)
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
ntokens = fluid_settings_tokenize(name, buf, tokens);
|
||||
@@ -822,8 +835,8 @@ void fluid_settings_foreach_option(fluid_settings_t* settings, char* name, void*
|
||||
{
|
||||
int type;
|
||||
void* value;
|
||||
char buf[1024];
|
||||
char* tokens[16];
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
char buf[MAX_SETTINGS_LABEL+1];
|
||||
int ntokens;
|
||||
|
||||
if (!func) {
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
/*
|
||||
* sse.h
|
||||
* Copyright (C) 1999 R. Fisher
|
||||
*
|
||||
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
|
||||
*
|
||||
* mpeg2dec is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpeg2dec 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Purpose:
|
||||
* This file defines assembler macros for the SSE instructions of Pentium III and higher.
|
||||
* They are used to execute several floating point multiplications in parallel.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FLUID_SSE_H
|
||||
#define FLUID_SSE_H
|
||||
typedef union {
|
||||
float sf[4]; /* Single-precision (32-bit) value */
|
||||
} __attribute__ ((aligned(16))) sse_t; /* On a 16 byte (128-bit) boundary */
|
||||
|
||||
|
||||
#define sse_i2r(op, imm, reg) \
|
||||
__asm__ __volatile__ (#op " %0, %%" #reg \
|
||||
: /* nothing */ \
|
||||
: "X" (imm) )
|
||||
|
||||
#define sse_m2r(op, mem, reg) \
|
||||
__asm__ __volatile__ (#op " %0, %%" #reg \
|
||||
: /* nothing */ \
|
||||
: "X" (mem))
|
||||
|
||||
#define sse_r2m(op, reg, mem) \
|
||||
__asm__ __volatile__ (#op " %%" #reg ", %0" \
|
||||
: "=X" (mem) \
|
||||
: /* nothing */ )
|
||||
|
||||
#define sse_r2r(op, regs, regd) \
|
||||
__asm__ __volatile__ (#op " %" #regs ", %" #regd)
|
||||
|
||||
#define sse_r2ri(op, regs, regd, imm) \
|
||||
__asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
|
||||
: /* nothing */ \
|
||||
: "X" (imm) )
|
||||
|
||||
#define sse_m2ri(op, mem, reg, subop) \
|
||||
__asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \
|
||||
: /* nothing */ \
|
||||
: "X" (mem))
|
||||
|
||||
|
||||
#define movaps_m2r(var, reg) sse_m2r(movaps, var, reg)
|
||||
#define movaps_r2m(reg, var) sse_r2m(movaps, reg, var)
|
||||
#define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd)
|
||||
|
||||
#define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var)
|
||||
|
||||
#define movups_m2r(var, reg) sse_m2r(movups, var, reg)
|
||||
#define movups_r2m(reg, var) sse_r2m(movups, reg, var)
|
||||
#define movups_r2r(regs, regd) sse_r2r(movups, regs, regd)
|
||||
|
||||
#define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd)
|
||||
|
||||
#define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd)
|
||||
|
||||
#define movhps_m2r(var, reg) sse_m2r(movhps, var, reg)
|
||||
#define movhps_r2m(reg, var) sse_r2m(movhps, reg, var)
|
||||
|
||||
#define movlps_m2r(var, reg) sse_m2r(movlps, var, reg)
|
||||
#define movlps_r2m(reg, var) sse_r2m(movlps, reg, var)
|
||||
|
||||
#define movss_m2r(var, reg) sse_m2r(movss, var, reg)
|
||||
#define movss_r2m(reg, var) sse_r2m(movss, reg, var)
|
||||
#define movss_r2r(regs, regd) sse_r2r(movss, regs, regd)
|
||||
|
||||
#define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index)
|
||||
#define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index)
|
||||
|
||||
#define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg)
|
||||
#define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg)
|
||||
|
||||
#define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg)
|
||||
#define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg)
|
||||
|
||||
#define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg)
|
||||
#define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg)
|
||||
|
||||
#define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg)
|
||||
#define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg)
|
||||
|
||||
#define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
|
||||
#define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
|
||||
|
||||
#define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
|
||||
#define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
|
||||
|
||||
#define movmskps(xmmreg, reg) \
|
||||
__asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg)
|
||||
|
||||
#define addps_m2r(var, reg) sse_m2r(addps, var, reg)
|
||||
#define addps_r2r(regs, regd) sse_r2r(addps, regs, regd)
|
||||
|
||||
#define addss_m2r(var, reg) sse_m2r(addss, var, reg)
|
||||
#define addss_r2r(regs, regd) sse_r2r(addss, regs, regd)
|
||||
|
||||
#define subps_m2r(var, reg) sse_m2r(subps, var, reg)
|
||||
#define subps_r2r(regs, regd) sse_r2r(subps, regs, regd)
|
||||
|
||||
#define subss_m2r(var, reg) sse_m2r(subss, var, reg)
|
||||
#define subss_r2r(regs, regd) sse_r2r(subss, regs, regd)
|
||||
|
||||
#define mulps_m2r(var, reg) sse_m2r(mulps, var, reg)
|
||||
#define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd)
|
||||
|
||||
#define mulss_m2r(var, reg) sse_m2r(mulss, var, reg)
|
||||
#define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd)
|
||||
|
||||
#define divps_m2r(var, reg) sse_m2r(divps, var, reg)
|
||||
#define divps_r2r(regs, regd) sse_r2r(divps, regs, regd)
|
||||
|
||||
#define divss_m2r(var, reg) sse_m2r(divss, var, reg)
|
||||
#define divss_r2r(regs, regd) sse_r2r(divss, regs, regd)
|
||||
|
||||
#define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg)
|
||||
#define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd)
|
||||
|
||||
#define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg)
|
||||
#define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd)
|
||||
|
||||
#define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg)
|
||||
#define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd)
|
||||
|
||||
#define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg)
|
||||
#define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd)
|
||||
|
||||
#define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg)
|
||||
#define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd)
|
||||
|
||||
#define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg)
|
||||
#define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd)
|
||||
|
||||
#define andps_m2r(var, reg) sse_m2r(andps, var, reg)
|
||||
#define andps_r2r(regs, regd) sse_r2r(andps, regs, regd)
|
||||
|
||||
#define andnps_m2r(var, reg) sse_m2r(andnps, var, reg)
|
||||
#define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd)
|
||||
|
||||
#define orps_m2r(var, reg) sse_m2r(orps, var, reg)
|
||||
#define orps_r2r(regs, regd) sse_r2r(orps, regs, regd)
|
||||
|
||||
#define xorps_m2r(var, reg) sse_m2r(xorps, var, reg)
|
||||
#define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd)
|
||||
|
||||
#define maxps_m2r(var, reg) sse_m2r(maxps, var, reg)
|
||||
#define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd)
|
||||
|
||||
#define maxss_m2r(var, reg) sse_m2r(maxss, var, reg)
|
||||
#define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd)
|
||||
|
||||
#define minps_m2r(var, reg) sse_m2r(minps, var, reg)
|
||||
#define minps_r2r(regs, regd) sse_r2r(minps, regs, regd)
|
||||
|
||||
#define minss_m2r(var, reg) sse_m2r(minss, var, reg)
|
||||
#define minss_r2r(regs, regd) sse_r2r(minss, regs, regd)
|
||||
|
||||
#define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op)
|
||||
#define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op)
|
||||
|
||||
#define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0)
|
||||
#define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0)
|
||||
|
||||
#define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1)
|
||||
#define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1)
|
||||
|
||||
#define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2)
|
||||
#define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2)
|
||||
|
||||
#define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3)
|
||||
#define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3)
|
||||
|
||||
#define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4)
|
||||
#define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4)
|
||||
|
||||
#define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5)
|
||||
#define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5)
|
||||
|
||||
#define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6)
|
||||
#define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6)
|
||||
|
||||
#define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7)
|
||||
#define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7)
|
||||
|
||||
#define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op)
|
||||
#define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op)
|
||||
|
||||
#define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0)
|
||||
#define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0)
|
||||
|
||||
#define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1)
|
||||
#define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1)
|
||||
|
||||
#define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2)
|
||||
#define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2)
|
||||
|
||||
#define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3)
|
||||
#define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3)
|
||||
|
||||
#define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4)
|
||||
#define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4)
|
||||
|
||||
#define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5)
|
||||
#define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5)
|
||||
|
||||
#define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6)
|
||||
#define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6)
|
||||
|
||||
#define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7)
|
||||
#define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7)
|
||||
|
||||
#define comiss_m2r(var, reg) sse_m2r(comiss, var, reg)
|
||||
#define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd)
|
||||
|
||||
#define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg)
|
||||
#define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd)
|
||||
|
||||
#define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg)
|
||||
#define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd)
|
||||
|
||||
#define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg)
|
||||
#define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd)
|
||||
|
||||
#define fxrstor(mem) \
|
||||
__asm__ __volatile__ ("fxrstor %0" \
|
||||
: /* nothing */ \
|
||||
: "X" (mem))
|
||||
|
||||
#define fxsave(mem) \
|
||||
__asm__ __volatile__ ("fxsave %0" \
|
||||
: /* nothing */ \
|
||||
: "X" (mem))
|
||||
|
||||
#define stmxcsr(mem) \
|
||||
__asm__ __volatile__ ("stmxcsr %0" \
|
||||
: /* nothing */ \
|
||||
: "X" (mem))
|
||||
|
||||
#define ldmxcsr(mem) \
|
||||
__asm__ __volatile__ ("ldmxcsr %0" \
|
||||
: /* nothing */ \
|
||||
: "X" (mem))
|
||||
#endif
|
||||
@@ -1,123 +0,0 @@
|
||||
/* 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
|
||||
*/
|
||||
|
||||
|
||||
#include "fluid_strtok.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
/*
|
||||
* new_fluid_strtok
|
||||
*/
|
||||
fluid_strtok_t* new_fluid_strtok(char* s, char* d)
|
||||
{
|
||||
fluid_strtok_t* st;
|
||||
st = FLUID_NEW(fluid_strtok_t);
|
||||
if (st == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
/* Careful! the strings are not copied for speed */
|
||||
st->string = s;
|
||||
st->delimiters = d;
|
||||
st->offset = 0;
|
||||
st->len = (s == NULL)? 0 : strlen(s);
|
||||
return st;
|
||||
}
|
||||
|
||||
int delete_fluid_strtok(fluid_strtok_t* st)
|
||||
{
|
||||
if (st == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||
return 0;
|
||||
}
|
||||
free(st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fluid_strtok_set(fluid_strtok_t* st, char* s, char* d)
|
||||
{
|
||||
/* Careful! the strings are not copied for speed */
|
||||
st->string = s;
|
||||
st->delimiters = d;
|
||||
st->offset = 0;
|
||||
st->len = (s == NULL)? 0 : strlen(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* fluid_strtok_next_token(fluid_strtok_t* st)
|
||||
{
|
||||
int start = st->offset;
|
||||
int end;
|
||||
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||
return NULL;
|
||||
}
|
||||
if (start >= st->len) {
|
||||
return NULL;
|
||||
}
|
||||
while (fluid_strtok_char_index(st->string[start], st->delimiters) >= 0) {
|
||||
if (start == st->len) {
|
||||
return NULL;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
end = start + 1;
|
||||
while (fluid_strtok_char_index(st->string[end], st->delimiters) < 0) {
|
||||
if (end == st->len) {
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
st->string[end] = 0;
|
||||
st->offset = end + 1;
|
||||
return &st->string[start];
|
||||
}
|
||||
|
||||
int fluid_strtok_has_more(fluid_strtok_t* st)
|
||||
{
|
||||
int cur = st->offset;
|
||||
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||
return -1;
|
||||
}
|
||||
while (cur < st->len) {
|
||||
if (fluid_strtok_char_index(st->string[cur], st->delimiters) < 0) {
|
||||
return -1;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fluid_strtok_char_index(char c, char* s)
|
||||
{
|
||||
int i;
|
||||
if (s == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; s[i] != 0; i++) {
|
||||
if (s[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/* 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_STRTOK_H
|
||||
#define _FLUID_STRTOK_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
|
||||
/** string tokenizer */
|
||||
typedef struct {
|
||||
char* string;
|
||||
char* delimiters;
|
||||
int offset;
|
||||
int len;
|
||||
} fluid_strtok_t;
|
||||
|
||||
fluid_strtok_t* new_fluid_strtok(char* s, char* d);
|
||||
int delete_fluid_strtok(fluid_strtok_t* st);
|
||||
int fluid_strtok_set(fluid_strtok_t* st, char* s, char* d);
|
||||
char* fluid_strtok_next_token(fluid_strtok_t* st);
|
||||
int fluid_strtok_has_more(fluid_strtok_t* st);
|
||||
int fluid_strtok_char_index(char c, char* s);
|
||||
|
||||
|
||||
#endif /* _FLUID_STRTOK_H */
|
||||
@@ -18,6 +18,7 @@
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_sys.h"
|
||||
@@ -26,6 +27,14 @@
|
||||
#include "fluid_settings.h"
|
||||
#include "fluid_sfont.h"
|
||||
|
||||
#ifdef TRAP_ON_FPE
|
||||
#define _GNU_SOURCE
|
||||
#include <fenv.h>
|
||||
|
||||
/* seems to not be declared in fenv.h */
|
||||
extern int feenableexcept (int excepts);
|
||||
#endif
|
||||
|
||||
|
||||
fluid_sfloader_t* new_fluid_defsfloader(void);
|
||||
|
||||
@@ -58,6 +67,7 @@ int fluid_synth_set_gen2(fluid_synth_t* synth, int chan,
|
||||
/* has the synth module been initialized? */
|
||||
static int fluid_synth_initialized = 0;
|
||||
static void fluid_synth_init(void);
|
||||
static void init_dither(void);
|
||||
|
||||
/* default modulators
|
||||
* SF2.01 page 52 ff:
|
||||
@@ -150,12 +160,19 @@ fluid_synth_init()
|
||||
{
|
||||
fluid_synth_initialized++;
|
||||
|
||||
#ifdef TRAP_ON_FPE
|
||||
/* Turn on floating point exception traps */
|
||||
feenableexcept (FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID);
|
||||
#endif
|
||||
|
||||
fluid_conversion_config();
|
||||
|
||||
fluid_voice_config();
|
||||
fluid_dsp_float_config();
|
||||
|
||||
fluid_sys_config();
|
||||
|
||||
init_dither();
|
||||
|
||||
|
||||
/* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
|
||||
fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */
|
||||
@@ -460,91 +477,62 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the sample buffers
|
||||
*
|
||||
* GCC seems to have a bug with alignment (address must be multiple
|
||||
* of 16 bytes. So we have to align for ourselves... As soon as
|
||||
* GCC aligns reliably, this mess can be cleaned up.
|
||||
*/
|
||||
|
||||
/* Allocate the sample buffers */
|
||||
synth->left_buf = NULL;
|
||||
synth->right_buf = NULL;
|
||||
synth->left_ubuf = NULL;
|
||||
synth->right_ubuf = NULL;
|
||||
synth->fx_left_buf = NULL;
|
||||
synth->fx_right_buf = NULL;
|
||||
synth->fx_left_ubuf = NULL;
|
||||
synth->fx_right_ubuf = NULL;
|
||||
|
||||
/* Left and right audio buffers */
|
||||
|
||||
synth->left_buf = FLUID_ARRAY(fluid_real_t*, synth->nbuf);
|
||||
synth->right_buf = FLUID_ARRAY(fluid_real_t*, synth->nbuf);
|
||||
synth->left_ubuf = FLUID_ARRAY(fluid_real_t*, synth->nbuf);
|
||||
synth->right_ubuf = FLUID_ARRAY(fluid_real_t*, synth->nbuf);
|
||||
|
||||
if ((synth->left_buf == NULL) || (synth->right_buf == NULL) ||
|
||||
(synth->left_ubuf == NULL) || (synth->right_ubuf == NULL)) {
|
||||
if ((synth->left_buf == NULL) || (synth->right_buf == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(synth->left_buf, 0, synth->nbuf * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(synth->right_buf, 0, synth->nbuf * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(synth->left_ubuf, 0, synth->nbuf * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(synth->right_ubuf, 0, synth->nbuf * sizeof(fluid_real_t*));
|
||||
|
||||
for (i = 0; i < synth->nbuf; i++) {
|
||||
|
||||
/* +4: add four floats for 16 added bytes */
|
||||
synth->left_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
|
||||
synth->right_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
|
||||
|
||||
synth->left_ubuf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE + 4);
|
||||
synth->right_ubuf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE + 4);
|
||||
|
||||
if ((synth->left_ubuf[i] == NULL) || (synth->right_ubuf[i] == NULL)) {
|
||||
if ((synth->left_buf[i] == NULL) || (synth->right_buf[i] == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
synth->left_buf[i] = (fluid_real_t*) FLUID_ALIGN16BYTE(synth->left_ubuf[i]);
|
||||
synth->right_buf[i] = (fluid_real_t*) FLUID_ALIGN16BYTE(synth->right_ubuf[i]);
|
||||
}
|
||||
|
||||
/* Effects audio buffers */
|
||||
|
||||
synth->fx_left_buf = FLUID_ARRAY(fluid_real_t*, synth->effects_channels);
|
||||
synth->fx_right_buf = FLUID_ARRAY(fluid_real_t*, synth->effects_channels);
|
||||
synth->fx_left_ubuf = FLUID_ARRAY(fluid_real_t*, synth->effects_channels);
|
||||
synth->fx_right_ubuf = FLUID_ARRAY(fluid_real_t*, synth->effects_channels);
|
||||
|
||||
if ((synth->fx_left_buf == NULL) || (synth->fx_left_ubuf == NULL) ||
|
||||
(synth->fx_right_buf == NULL) || (synth->fx_right_ubuf == NULL)) {
|
||||
if ((synth->fx_left_buf == NULL) || (synth->fx_right_buf == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(synth->fx_left_ubuf, 0, 2 * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(synth->fx_left_buf, 0, 2 * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(synth->fx_right_ubuf, 0, 2 * sizeof(fluid_real_t*));
|
||||
FLUID_MEMSET(synth->fx_right_buf, 0, 2 * sizeof(fluid_real_t*));
|
||||
|
||||
for (i = 0; i < synth->effects_channels; i++) {
|
||||
synth->fx_left_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
|
||||
synth->fx_right_buf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE);
|
||||
|
||||
/* +4: add four floats for 16 added bytes */
|
||||
synth->fx_left_ubuf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE + 4);
|
||||
synth->fx_right_ubuf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE + 4);
|
||||
|
||||
if ((synth->fx_left_ubuf[i] == NULL) || (synth->fx_right_ubuf[i] == NULL)) {
|
||||
if ((synth->fx_left_buf[i] == NULL) || (synth->fx_right_buf[i] == NULL)) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
synth->fx_left_buf[i] = (fluid_real_t*) FLUID_ALIGN16BYTE(synth->fx_left_ubuf[i]);
|
||||
synth->fx_right_buf[i] = (fluid_real_t*) FLUID_ALIGN16BYTE(synth->fx_right_ubuf[i]);
|
||||
}
|
||||
|
||||
|
||||
synth->cur = FLUID_BUFSIZE;
|
||||
synth->dither_index = 0;
|
||||
|
||||
/* allocate the reverb module */
|
||||
synth->reverb = new_fluid_revmodel();
|
||||
@@ -596,6 +584,14 @@ delete_fluid_synth(fluid_synth_t* synth)
|
||||
|
||||
synth->state = FLUID_SYNTH_STOPPED;
|
||||
|
||||
/* turn off all voices, needed to unload SoundFont data */
|
||||
if (synth->voice != NULL) {
|
||||
for (i = 0; i < synth->nvoice; i++) {
|
||||
if (synth->voice[i] && fluid_voice_is_playing (synth->voice[i]))
|
||||
fluid_voice_off (synth->voice[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* delete all the SoundFonts */
|
||||
for (list = synth->sfont; list; list = fluid_list_next(list)) {
|
||||
sfont = (fluid_sfont_t*) fluid_list_get(list);
|
||||
@@ -642,31 +638,40 @@ delete_fluid_synth(fluid_synth_t* synth)
|
||||
}
|
||||
|
||||
/* free all the sample buffers */
|
||||
if (synth->left_ubuf != NULL) {
|
||||
if (synth->left_buf != NULL) {
|
||||
for (i = 0; i < synth->nbuf; i++) {
|
||||
if (synth->left_ubuf[i] != NULL) {
|
||||
FLUID_FREE(synth->left_ubuf[i]);
|
||||
if (synth->left_buf[i] != NULL) {
|
||||
FLUID_FREE(synth->left_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(synth->left_ubuf);
|
||||
FLUID_FREE(synth->left_buf);
|
||||
}
|
||||
|
||||
if (synth->right_ubuf != NULL) {
|
||||
if (synth->right_buf != NULL) {
|
||||
for (i = 0; i < synth->nbuf; i++) {
|
||||
if (synth->right_ubuf[i] != NULL) {
|
||||
FLUID_FREE(synth->right_ubuf[i]);
|
||||
if (synth->right_buf[i] != NULL) {
|
||||
FLUID_FREE(synth->right_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(synth->right_ubuf);
|
||||
FLUID_FREE(synth->right_buf);
|
||||
}
|
||||
|
||||
if (synth->fx_left_ubuf != NULL) {
|
||||
if (synth->fx_left_buf != NULL) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (synth->fx_left_ubuf[i] != NULL) {
|
||||
FLUID_FREE(synth->fx_left_ubuf[i]);
|
||||
if (synth->fx_left_buf[i] != NULL) {
|
||||
FLUID_FREE(synth->fx_left_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(synth->fx_left_ubuf);
|
||||
FLUID_FREE(synth->fx_left_buf);
|
||||
}
|
||||
|
||||
if (synth->fx_right_buf != NULL) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (synth->fx_right_buf[i] != NULL) {
|
||||
FLUID_FREE(synth->fx_right_buf[i]);
|
||||
}
|
||||
}
|
||||
FLUID_FREE(synth->fx_right_buf);
|
||||
}
|
||||
|
||||
/* release the reverb module */
|
||||
@@ -1675,6 +1680,37 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DITHER_SIZE 48000
|
||||
#define DITHER_CHANNELS 2
|
||||
|
||||
static float rand_table[DITHER_CHANNELS][DITHER_SIZE];
|
||||
|
||||
static void init_dither(void)
|
||||
{
|
||||
float d, dp;
|
||||
int c, i;
|
||||
|
||||
for (c = 0; c < DITHER_CHANNELS; c++) {
|
||||
dp = 0;
|
||||
for (i = 0; i < DITHER_SIZE-1; i++) {
|
||||
d = rand() / (float)RAND_MAX - 0.5f;
|
||||
rand_table[c][i] = d - dp;
|
||||
dp = d;
|
||||
}
|
||||
rand_table[c][DITHER_SIZE-1] = 0 - dp;
|
||||
}
|
||||
}
|
||||
|
||||
/* A portable replacement for roundf(), seems it may actually be faster too! */
|
||||
static inline int
|
||||
roundi (float x)
|
||||
{
|
||||
if (x >= 0.0f)
|
||||
return (int)(x+0.5f);
|
||||
else
|
||||
return (int)(x-0.5f);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_synth_write_s16
|
||||
*/
|
||||
@@ -1692,6 +1728,8 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
||||
fluid_real_t left_sample;
|
||||
fluid_real_t right_sample;
|
||||
double time = fluid_utime();
|
||||
int di = synth->dither_index;
|
||||
double prof_ref_on_block;
|
||||
|
||||
/* make sure we're playing */
|
||||
if (synth->state != FLUID_SYNTH_PLAYING) {
|
||||
@@ -1704,8 +1742,7 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
||||
|
||||
/* fill up the buffers as needed */
|
||||
if (cur == FLUID_BUFSIZE) {
|
||||
|
||||
double prof_ref_on_block = fluid_profile_ref();
|
||||
prof_ref_on_block = fluid_profile_ref();
|
||||
|
||||
fluid_synth_one_block(synth, 0);
|
||||
cur = 0;
|
||||
@@ -1713,27 +1750,24 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref_on_block);
|
||||
}
|
||||
|
||||
left_sample=left_in[cur]* 32767.0f;
|
||||
right_sample=right_in[cur] * 32767.0f;
|
||||
left_sample = roundi (left_in[cur] * 32766.0f + rand_table[0][di]);
|
||||
right_sample = roundi (right_in[cur] * 32766.0f + rand_table[1][di]);
|
||||
|
||||
di++;
|
||||
if (di >= DITHER_SIZE) di = 0;
|
||||
|
||||
/* digital clipping */
|
||||
if (left_sample > 32767.0f) {
|
||||
left_sample = 32767;
|
||||
}
|
||||
if (left_sample < -32768.0f) {
|
||||
left_sample = -32768;
|
||||
}
|
||||
if (right_sample > 32767.0f) {
|
||||
right_sample = 32767;
|
||||
}
|
||||
if (right_sample < -32768.0f) {
|
||||
right_sample = -32768;
|
||||
}
|
||||
if (left_sample > 32767.0f) left_sample = 32767.0f;
|
||||
if (left_sample < -32768.0f) left_sample = -32768.0f;
|
||||
if (right_sample > 32767.0f) right_sample = 32767.0f;
|
||||
if (right_sample < -32768.0f) right_sample = -32768.0f;
|
||||
|
||||
left_out[j] = (signed short) left_sample;
|
||||
right_out[k] = (signed short) right_sample;
|
||||
}
|
||||
|
||||
synth->cur = cur;
|
||||
synth->dither_index = di; /* keep dither buffer continous */
|
||||
|
||||
fluid_profile(FLUID_PROF_WRITE_S16, prof_ref);
|
||||
|
||||
@@ -1747,6 +1781,49 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_synth_dither_s16
|
||||
* Converts stereo floating point sample data to signed 16 bit data with
|
||||
* dithering. 'dither_index' parameter is a caller supplied pointer to an
|
||||
* integer which should be initialized to 0 before the first call and passed
|
||||
* unmodified to additional calls which are part of the same synthesis output.
|
||||
* Only used internally currently.
|
||||
*/
|
||||
void
|
||||
fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr)
|
||||
{
|
||||
int i, j, k;
|
||||
signed short* left_out = (signed short*) lout;
|
||||
signed short* right_out = (signed short*) rout;
|
||||
double prof_ref = fluid_profile_ref();
|
||||
fluid_real_t left_sample;
|
||||
fluid_real_t right_sample;
|
||||
int di = *dither_index;
|
||||
|
||||
for (i = 0, j = loff, k = roff; i < len; i++, j += lincr, k += rincr) {
|
||||
|
||||
left_sample = roundi (lin[i] * 32766.0f + rand_table[0][di]);
|
||||
right_sample = roundi (rin[i] * 32766.0f + rand_table[1][di]);
|
||||
|
||||
di++;
|
||||
if (di >= DITHER_SIZE) di = 0;
|
||||
|
||||
/* digital clipping */
|
||||
if (left_sample > 32767.0f) left_sample = 32767.0f;
|
||||
if (left_sample < -32768.0f) left_sample = -32768.0f;
|
||||
if (right_sample > 32767.0f) right_sample = 32767.0f;
|
||||
if (right_sample < -32768.0f) right_sample = -32768.0f;
|
||||
|
||||
left_out[j] = (signed short) left_sample;
|
||||
right_out[k] = (signed short) right_sample;
|
||||
}
|
||||
|
||||
*dither_index = di; /* keep dither buffer continous */
|
||||
|
||||
fluid_profile(FLUID_PROF_WRITE_S16, prof_ref);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_synth_one_block
|
||||
@@ -1772,6 +1849,7 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
||||
FLUID_MEMSET(synth->left_buf[i], 0, byte_size);
|
||||
FLUID_MEMSET(synth->right_buf[i], 0, byte_size);
|
||||
}
|
||||
|
||||
for (i = 0; i < synth->effects_channels; i++) {
|
||||
FLUID_MEMSET(synth->fx_left_buf[i], 0, byte_size);
|
||||
FLUID_MEMSET(synth->fx_right_buf[i], 0, byte_size);
|
||||
@@ -1781,18 +1859,8 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
||||
* enabled on synth level. Nonexisting buffers are detected in the
|
||||
* DSP loop. Not sending the reverb / chorus signal saves some time
|
||||
* in that case. */
|
||||
if (synth->with_reverb) {
|
||||
reverb_buf = synth->fx_left_buf[0];
|
||||
} else {
|
||||
reverb_buf = NULL;
|
||||
}
|
||||
|
||||
if (synth->with_chorus) {
|
||||
chorus_buf = synth->fx_left_buf[1];
|
||||
} else {
|
||||
chorus_buf = NULL;
|
||||
}
|
||||
|
||||
reverb_buf = synth->with_reverb ? synth->fx_left_buf[0] : NULL;
|
||||
chorus_buf = synth->with_chorus ? synth->fx_left_buf[1] : NULL;
|
||||
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref);
|
||||
|
||||
@@ -1825,6 +1893,7 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref_voice);
|
||||
}
|
||||
}
|
||||
|
||||
fluid_check_fpe("Synthesis processes");
|
||||
|
||||
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref);
|
||||
|
||||
@@ -128,14 +128,10 @@ struct _fluid_synth_t
|
||||
fluid_real_t** fx_left_buf;
|
||||
fluid_real_t** fx_right_buf;
|
||||
|
||||
fluid_real_t** left_ubuf; /* Stores the unaligned buffers (see new_fluid_synth) */
|
||||
fluid_real_t** right_ubuf; /* Stores the unaligned buffers (see new_fluid_synth) */
|
||||
fluid_real_t** fx_left_ubuf; /* Stores the unaligned buffers (see new_fluid_synth) */
|
||||
fluid_real_t** fx_right_ubuf; /* Stores the unaligned buffers (see new_fluid_synth) */
|
||||
|
||||
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 */
|
||||
double cpu_load;
|
||||
@@ -153,7 +149,6 @@ struct _fluid_synth_t
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/** returns 1 if the value has been set, 0 otherwise */
|
||||
int fluid_synth_setstr(fluid_synth_t* synth, char* name, char* str);
|
||||
|
||||
@@ -210,8 +205,9 @@ int fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value);
|
||||
fluid_bank_offset_t* fluid_synth_get_bank_offset0(fluid_synth_t* synth, int sfont_id);
|
||||
void fluid_synth_remove_bank_offset(fluid_synth_t* synth, int sfont_id);
|
||||
|
||||
|
||||
|
||||
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);
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
|
||||
#include "fluid_sys.h"
|
||||
//#include <fpu_control.h>
|
||||
|
||||
static char fluid_errbuf[512]; /* buffer for error message */
|
||||
|
||||
@@ -63,8 +62,12 @@ int fluid_debug(int level, char * fmt, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fluid_set_log_function
|
||||
/**
|
||||
* Installs a new log function for a specified log level.
|
||||
* @param level Log level to install handler for.
|
||||
* @param fun Callback function handler to call for logged messages
|
||||
* @param data User supplied data pointer to pass to log function
|
||||
* @return The previously installed function.
|
||||
*/
|
||||
fluid_log_function_t
|
||||
fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
|
||||
@@ -79,8 +82,11 @@ fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
|
||||
return old;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_default_log_function
|
||||
/**
|
||||
* Default log function which prints to the stderr.
|
||||
* @param level Log level
|
||||
* @param message Log message
|
||||
* @param data User supplied data (not used)
|
||||
*/
|
||||
void
|
||||
fluid_default_log_function(int level, char* message, void* data)
|
||||
@@ -154,8 +160,12 @@ fluid_log_config(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_log
|
||||
/**
|
||||
* Print a message to the log.
|
||||
* @param level Log level (#fluid_log_level).
|
||||
* @param fmt Printf style format string for log message
|
||||
* @param ... Arguments for printf 'fmt' message string
|
||||
* @return Always returns -1
|
||||
*/
|
||||
int
|
||||
fluid_log(int level, char* fmt, ...)
|
||||
@@ -176,6 +186,75 @@ fluid_log(int level, char* fmt, ...)
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* An improved strtok, still trashes the input string, but is portable and
|
||||
* thread safe. Also skips token chars at beginning of token string and never
|
||||
* returns an empty token (will return NULL if source ends in token chars though).
|
||||
* NOTE: NOT part of public API
|
||||
* @internal
|
||||
* @param str Pointer to a string pointer of source to tokenize. Pointer gets
|
||||
* updated on each invocation to point to beginning of next token. Note that
|
||||
* token char get's overwritten with a 0 byte. String pointer is set to NULL
|
||||
* when final token is returned.
|
||||
* @param delim String of delimiter chars.
|
||||
* @return Pointer to the next token or NULL if no more tokens.
|
||||
*/
|
||||
char *fluid_strtok (char **str, char *delim)
|
||||
{
|
||||
char *s, *d, *token;
|
||||
char c;
|
||||
|
||||
if (str == NULL || delim == NULL || !*delim)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = *str;
|
||||
if (!s) return NULL; /* str points to a NULL pointer? (tokenize already ended) */
|
||||
|
||||
/* skip delimiter chars at beginning of token */
|
||||
do
|
||||
{
|
||||
c = *s;
|
||||
if (!c) /* end of source string? */
|
||||
{
|
||||
*str = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (d = delim; *d; d++) /* is source char a token char? */
|
||||
{
|
||||
if (c == *d) /* token char match? */
|
||||
{
|
||||
s++; /* advance to next source char */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (*d); /* while token char match */
|
||||
|
||||
token = s; /* start of token found */
|
||||
|
||||
/* search for next token char or end of source string */
|
||||
for (s = s+1; *s; s++)
|
||||
{
|
||||
c = *s;
|
||||
|
||||
for (d = delim; *d; d++) /* is source char a token char? */
|
||||
{
|
||||
if (c == *d) /* token char match? */
|
||||
{
|
||||
*s = '\0'; /* overwrite token char with zero byte to terminate token */
|
||||
*str = s+1; /* update str to point to beginning of next token */
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we get here only if source string ended */
|
||||
*str = NULL;
|
||||
return token;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_error
|
||||
@@ -555,6 +634,7 @@ unsigned int fluid_curtime()
|
||||
return (ms);
|
||||
}
|
||||
|
||||
|
||||
#elif __BEOS__
|
||||
|
||||
struct _fluid_timer_t
|
||||
@@ -806,6 +886,7 @@ void fluid_time_config(void)
|
||||
{
|
||||
if (fluid_cpu_frequency < 0.0) {
|
||||
fluid_cpu_frequency = fluid_estimate_cpu_frequency() / 1000000.0;
|
||||
if (fluid_cpu_frequency == 0.0) fluid_cpu_frequency = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,7 +947,7 @@ double fluid_estimate_cpu_frequency(void)
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
#ifdef FPE_CHECK
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
@@ -900,7 +981,8 @@ double fluid_estimate_cpu_frequency(void)
|
||||
#define _FPU_CLR_SW() __asm__ ("fnclex" : : )
|
||||
|
||||
/* Purpose:
|
||||
* Checks, if the floating point unit has produced an exception in the meantime.
|
||||
* Checks, if the floating point unit has produced an exception, print a message
|
||||
* if so and clear the exception.
|
||||
*/
|
||||
unsigned int fluid_check_fpe_i386(char* explanation)
|
||||
{
|
||||
@@ -909,11 +991,10 @@ unsigned int fluid_check_fpe_i386(char* explanation)
|
||||
_FPU_GET_SW(s);
|
||||
_FPU_CLR_SW();
|
||||
|
||||
if ((s & _FPU_STATUS_IE)
|
||||
|| (s & _FPU_STATUS_DE)
|
||||
|| (s & _FPU_STATUS_ZE)
|
||||
|| (s & _FPU_STATUS_OE)
|
||||
|| (s & _FPU_STATUS_UE)) {
|
||||
s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
|
||||
|
||||
if (s)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
|
||||
(s & _FPU_STATUS_IE) ? "Invalid operation " : "",
|
||||
(s & _FPU_STATUS_DE) ? "Denormal number " : "",
|
||||
@@ -925,10 +1006,18 @@ unsigned int fluid_check_fpe_i386(char* explanation)
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Purpose:
|
||||
* Clear floating point exception.
|
||||
*/
|
||||
void fluid_clear_fpe_i386 (void)
|
||||
{
|
||||
_FPU_CLR_SW();
|
||||
}
|
||||
|
||||
#endif // ifdef FPE_CHECK
|
||||
|
||||
|
||||
#endif
|
||||
#endif // #else (its POSIX)
|
||||
|
||||
|
||||
/***************************************************************
|
||||
|
||||
@@ -43,6 +43,13 @@ void fluid_sys_config(void);
|
||||
void fluid_log_config(void);
|
||||
void fluid_time_config(void);
|
||||
|
||||
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
char *fluid_strtok (char **str, char *delim);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Additional debugging system, separate from the log system. This
|
||||
@@ -153,6 +160,7 @@ typedef pthread_mutex_t fluid_mutex_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Threads
|
||||
|
||||
@@ -291,15 +299,15 @@ extern fluid_profile_data_t fluid_profile_data[];
|
||||
fluid_check_fpe() checks for "unnormalized numbers" and other
|
||||
exceptions of the floating point processsor.
|
||||
*/
|
||||
#if 0
|
||||
/* Enable FPE exception check */
|
||||
#ifdef FPE_CHECK
|
||||
#define fluid_check_fpe(expl) fluid_check_fpe_i386(expl)
|
||||
#define fluid_clear_fpe() fluid_clear_fpe_i386()
|
||||
#else
|
||||
/* Disable FPE exception check */
|
||||
#define fluid_check_fpe(expl)
|
||||
#define fluid_clear_fpe()
|
||||
#endif
|
||||
|
||||
unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe);
|
||||
void fluid_clear_fpe_i386(void);
|
||||
|
||||
#endif /* _FLUID_SYS_H */
|
||||
|
||||
|
||||
@@ -27,18 +27,6 @@
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_sfont.h"
|
||||
|
||||
#ifndef WITH_FLOAT
|
||||
#ifdef ENABLE_SSE
|
||||
#error "Can't use SSE extensions with other than float type!"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SSE
|
||||
#include "fluid_sse.h"
|
||||
float interp_coeff_sse_mem[FLUID_INTERP_MAX*4+4];
|
||||
sse_t* interp_coeff_sse;
|
||||
#endif
|
||||
|
||||
/* used for filter turn off optimization - if filter cutoff is above the
|
||||
specified value and filter q is below the other value, turn filter off */
|
||||
#define FLUID_MAX_AUDIBLE_FILTER_FC 19000.0f
|
||||
@@ -52,83 +40,17 @@ sse_t* interp_coeff_sse;
|
||||
|
||||
/* these should be the absolute minimum that FluidSynth can deal with */
|
||||
#define FLUID_MIN_LOOP_SIZE 2
|
||||
#define FLUID_MIN_LOOP_PAD 1
|
||||
#define FLUID_MIN_LOOP_PAD 0
|
||||
|
||||
/* min vol envelope release (to stop clicks) in SoundFont timecents */
|
||||
#define FLUID_MIN_VOLENVRELEASE -7200.0f /* ~16ms */
|
||||
|
||||
fluid_interp_coeff_t interp_coeff[FLUID_INTERP_MAX];
|
||||
fluid_interp_coeff_t interp_coeff_linear[FLUID_INTERP_MAX];
|
||||
fluid_real_t sinc_table7[7][FLUID_INTERP_MAX];
|
||||
|
||||
/*
|
||||
* fluid_voice_config
|
||||
*/
|
||||
void fluid_voice_config()
|
||||
{
|
||||
int i;
|
||||
double x;
|
||||
|
||||
#ifdef ENABLE_SSE
|
||||
sse_t* sse_a;
|
||||
interp_coeff_sse = (sse_t*)FLUID_ALIGN16BYTE(&interp_coeff_sse_mem);
|
||||
#endif
|
||||
|
||||
/* Initialize the coefficients for the interpolation. The math comes
|
||||
* from a mail, posted by Olli Niemitalo to the music-dsp mailing
|
||||
* list (I found it in the music-dsp archives
|
||||
* http://www.smartelectronix.com/musicdsp/). */
|
||||
|
||||
for (i = 0; i < FLUID_INTERP_MAX; i++) {
|
||||
|
||||
x = (double) i / (double) FLUID_INTERP_MAX;
|
||||
|
||||
interp_coeff[i].a0 = (fluid_real_t) (x * (-0.5 + x * (1 - 0.5 * x)));
|
||||
interp_coeff[i].a1 = (fluid_real_t) (1.0 + x * x * (1.5 * x - 2.5));
|
||||
interp_coeff[i].a2 = (fluid_real_t) (x * (0.5 + x * (2.0 - 1.5 * x)));
|
||||
interp_coeff[i].a3 = (fluid_real_t) (0.5 * x * x * (x - 1.0));
|
||||
|
||||
interp_coeff_linear[i].a0 = (fluid_real_t) (1. -x);
|
||||
interp_coeff_linear[i].a1 = (fluid_real_t) x;
|
||||
|
||||
#if 0
|
||||
interp_coeff[i].c0 = (signed int) (65536.0 * x * (-0.5 + x * (1 - 0.5 * x)));
|
||||
interp_coeff[i].c1 = (signed int) (65536.0 * (1.0 + x * x * (1.5 * x - 2.5)));
|
||||
interp_coeff[i].c2 = (signed int) (65536.0 * x * (0.5 + x * (2.0 - 1.5 * x)));
|
||||
interp_coeff[i].c3 = (signed int) (65536.0 * 0.5 * x * x * (x - 1.0));
|
||||
#endif
|
||||
#ifdef ENABLE_SSE
|
||||
sse_a=&interp_coeff_sse[i];
|
||||
sse_a->sf[0]=interp_coeff[i].a0;
|
||||
sse_a->sf[1]=interp_coeff[i].a1;
|
||||
sse_a->sf[2]=interp_coeff[i].a2;
|
||||
sse_a->sf[3]=interp_coeff[i].a3;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define sinc_interp_order 7
|
||||
/* i: Offset in terms of whole samples */
|
||||
for (i = 0; i < sinc_interp_order; i++){
|
||||
int ii;
|
||||
/* ii: Offset in terms of fractional samples ('subsamples') */
|
||||
for (ii = 0; ii < FLUID_INTERP_MAX; ii++){
|
||||
/* Move the origin into the center of the table */
|
||||
double i_shifted=(double)i-((double)sinc_interp_order)/2.
|
||||
+ (double)ii/(double)FLUID_INTERP_MAX;
|
||||
double v=1.;
|
||||
|
||||
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
|
||||
if (fabs(i_shifted) > 0.000001) {
|
||||
v = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
|
||||
/* Hamming window */
|
||||
v *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)sinc_interp_order));
|
||||
}
|
||||
sinc_table7[i][FLUID_INTERP_MAX-ii-1]=v;
|
||||
}
|
||||
}
|
||||
fluid_check_fpe("interpolation table calculation");
|
||||
}
|
||||
|
||||
static inline void fluid_voice_effects (fluid_voice_t *voice, int count,
|
||||
fluid_real_t* dsp_left_buf,
|
||||
fluid_real_t* dsp_right_buf,
|
||||
fluid_real_t* dsp_reverb_buf,
|
||||
fluid_real_t* dsp_chorus_buf);
|
||||
/*
|
||||
* new_fluid_voice
|
||||
*/
|
||||
@@ -324,93 +246,57 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf,
|
||||
fluid_real_t* dsp_reverb_buf, fluid_real_t* dsp_chorus_buf)
|
||||
{
|
||||
unsigned int i, start, end_in_buffer;
|
||||
unsigned int i;
|
||||
fluid_real_t incr;
|
||||
fluid_real_t fres;
|
||||
fluid_real_t target_amp; /* target amplitude */
|
||||
int count;
|
||||
|
||||
/* All variables starting with dsp_ are used by the DSP
|
||||
loop. Documented in fluid_dsp_core.c */
|
||||
|
||||
int dsp_phase_index;
|
||||
unsigned int dsp_i;
|
||||
fluid_phase_t dsp_phase, dsp_phase_incr;
|
||||
fluid_real_t dsp_incr;
|
||||
fluid_real_t dsp_amp, dsp_amp_incr, dsp_centernode, dsp_hist1, dsp_hist2;
|
||||
fluid_real_t dsp_b02, dsp_b1, dsp_a1, dsp_a2;
|
||||
fluid_real_t dsp_a1_incr;
|
||||
fluid_real_t dsp_a2_incr;
|
||||
fluid_real_t dsp_b02_incr;
|
||||
fluid_real_t dsp_b1_incr;
|
||||
fluid_interp_coeff_t* dsp_coeff;
|
||||
unsigned int dsp_start, dsp_end;
|
||||
int dsp_filter_coeff_incr_count;
|
||||
int dsp_use_filter_flag = 1;
|
||||
short* dsp_data;
|
||||
int dsp_interp_method = voice->interp_method;
|
||||
|
||||
|
||||
#ifdef ENABLE_SSE
|
||||
float mem_for_sse_interface[5*4+4]; /* Reserve memory */
|
||||
/* +4: add four floats for 16 added bytes */
|
||||
|
||||
/* Align the first element */
|
||||
sse_t* sse_n = (sse_t*) FLUID_ALIGN16BYTE(&mem_for_sse_interface);
|
||||
sse_t* sse_a = sse_n++; /* The ++ operator increases
|
||||
* by the size of the structure! */
|
||||
sse_t* sse_b = sse_n++;
|
||||
sse_t* sse_c = sse_n++;
|
||||
sse_t* sse_d = sse_n++;
|
||||
sse_t* sse_e = sse_n++;
|
||||
sse_t* sse_coeff;
|
||||
|
||||
sse_t* sse_src;
|
||||
sse_t* sse_dest_left;
|
||||
sse_t* sse_dest_right;
|
||||
sse_t* sse_dest;
|
||||
#endif
|
||||
|
||||
/* +4: add four floats for 16 added bytes */
|
||||
fluid_real_t dsp_buf_unaligned[FLUID_BUFSIZE+4];
|
||||
fluid_real_t* dsp_buf = (fluid_real_t*) FLUID_ALIGN16BYTE(&dsp_buf_unaligned);
|
||||
fluid_real_t dsp_buf[FLUID_BUFSIZE];
|
||||
fluid_env_data_t* env_data;
|
||||
fluid_real_t x;
|
||||
|
||||
|
||||
/* make sure we're playing and that we have sample data */
|
||||
if (!_PLAYING(voice)) {
|
||||
return FLUID_OK;
|
||||
}
|
||||
if (!_PLAYING(voice)) return FLUID_OK;
|
||||
|
||||
/******************* sample **********************/
|
||||
|
||||
if (voice->sample == NULL) {
|
||||
if (voice->sample == NULL)
|
||||
{
|
||||
fluid_voice_off(voice);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
fluid_check_fpe("voice_write startup");
|
||||
fluid_check_fpe ("voice_write startup");
|
||||
|
||||
/* Range checking for sample- and loop-related parameters
|
||||
* Initial phase is calculated here*/
|
||||
fluid_voice_check_sample_sanity(voice);
|
||||
fluid_voice_check_sample_sanity (voice);
|
||||
|
||||
/******************* vol env **********************/
|
||||
|
||||
env_data = &voice->volenv_data[voice->volenv_section];
|
||||
|
||||
/* skip to the next section of the envelope if necessary */
|
||||
while (voice->volenv_count >= env_data->count) {
|
||||
while (voice->volenv_count >= env_data->count)
|
||||
{
|
||||
env_data = &voice->volenv_data[++voice->volenv_section];
|
||||
voice->volenv_count = 0;
|
||||
}
|
||||
|
||||
/* calculate the envelope value and check for valid range */
|
||||
x = env_data->coeff * voice->volenv_val + env_data->incr;
|
||||
if (x < env_data->min) {
|
||||
if (x < env_data->min)
|
||||
{
|
||||
x = env_data->min;
|
||||
voice->volenv_section++;
|
||||
voice->volenv_count = 0;
|
||||
} else if (x > env_data->max) {
|
||||
}
|
||||
else if (x > env_data->max)
|
||||
{
|
||||
x = env_data->max;
|
||||
voice->volenv_section++;
|
||||
voice->volenv_count = 0;
|
||||
@@ -419,19 +305,22 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
voice->volenv_val = x;
|
||||
voice->volenv_count++;
|
||||
|
||||
if (voice->volenv_section == FLUID_VOICE_ENVFINISHED) {
|
||||
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
|
||||
fluid_voice_off(voice);
|
||||
if (voice->volenv_section == FLUID_VOICE_ENVFINISHED)
|
||||
{
|
||||
fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref);
|
||||
fluid_voice_off (voice);
|
||||
return FLUID_OK;
|
||||
}
|
||||
fluid_check_fpe("voice_write vol env");
|
||||
|
||||
fluid_check_fpe ("voice_write vol env");
|
||||
|
||||
/******************* mod env **********************/
|
||||
|
||||
env_data = &voice->modenv_data[voice->modenv_section];
|
||||
|
||||
/* skip to the next section of the envelope if necessary */
|
||||
while (voice->modenv_count >= env_data->count) {
|
||||
while (voice->modenv_count >= env_data->count)
|
||||
{
|
||||
env_data = &voice->modenv_data[++voice->modenv_section];
|
||||
voice->modenv_count = 0;
|
||||
}
|
||||
@@ -439,11 +328,14 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
/* calculate the envelope value and check for valid range */
|
||||
x = env_data->coeff * voice->modenv_val + env_data->incr;
|
||||
|
||||
if (x < env_data->min) {
|
||||
if (x < env_data->min)
|
||||
{
|
||||
x = env_data->min;
|
||||
voice->modenv_section++;
|
||||
voice->modenv_count = 0;
|
||||
} else if (x > env_data->max) {
|
||||
}
|
||||
else if (x > env_data->max)
|
||||
{
|
||||
x = env_data->max;
|
||||
voice->modenv_section++;
|
||||
voice->modenv_count = 0;
|
||||
@@ -451,35 +343,47 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
|
||||
voice->modenv_val = x;
|
||||
voice->modenv_count++;
|
||||
fluid_check_fpe("voice_write mod env");
|
||||
fluid_check_fpe ("voice_write mod env");
|
||||
|
||||
/******************* mod lfo **********************/
|
||||
|
||||
if (voice->ticks >= voice->modlfo_delay) {
|
||||
if (voice->ticks >= voice->modlfo_delay)
|
||||
{
|
||||
voice->modlfo_val += voice->modlfo_incr;
|
||||
if (voice->modlfo_val > 1.0) {
|
||||
|
||||
if (voice->modlfo_val > 1.0)
|
||||
{
|
||||
voice->modlfo_incr = -voice->modlfo_incr;
|
||||
voice->modlfo_val = (fluid_real_t) 2.0 - voice->modlfo_val;
|
||||
} else if (voice->modlfo_val < -1.0) {
|
||||
}
|
||||
else if (voice->modlfo_val < -1.0)
|
||||
{
|
||||
voice->modlfo_incr = -voice->modlfo_incr;
|
||||
voice->modlfo_val = (fluid_real_t) -2.0 - voice->modlfo_val;
|
||||
}
|
||||
}
|
||||
fluid_check_fpe("voice_write mod LFO");
|
||||
|
||||
fluid_check_fpe ("voice_write mod LFO");
|
||||
|
||||
/******************* vib lfo **********************/
|
||||
|
||||
if (voice->ticks >= voice->viblfo_delay) {
|
||||
if (voice->ticks >= voice->viblfo_delay)
|
||||
{
|
||||
voice->viblfo_val += voice->viblfo_incr;
|
||||
if (voice->viblfo_val > (fluid_real_t) 1.0) {
|
||||
|
||||
if (voice->viblfo_val > (fluid_real_t) 1.0)
|
||||
{
|
||||
voice->viblfo_incr = -voice->viblfo_incr;
|
||||
voice->viblfo_val = (fluid_real_t) 2.0 - voice->viblfo_val;
|
||||
} else if (voice->viblfo_val < -1.0) {
|
||||
}
|
||||
else if (voice->viblfo_val < -1.0)
|
||||
{
|
||||
voice->viblfo_incr = -voice->viblfo_incr;
|
||||
voice->viblfo_val = (fluid_real_t) -2.0 - voice->viblfo_val;
|
||||
}
|
||||
}
|
||||
fluid_check_fpe("voice_write Vib LFO");
|
||||
|
||||
fluid_check_fpe ("voice_write Vib LFO");
|
||||
|
||||
/******************* amplitude **********************/
|
||||
|
||||
@@ -488,35 +392,28 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
* - amplitude envelope
|
||||
*/
|
||||
|
||||
if (voice->volenv_section == FLUID_VOICE_ENVDELAY) {
|
||||
/* The volume amplitude is in hold phase. No sound is produced. */
|
||||
goto post_process;
|
||||
} else if (voice->volenv_section == FLUID_VOICE_ENVATTACK) {
|
||||
if (voice->volenv_section == FLUID_VOICE_ENVDELAY)
|
||||
goto post_process; /* The volume amplitude is in hold phase. No sound is produced. */
|
||||
|
||||
if (voice->volenv_section == FLUID_VOICE_ENVATTACK)
|
||||
{
|
||||
/* the envelope is in the attack section: ramp linearly to max value.
|
||||
* A positive modlfo_to_vol should increase volume (negative attenuation).
|
||||
*/
|
||||
dsp_amp = fluid_atten2amp(voice->attenuation)
|
||||
target_amp = fluid_atten2amp (voice->attenuation)
|
||||
* fluid_cb2amp (voice->modlfo_val * -voice->modlfo_to_vol)
|
||||
* voice->volenv_val;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fluid_real_t amplitude_that_reaches_noise_floor;
|
||||
fluid_real_t amp_max;
|
||||
|
||||
dsp_amp = fluid_atten2amp(voice->attenuation)
|
||||
target_amp = fluid_atten2amp (voice->attenuation)
|
||||
* fluid_cb2amp (960.0f * (1.0f - voice->volenv_val)
|
||||
+ voice->modlfo_val * -voice->modlfo_to_vol);
|
||||
|
||||
/* Here we are trying to turn off a voice, if the volume has dropped
|
||||
* low enough.
|
||||
* Motivation:
|
||||
* If voices are not turned off as soon as possible, the
|
||||
* DSP loop burns a lot of CPU time producing sounds that no one
|
||||
* can hear
|
||||
* Problem:
|
||||
* It would be tempting to just look at the attenuation, but then
|
||||
* a voice terminates as soon as it is brought to 0 with a volume
|
||||
* pedal (MIDI CC 7 or 11).
|
||||
*/
|
||||
/* We turn off a voice, if the volume has dropped low enough. */
|
||||
|
||||
/* A voice can be turned off, when an estimate for the volume
|
||||
* (upper bound) falls below that volume, that will drop the
|
||||
@@ -526,19 +423,12 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
/* If the loop amplitude is known, we can use it if the voice loop is within
|
||||
* the sample loop
|
||||
*/
|
||||
#if 0
|
||||
printf("%i %i %i %i %i %i\n", voice->has_looped, voice->sample->amplitude_that_reaches_noise_floor_is_valid, voice->loopstart, voice->loopend, voice->sample->loopstart, voice->sample->loopend );
|
||||
#endif
|
||||
|
||||
/* Is the playing pointer already in the loop? */
|
||||
if (voice->has_looped){
|
||||
if (voice->has_looped)
|
||||
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor_loop;
|
||||
} else {
|
||||
else
|
||||
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor_nonloop;
|
||||
};
|
||||
#if 0
|
||||
printf("Retrieving %f\n", amplitude_that_reaches_noise_floor);
|
||||
#endif
|
||||
|
||||
/* voice->attenuation_min is a lower boundary for the attenuation
|
||||
* now and in the future (possibly 0 in the worst case). Now the
|
||||
@@ -546,79 +436,41 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
* volenv_val can only drop):
|
||||
*/
|
||||
|
||||
amp_max = fluid_atten2amp(voice->min_attenuation_cB) * voice->volenv_val;
|
||||
|
||||
/* printf("Att min: %f Amp max: %f Limit: %f\n",voice->min_attenuation_cB,amp_max, amplitude_that_reaches_noise_floor); */
|
||||
|
||||
// printf("Amp max: %f\n",amp_max);
|
||||
amp_max = fluid_atten2amp (voice->min_attenuation_cB) * voice->volenv_val;
|
||||
|
||||
/* And if amp_max is already smaller than the known amplitude,
|
||||
* which will attenuate the sample below the noise floor, then we
|
||||
* can safely turn off the voice. Duh. */
|
||||
if (amp_max < amplitude_that_reaches_noise_floor){
|
||||
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
|
||||
#if 0
|
||||
printf("Voice turned off! Amp is %f\n", amp_max);
|
||||
#endif
|
||||
fluid_voice_off(voice);
|
||||
if (amp_max < amplitude_that_reaches_noise_floor)
|
||||
{
|
||||
fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref);
|
||||
fluid_voice_off (voice);
|
||||
goto post_process;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point, dsp_amp is the desired amplitude for the voice.
|
||||
* This value will be reached at the end of the next buffer. So we
|
||||
* raise the amplitude smoothly from the current voice amplitude
|
||||
* (voice->amp) to the wanted amplitude dsp_amp.
|
||||
*
|
||||
* By how much do we have to increase voice->amp, so that it reaches
|
||||
* dsp_amp, when the increment is added FLUID_BUFSIZE times? */
|
||||
dsp_amp_incr = (dsp_amp - voice->amp) / FLUID_BUFSIZE;
|
||||
/* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
|
||||
voice->amp_incr = (target_amp - voice->amp) / FLUID_BUFSIZE;
|
||||
|
||||
/* dsp_amp will now be fed into the DSP loop. Use the amplitude,
|
||||
* that came out of the last DSP loop run. */
|
||||
dsp_amp = voice->amp;
|
||||
fluid_check_fpe ("voice_write amplitude calculation");
|
||||
|
||||
fluid_check_fpe("voice_write amplitude calculation");
|
||||
if ((dsp_amp == 0.0f) && (dsp_amp_incr == 0.0f)) {
|
||||
/* no volume and not changing? - No need to process */
|
||||
if ((voice->amp == 0.0f) && (voice->amp_incr == 0.0f))
|
||||
goto post_process;
|
||||
}
|
||||
|
||||
/* Calculate the number of samples, that the DSP loop advances
|
||||
* through the original waveform with each step in the output
|
||||
* buffer. It is the ratio between the frequencies of original
|
||||
* waveform and output waveform.*/
|
||||
incr = fluid_ct2hz_real(voice->pitch
|
||||
+ voice->modlfo_val * voice->modlfo_to_pitch
|
||||
voice->phase_incr = fluid_ct2hz_real
|
||||
(voice->pitch + voice->modlfo_val * voice->modlfo_to_pitch
|
||||
+ voice->viblfo_val * voice->viblfo_to_pitch
|
||||
+ voice->modenv_val * voice->modenv_to_pitch) / voice->root_pitch;
|
||||
|
||||
/* Transfer the phase from the voice into the dsp loop parameter
|
||||
dsp_phase */
|
||||
fluid_phase_set(dsp_phase, voice->phase);
|
||||
fluid_check_fpe ("voice_write phase calculation");
|
||||
|
||||
/* Convert the 'speed' through the original waveform to a
|
||||
* representation 'integer part' and 'fractional part' */
|
||||
fluid_phase_set_float(dsp_phase_incr, incr);
|
||||
/* incr *= 1.00000000000001; FIXME: gcc optimization problem. Quick fix. [Commented out. Don't understand the problem, PH] */
|
||||
fluid_check_fpe("voice_write phase calculation");
|
||||
|
||||
/* Check, if we are really making progress through the original
|
||||
* sample. If the step size is rounded to 0, the DSP loop would get
|
||||
* stuck. */
|
||||
/* [PH] I commented this out. The first time a voice is called, dsp_phase
|
||||
* will be zero. Settings the fractionnal part of the phase to
|
||||
* non-zero, causes the sample to be interpolated even if it is
|
||||
* played a the root key (cfr. fluid_dsp_float.c:96:
|
||||
* if ((fluid_phase_fract(dsp_phase) == 0)))
|
||||
*
|
||||
* I replaced it with a check on the phase increment.
|
||||
*/
|
||||
/* if ((fluid_phase_index(dsp_phase) == 0) && (fluid_phase_fract(dsp_phase) == 0)) { */
|
||||
/* fluid_phase_fract(dsp_phase) = 1; */
|
||||
/* } */
|
||||
if ((fluid_phase_index(dsp_phase_incr) == 0) && (fluid_phase_fract(dsp_phase_incr) == 0)) {
|
||||
fluid_phase_fract(dsp_phase_incr) = 1;
|
||||
}
|
||||
/* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
|
||||
if (voice->phase_incr == 0) voice->phase_incr = 1;
|
||||
|
||||
/*************** resonant filter ******************/
|
||||
|
||||
@@ -627,46 +479,27 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
+ voice->modlfo_val * voice->modlfo_to_fc
|
||||
+ voice->modenv_val * voice->modenv_to_fc);
|
||||
|
||||
/* Testcase for filter resonance: Use the following line, and press
|
||||
* A3. There should be a _very_ pronounced resonant peak, which
|
||||
* drops down, when moving the pitch bend wheel only slightly. */
|
||||
//fres=440;voice->q_lin=100;
|
||||
|
||||
|
||||
/* FIXME - Still potential for a click during turn on, can we interpolate
|
||||
between 20khz cutoff and 0 Q? */
|
||||
|
||||
/* if filter has not yet started and filter cutoff and Q don't
|
||||
exceed "audible" thresholds, then don't turn on the filter.
|
||||
Once the filter is turned on, it remains on. */
|
||||
/* if (voice->filter_startup */
|
||||
/* && (fres > FLUID_MAX_AUDIBLE_FILTER_FC) */
|
||||
/* && (voice->q_lin < FLUID_MIN_AUDIBLE_FILTER_Q)) { */
|
||||
/* dsp_use_filter_flag = 0; */
|
||||
/* } else if (fres < 5) { */
|
||||
/* fres = 5; */
|
||||
/* } */
|
||||
|
||||
/* I removed the optimization of turning the filter off when the
|
||||
* resonance frequence is above the maximum frequency. Instead, the
|
||||
* filter frequence is set to a maximum of 0.45 times the sampling
|
||||
* filter frequency is set to a maximum of 0.45 times the sampling
|
||||
* rate. For a 44100 kHz sampling rate, this amounts to 19845
|
||||
* Hz. The reasing is that were problems with anti-aliasing when the
|
||||
* Hz. The reason is that there were problems with anti-aliasing when the
|
||||
* synthesizer was run at lower sampling rates. Thanks to Stephan
|
||||
* Tassart for pointing me to this bug. By turning the filter on and
|
||||
* clipping the maximum filter frequency at 0.45*srate, the filter
|
||||
* is used as an anti-aliasing filter. */
|
||||
|
||||
if (fres > 0.45f * voice->output_rate) {
|
||||
if (fres > 0.45f * voice->output_rate)
|
||||
fres = 0.45f * voice->output_rate;
|
||||
} else if (fres < 5) {
|
||||
else if (fres < 5)
|
||||
fres = 5;
|
||||
}
|
||||
|
||||
|
||||
/* if filter enabled and there is a significant frequency change.. */
|
||||
if (/*dsp_use_filter_flag &&*/ (abs(fres - voice->last_fres) > 0.01)) {
|
||||
|
||||
if ((abs (fres - voice->last_fres) > 0.01))
|
||||
{
|
||||
/* The filter coefficients have to be recalculated (filter
|
||||
* parameters have changed). Recalculation for various reasons is
|
||||
* forced by setting last_fres to -1. The flag filter_startup
|
||||
@@ -703,7 +536,8 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
/* both b0 -and- b2 */
|
||||
fluid_real_t b02_temp = b1_temp * 0.5f;
|
||||
|
||||
if (voice->filter_startup) {
|
||||
if (voice->filter_startup)
|
||||
{
|
||||
/* The filter is calculated, because the voice was started up.
|
||||
* In this case set the filter coefficients without delay.
|
||||
*/
|
||||
@@ -714,7 +548,9 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
voice->filter_coeff_incr_count = 0;
|
||||
voice->filter_startup = 0;
|
||||
// printf("Setting initial filter coefficients.\n");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* The filter frequency is changed. Calculate an increment
|
||||
* factor, so that the new setting is reached after one buffer
|
||||
@@ -735,125 +571,207 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||
voice->filter_coeff_incr_count = FILTER_TRANSITION_SAMPLES;
|
||||
}
|
||||
voice->last_fres = fres;
|
||||
fluid_check_fpe("voice_write filter calculation");
|
||||
fluid_check_fpe ("voice_write filter calculation");
|
||||
}
|
||||
|
||||
/* Now we set up the variables, that go into the DSP routine. For documentation,
|
||||
* see fluid_dsp_core.c
|
||||
*/
|
||||
/* Sample waveform data */
|
||||
dsp_data = voice->sample->data;
|
||||
|
||||
/* IIR filter sample history */
|
||||
dsp_hist1 = voice->hist1;
|
||||
dsp_hist2 = voice->hist2;
|
||||
|
||||
/* IIR filter coefficients */
|
||||
dsp_a1 = voice->a1;
|
||||
dsp_a2 = voice->a2;
|
||||
dsp_b02 = voice->b02;
|
||||
dsp_b1 = voice->b1;
|
||||
dsp_a1_incr = voice->a1_incr;
|
||||
dsp_a2_incr = voice->a2_incr;
|
||||
dsp_b02_incr = voice->b02_incr;
|
||||
dsp_b1_incr = voice->b1_incr;
|
||||
dsp_filter_coeff_incr_count = voice->filter_coeff_incr_count;
|
||||
|
||||
fluid_check_fpe("voice_write DSP coefficients");
|
||||
fluid_check_fpe ("voice_write DSP coefficients");
|
||||
|
||||
/*********************** run the dsp chain ************************
|
||||
* The sample is mixed with the output buffer.
|
||||
* The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
|
||||
* Depending on the position in the loop and the loop size, this
|
||||
* may require several runs. */
|
||||
fluid_check_fpe("voice_write DSP processing");
|
||||
|
||||
if (((_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|
||||
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
||||
voice->dsp_buf = dsp_buf;
|
||||
|
||||
/* At which index does the loop point occur in the output buffer?
|
||||
* This calculates the first index in the buffer, which uses
|
||||
* sample data taken after the looparound. */
|
||||
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loopend, incr);
|
||||
|
||||
if (end_in_buffer >= FLUID_BUFSIZE) {
|
||||
/* The loop occurs after the end of the buffer.
|
||||
* Process the whole buffer in one run. */
|
||||
dsp_start = 0;
|
||||
dsp_end = FLUID_BUFSIZE;
|
||||
#include "fluid_dsp_core.c"
|
||||
|
||||
} else {
|
||||
/* The loop occurs during the current buffer length. Note, that
|
||||
* this method is unable to cope with a 'skipped' loop point. *
|
||||
* If, by means of witchcraft, evil magic or modulators, we end
|
||||
* up beyond * the loop point, a SEGV is unavoidable. * We
|
||||
* can't even detect this here, because the calculations are
|
||||
* done using * unsigned ints (only positive), and end_in_buffer
|
||||
* would be negative * for a skipped loop point...*/
|
||||
start = 0;
|
||||
|
||||
while (end_in_buffer < FLUID_BUFSIZE) {
|
||||
|
||||
dsp_start = start;
|
||||
dsp_end = end_in_buffer;
|
||||
#include "fluid_dsp_core.c"
|
||||
|
||||
/* loop */
|
||||
fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart);
|
||||
start = end_in_buffer;
|
||||
end_in_buffer += fluid_phase_steps(dsp_phase, voice->loopend, incr);
|
||||
}
|
||||
voice->has_looped=1;
|
||||
dsp_start = start;
|
||||
dsp_end = FLUID_BUFSIZE;
|
||||
#include "fluid_dsp_core.c"
|
||||
switch (voice->interp_method)
|
||||
{
|
||||
case FLUID_INTERP_NONE:
|
||||
count = fluid_dsp_float_interpolate_none (voice);
|
||||
break;
|
||||
case FLUID_INTERP_LINEAR:
|
||||
count = fluid_dsp_float_interpolate_linear (voice);
|
||||
break;
|
||||
case FLUID_INTERP_4THORDER:
|
||||
default:
|
||||
count = fluid_dsp_float_interpolate_4th_order (voice);
|
||||
break;
|
||||
case FLUID_INTERP_7THORDER:
|
||||
count = fluid_dsp_float_interpolate_7th_order (voice);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Not looping right now. */
|
||||
fluid_check_fpe ("voice_write interpolation");
|
||||
|
||||
dsp_start = 0;
|
||||
end_in_buffer = fluid_phase_steps(dsp_phase, voice->end, incr);
|
||||
if (count > 0)
|
||||
fluid_voice_effects (voice, count, dsp_left_buf, dsp_right_buf,
|
||||
dsp_reverb_buf, dsp_chorus_buf);
|
||||
|
||||
if (end_in_buffer >= FLUID_BUFSIZE) {
|
||||
/* Run the whole buffer at once */
|
||||
dsp_end = FLUID_BUFSIZE;
|
||||
#include "fluid_dsp_core.c"
|
||||
} else {
|
||||
/* The sample ends in the middle of the buffer length.
|
||||
* Process that far, and turn the voice off.
|
||||
*/
|
||||
dsp_end = end_in_buffer;
|
||||
#include "fluid_dsp_core.c"
|
||||
/* turn off voice if short count (sample ended and not looping) */
|
||||
if (count < FLUID_BUFSIZE)
|
||||
{
|
||||
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
|
||||
fluid_voice_off(voice);
|
||||
goto post_process;
|
||||
}
|
||||
|
||||
post_process:
|
||||
voice->ticks += FLUID_BUFSIZE;
|
||||
fluid_check_fpe ("voice_write postprocess");
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Purpose:
|
||||
*
|
||||
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
|
||||
* - mixes the processed sample to left and right output using the pan setting
|
||||
* - sends the processed sample to chorus and reverb
|
||||
*
|
||||
* Variable description:
|
||||
* - dsp_data: Pointer to the original waveform data
|
||||
* - dsp_left_buf: The generated signal goes here, left channel
|
||||
* - dsp_right_buf: right channel
|
||||
* - dsp_reverb_buf: Send to reverb unit
|
||||
* - dsp_chorus_buf: Send to chorus unit
|
||||
* - dsp_a1: Coefficient for the filter
|
||||
* - dsp_a2: same
|
||||
* - dsp_b0: same
|
||||
* - dsp_b1: same
|
||||
* - dsp_b2: same
|
||||
* - voice holds the voice structure
|
||||
*
|
||||
* A couple of variables are used internally, their results are discarded:
|
||||
* - dsp_i: Index through the output buffer
|
||||
* - dsp_phase_fractional: The fractional part of dsp_phase
|
||||
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
|
||||
* Used to interpolate between samples.
|
||||
* - dsp_process_buffer: Holds the processed signal between stages
|
||||
* - dsp_centernode: delay line for the IIR filter
|
||||
* - dsp_hist1: same
|
||||
* - dsp_hist2: same
|
||||
*
|
||||
*/
|
||||
static inline void
|
||||
fluid_voice_effects (fluid_voice_t *voice, int count,
|
||||
fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf,
|
||||
fluid_real_t* dsp_reverb_buf, fluid_real_t* dsp_chorus_buf)
|
||||
{
|
||||
/* IIR filter sample history */
|
||||
fluid_real_t dsp_hist1 = voice->hist1;
|
||||
fluid_real_t dsp_hist2 = voice->hist2;
|
||||
|
||||
/* IIR filter coefficients */
|
||||
fluid_real_t dsp_a1 = voice->a1;
|
||||
fluid_real_t dsp_a2 = voice->a2;
|
||||
fluid_real_t dsp_b02 = voice->b02;
|
||||
fluid_real_t dsp_b1 = voice->b1;
|
||||
fluid_real_t dsp_a1_incr = voice->a1_incr;
|
||||
fluid_real_t dsp_a2_incr = voice->a2_incr;
|
||||
fluid_real_t dsp_b02_incr = voice->b02_incr;
|
||||
fluid_real_t dsp_b1_incr = voice->b1_incr;
|
||||
int dsp_filter_coeff_incr_count = voice->filter_coeff_incr_count;
|
||||
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
|
||||
fluid_real_t dsp_centernode;
|
||||
int dsp_i;
|
||||
float v;
|
||||
|
||||
/* filter (implement the voice filter according to SoundFont standard) */
|
||||
|
||||
/* Check for denormal number (too close to zero). */
|
||||
if (fabs (dsp_hist1) < 1e-20) dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */
|
||||
|
||||
/* Two versions of the filter loop. One, while the filter is
|
||||
* changing towards its new setting. The other, if the filter
|
||||
* doesn't change.
|
||||
*/
|
||||
|
||||
if (dsp_filter_coeff_incr_count > 0)
|
||||
{
|
||||
/* Increment is added to each filter coefficient filter_coeff_incr_count times. */
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
{
|
||||
/* The filter is implemented in Direct-II form. */
|
||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
||||
dsp_hist2 = dsp_hist1;
|
||||
dsp_hist1 = dsp_centernode;
|
||||
|
||||
if (dsp_filter_coeff_incr_count-- > 0)
|
||||
{
|
||||
dsp_a1 += dsp_a1_incr;
|
||||
dsp_a2 += dsp_a2_incr;
|
||||
dsp_b02 += dsp_b02_incr;
|
||||
dsp_b1 += dsp_b1_incr;
|
||||
}
|
||||
} /* for dsp_i */
|
||||
}
|
||||
else /* The filter parameters are constant. This is duplicated to save time. */
|
||||
{
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
{ /* The filter is implemented in Direct-II form. */
|
||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
||||
dsp_hist2 = dsp_hist1;
|
||||
dsp_hist1 = dsp_centernode;
|
||||
}
|
||||
}
|
||||
|
||||
/*************** finishing ******************/
|
||||
/* copy back the state for the next cycle */
|
||||
/* pan (Copy the signal to the left and right output buffer) The voice
|
||||
* panning generator has a range of -500 .. 500. If it is centered,
|
||||
* it's close to 0. voice->amp_left and voice->amp_right are then the
|
||||
* same, and we can save one multiplication per voice and sample.
|
||||
*/
|
||||
if ((-0.5 < voice->pan) && (voice->pan < 0.5))
|
||||
{
|
||||
/* The voice is centered. Use voice->amp_left twice. */
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
{
|
||||
v = voice->amp_left * dsp_buf[dsp_i];
|
||||
dsp_left_buf[dsp_i] += v;
|
||||
dsp_right_buf[dsp_i] += v;
|
||||
}
|
||||
}
|
||||
else /* The voice is not centered. Stereo samples have one side zero. */
|
||||
{
|
||||
if (voice->amp_left != 0.0)
|
||||
{
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
dsp_left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i];
|
||||
}
|
||||
|
||||
if (voice->amp_right != 0.0)
|
||||
{
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
dsp_right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i];
|
||||
}
|
||||
}
|
||||
|
||||
/* reverb send. Buffer may be NULL. */
|
||||
if ((dsp_reverb_buf != NULL) && (voice->amp_reverb != 0.0))
|
||||
{
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i];
|
||||
}
|
||||
|
||||
/* chorus send. Buffer may be NULL. */
|
||||
if ((dsp_chorus_buf != NULL) && (voice->amp_chorus != 0))
|
||||
{
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i];
|
||||
}
|
||||
|
||||
voice->hist1 = dsp_hist1;
|
||||
voice->hist2 = dsp_hist2;
|
||||
voice->phase = dsp_phase;
|
||||
voice->amp = dsp_amp;
|
||||
voice->a1 = dsp_a1;
|
||||
voice->a2 = dsp_a2;
|
||||
voice->b02 = dsp_b02;
|
||||
voice->b1 = dsp_b1;
|
||||
voice->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
|
||||
|
||||
/* if (dsp_filter_coeff_incr_count) { */
|
||||
/* printf("ticks = %d, dsp_filter_coeff_incr_count = %d\n", */
|
||||
/* voice->ticks, dsp_filter_coeff_incr_count); */
|
||||
/* } */
|
||||
|
||||
post_process:
|
||||
voice->ticks += FLUID_BUFSIZE;
|
||||
fluid_check_fpe("voice_write postprocess");
|
||||
return FLUID_OK;
|
||||
fluid_check_fpe ("voice_effects");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1718,9 +1636,10 @@ fluid_voice_off(fluid_voice_t* voice)
|
||||
voice->status = FLUID_VOICE_OFF;
|
||||
|
||||
/* Decrement the reference count of the sample. */
|
||||
if (voice->sample) {
|
||||
fluid_sample_decr_ref(voice->sample);
|
||||
|
||||
voice->sample = NULL;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
@@ -1873,7 +1792,7 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||
|
||||
/* make sure we have enough samples surrounding the loop */
|
||||
int min_index_loop=(int) voice->sample->start + FLUID_MIN_LOOP_PAD;
|
||||
int max_index_loop=(int) voice->sample->end - FLUID_MIN_LOOP_PAD;
|
||||
int max_index_loop=(int) voice->sample->end - FLUID_MIN_LOOP_PAD + 1; /* 'end' is last valid sample, loopend can be + 1 */
|
||||
fluid_check_fpe("voice_check_sample_sanity start");
|
||||
|
||||
if (!voice->check_sample_sanity_flag){
|
||||
|
||||
@@ -60,14 +60,6 @@ enum fluid_voice_envelope_index_t{
|
||||
FLUID_VOICE_ENVLAST
|
||||
};
|
||||
|
||||
/*
|
||||
* interpolation data
|
||||
*/
|
||||
typedef struct {
|
||||
fluid_real_t a0, a1, a2, a3;
|
||||
/* signed int c0, c1, c2, c3; */
|
||||
} fluid_interp_coeff_t;
|
||||
|
||||
/*
|
||||
* fluid_voice_t
|
||||
*/
|
||||
@@ -116,12 +108,16 @@ struct _fluid_voice_t
|
||||
unsigned int start_time;
|
||||
unsigned int ticks;
|
||||
|
||||
fluid_real_t amp; /* the linear amplitude */
|
||||
fluid_real_t amp; /* current linear amplitude */
|
||||
fluid_phase_t phase; /* the phase of the sample wave */
|
||||
|
||||
#if 0
|
||||
fluid_real_t incr; /* the phase increment for the next 64 samples [NEW, PH] */
|
||||
#endif
|
||||
/* Temporary variables used in fluid_voice_write() */
|
||||
|
||||
fluid_real_t phase_incr; /* the phase increment for the next 64 samples */
|
||||
fluid_real_t amp_incr; /* amplitude increment value */
|
||||
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
|
||||
|
||||
/* End temporary variables */
|
||||
|
||||
/* basic parameters */
|
||||
fluid_real_t pitch; /* the pitch in midicents */
|
||||
@@ -134,7 +130,7 @@ struct _fluid_voice_t
|
||||
int start;
|
||||
int end;
|
||||
int loopstart;
|
||||
int loopend;
|
||||
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||
|
||||
/* master gain */
|
||||
fluid_real_t synth_gain;
|
||||
@@ -282,7 +278,14 @@ fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
|
||||
|
||||
#define FLUID_SAMPLESANITY_CHECK (1 << 0)
|
||||
#define FLUID_SAMPLESANITY_STARTUP (1 << 1)
|
||||
void fluid_voice_config(void);
|
||||
|
||||
|
||||
/* defined in fluid_dsp_float.c */
|
||||
|
||||
void fluid_dsp_float_config (void);
|
||||
int fluid_dsp_float_interpolate_none (fluid_voice_t *voice);
|
||||
int fluid_dsp_float_interpolate_linear (fluid_voice_t *voice);
|
||||
int fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice);
|
||||
int fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice);
|
||||
|
||||
#endif /* _FLUID_VOICE_H */
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -37,10 +39,6 @@
|
||||
|
||||
#include "fluidsynth.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(MINGW32)
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
@@ -458,13 +456,16 @@ int main(int argc, char** argv)
|
||||
fluid_source(cmd_handler, buf);
|
||||
}
|
||||
|
||||
/* load the soundfonts */
|
||||
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
|
||||
for (i = arg1; i < argc; i++) {
|
||||
if ((argv[i][0] != '-') && fluid_is_soundfont(argv[i])) {
|
||||
if (fluid_synth_sfload(synth, argv[i], 1) == -1) {
|
||||
if (fluid_is_soundfont(argv[i]))
|
||||
{
|
||||
if (fluid_synth_sfload(synth, argv[i], 1) == -1)
|
||||
fprintf(stderr, "Failed to load the SoundFont %s\n", argv[i]);
|
||||
}
|
||||
}
|
||||
else if (!fluid_is_midifile(argv[i]))
|
||||
fprintf (stderr, "Parameter '%s' not a SoundFont or MIDI file or error occurred identifying it.\n",
|
||||
argv[i]);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
//#if defined(__POWERPC__) && !(defined(__APPLE__) && defined(__MACH__))
|
||||
//#include "config_maxmsp43.h"
|
||||
//#endif
|
||||
#if defined(__POWERPC__) && !(defined(__APPLE__) && defined(__MACH__))
|
||||
#include "config_maxmsp43.h"
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(MINGW32)
|
||||
#include "config_win32.h"
|
||||
@@ -283,21 +283,6 @@ typedef FILE* fluid_file;
|
||||
#define fluid_clip(_val, _min, _max) \
|
||||
{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); }
|
||||
|
||||
/* Purpose:
|
||||
* Some commands (SSE extensions on Pentium) need aligned data(
|
||||
* The address must be ...xxx0.
|
||||
* Take a pointer, and round it up to the next suitable address.
|
||||
* Obviously, one has to allocate 15 bytes of additional memory.
|
||||
* As soon as proper alignment is supported by the compiler, this
|
||||
* can be removed.
|
||||
*/
|
||||
#ifdef ENABLE_SSE
|
||||
/* FIXME - This is broken on AMD 64 - only used if SSE enabled */
|
||||
#define FLUID_ALIGN16BYTE(ptr)(((int)(ptr)+15) & (~0xFL))
|
||||
#else
|
||||
#define FLUID_ALIGN16BYTE(ptr) ptr
|
||||
#endif
|
||||
|
||||
#if WITH_FTS
|
||||
#define FLUID_PRINTF post
|
||||
#define FLUID_FLUSH()
|
||||
|
||||
Reference in New Issue
Block a user