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:
Jérôme Duval
2008-03-18 22:17:50 +00:00
parent a529aaf3c6
commit 5c102180bd
71 changed files with 4114 additions and 4125 deletions
+29 -32
View File
@@ -45,38 +45,35 @@ extern "C" {
/** /**
* @file fluidsynth.h
\file fluidsynth.h * @brief FluidSynth is a real-time synthesizer designed for SoundFont(R) files.
*
\brief fluidsynth is a real-time SoundFont(R) synthesizer. This is * This is the header of the fluidsynth library and contains the
the header of the fluidsynth library and contains the * synthesizer's public API.
synthesizer's public API. *
* Depending on how you want to use or extend the synthesizer you
Depending on how you want to use or extend the synthesizer you * will need different API functions. You probably do not need all
will need different API functions. You probably do not need all * of them. Here is what you might want to do:
of them. Here is what you might want to do: *
* o Embedded synthesizer: create a new synthesizer and send MIDI
o Embedded synthesizer: create a new synthesizer and send MIDI * events to it. The sound goes directly to the audio output of
events to it. The sound goes directly to the audio output of * your system.
your system. *
* o Plugin synthesizer: create a synthesizer and send MIDI events
o Plugin synthesizer: create a synthesizer and send MIDI events * but pull the audio back into your application.
but pull the audio back into your application. *
* o SoundFont plugin: create a new type of "SoundFont" and allow
o SoundFont plugin: create a new type of "SoundFont" and allow * the synthesizer to load your type of SoundFonts.
the synthesizer to load your type of SoundFonts. *
* o MIDI input: Create a MIDI handler to read the MIDI input on your
o MIDI input: Create a MIDI handler to read the MIDI input on your * machine and send the MIDI events directly to the synthesizer.
machine and send the MIDI events directly to the synthesizer. *
* o MIDI files: Open MIDI files and send the MIDI events to the
o MIDI files: Open MIDI files and send the MIDI events to the * synthesizer.
synthesizer. *
* o Command lines: You can send textual commands 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.
SoundFont(R) is a registered trademark of E-mu Systems, Inc.
*/ */
#include "fluidsynth/types.h" #include "fluidsynth/types.h"
+20 -6
View File
@@ -25,15 +25,29 @@
extern "C" { extern "C" {
#endif #endif
/**
* @file audio.h
/** Audio driver * @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, typedef int (*fluid_audio_func_t)(void* data, int len,
int nin, float** in, int nin, float** in,
int nout, float** out); int nout, float** out);
+29 -20
View File
@@ -25,28 +25,37 @@
extern "C" { extern "C" {
#endif #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 { enum fluid_seq_event_type {
FLUID_SEQ_NOTE = 0, FLUID_SEQ_NOTE = 0, /**< Note event (DOCME) */
FLUID_SEQ_NOTEON, FLUID_SEQ_NOTEON, /**< Note on event */
FLUID_SEQ_NOTEOFF, FLUID_SEQ_NOTEOFF, /**< Note off event */
FLUID_SEQ_ALLSOUNDSOFF, FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
FLUID_SEQ_ALLNOTESOFF, FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
FLUID_SEQ_BANKSELECT, FLUID_SEQ_BANKSELECT, /**< Bank select message */
FLUID_SEQ_PROGRAMCHANGE, FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
FLUID_SEQ_PROGRAMSELECT, FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */
FLUID_SEQ_PITCHBEND, FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
FLUID_SEQ_PITCHWHHELSENS, FLUID_SEQ_PITCHWHHELSENS, /**< Pitch wheel sensitivity set message */
FLUID_SEQ_MODULATION, FLUID_SEQ_MODULATION, /**< Modulation controller event */
FLUID_SEQ_SUSTAIN, FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
FLUID_SEQ_CONTROLCHANGE, FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
FLUID_SEQ_PAN, FLUID_SEQ_PAN, /**< Stereo pan set event */
FLUID_SEQ_VOLUME, FLUID_SEQ_VOLUME, /**< Volume set event */
FLUID_SEQ_REVERBSEND, FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
FLUID_SEQ_CHORUSSEND, FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
FLUID_SEQ_TIMER, FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
FLUID_SEQ_ANYCONTROLCHANGE, // used for remove_events only FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
FLUID_SEQ_LASTEVENT FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
}; };
/* Event alloc/free */ /* Event alloc/free */
+80 -74
View File
@@ -25,99 +25,105 @@
extern "C" { extern "C" {
#endif #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 { enum fluid_gen_type {
GEN_STARTADDROFS, GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
GEN_ENDADDROFS, GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
GEN_STARTLOOPADDROFS, GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
GEN_ENDLOOPADDROFS, GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
GEN_STARTADDRCOARSEOFS, GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
GEN_MODLFOTOPITCH, GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
GEN_VIBLFOTOPITCH, GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
GEN_MODENVTOPITCH, GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
GEN_FILTERFC, GEN_FILTERFC, /**< Filter cutoff */
GEN_FILTERQ, GEN_FILTERQ, /**< Filter Q */
GEN_MODLFOTOFILTERFC, GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
GEN_MODENVTOFILTERFC, GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
GEN_ENDADDRCOARSEOFS, GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
GEN_MODLFOTOVOL, GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
GEN_UNUSED1, GEN_UNUSED1, /**< Unused */
GEN_CHORUSSEND, GEN_CHORUSSEND, /**< Chorus send amount */
GEN_REVERBSEND, GEN_REVERBSEND, /**< Reverb send amount */
GEN_PAN, GEN_PAN, /**< Stereo panning */
GEN_UNUSED2, GEN_UNUSED2, /**< Unused */
GEN_UNUSED3, GEN_UNUSED3, /**< Unused */
GEN_UNUSED4, GEN_UNUSED4, /**< Unused */
GEN_MODLFODELAY, GEN_MODLFODELAY, /**< Modulation LFO delay */
GEN_MODLFOFREQ, GEN_MODLFOFREQ, /**< Modulation LFO frequency */
GEN_VIBLFODELAY, GEN_VIBLFODELAY, /**< Vibrato LFO delay */
GEN_VIBLFOFREQ, GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
GEN_MODENVDELAY, GEN_MODENVDELAY, /**< Modulation envelope delay */
GEN_MODENVATTACK, GEN_MODENVATTACK, /**< Modulation envelope attack */
GEN_MODENVHOLD, GEN_MODENVHOLD, /**< Modulation envelope hold */
GEN_MODENVDECAY, GEN_MODENVDECAY, /**< Modulation envelope decay */
GEN_MODENVSUSTAIN, GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
GEN_MODENVRELEASE, GEN_MODENVRELEASE, /**< Modulation envelope release */
GEN_KEYTOMODENVHOLD, GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
GEN_KEYTOMODENVDECAY, GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
GEN_VOLENVDELAY, GEN_VOLENVDELAY, /**< Volume envelope delay */
GEN_VOLENVATTACK, GEN_VOLENVATTACK, /**< Volume envelope attack */
GEN_VOLENVHOLD, GEN_VOLENVHOLD, /**< Volume envelope hold */
GEN_VOLENVDECAY, GEN_VOLENVDECAY, /**< Volume envelope decay */
GEN_VOLENVSUSTAIN, GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
GEN_VOLENVRELEASE, GEN_VOLENVRELEASE, /**< Volume envelope release */
GEN_KEYTOVOLENVHOLD, GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
GEN_KEYTOVOLENVDECAY, GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
GEN_INSTRUMENT, GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
GEN_RESERVED1, GEN_RESERVED1, /**< Reserved */
GEN_KEYRANGE, GEN_KEYRANGE, /**< MIDI note range */
GEN_VELRANGE, GEN_VELRANGE, /**< MIDI velocity range */
GEN_STARTLOOPADDRCOARSEOFS, GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
GEN_KEYNUM, GEN_KEYNUM, /**< Fixed MIDI note number */
GEN_VELOCITY, GEN_VELOCITY, /**< Fixed MIDI velocity value */
GEN_ATTENUATION, GEN_ATTENUATION, /**< Initial volume attenuation */
GEN_RESERVED2, GEN_RESERVED2, /**< Reserved */
GEN_ENDLOOPADDRCOARSEOFS, GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
GEN_COARSETUNE, GEN_COARSETUNE, /**< Coarse tuning */
GEN_FINETUNE, GEN_FINETUNE, /**< Fine tuning */
GEN_SAMPLEID, GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
GEN_SAMPLEMODE, GEN_SAMPLEMODE, /**< Sample mode flags */
GEN_RESERVED3, GEN_RESERVED3, /**< Reserved */
GEN_SCALETUNE, GEN_SCALETUNE, /**< Scale tuning */
GEN_EXCLUSIVECLASS, GEN_EXCLUSIVECLASS, /**< Exclusive class number */
GEN_OVERRIDEROOTKEY, GEN_OVERRIDEROOTKEY, /**< Sample root note override */
/* the initial pitch is not a "standard" generator. It is not /* the initial pitch is not a "standard" generator. It is not
* mentioned in the list of generator in the SF2 specifications. It * mentioned in the list of generator in the SF2 specifications. It
* is used, however, as the destination for the default pitch wheel * is used, however, as the destination for the default pitch wheel
* modulator. */ * modulator. */
GEN_PITCH, GEN_PITCH, /**< Pitch (NOTE: Not a real SoundFont generator) */
GEN_LAST GEN_LAST /**< Value defines the count of generators (#fluid_gen_type) */
}; };
/* /**
* fluid_gen_t * SoundFont generator structure.
* Sound font generator
*/ */
typedef struct _fluid_gen_t typedef struct _fluid_gen_t
{ {
unsigned char flags; /* is it used or not */ unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
double val; /* The nominal value */ double val; /**< The nominal value */
double mod; /* Change by modulators */ double mod; /**< Change by modulators */
double nrpn; /* Change by NRPN messages */ double nrpn; /**< Change by NRPN messages */
} fluid_gen_t; } fluid_gen_t;
/**
* Enum value for 'flags' field of #_fluid_gen_t (not really flags).
*/
enum fluid_gen_flags enum fluid_gen_flags
{ {
GEN_UNUSED, GEN_UNUSED, /**< Generator value is not set */
GEN_SET, GEN_SET, /**< Generator value is set */
GEN_ABS_NRPN 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); FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
+22 -24
View File
@@ -28,56 +28,54 @@ extern "C" {
/** /**
* * @file log.h
* Logging interface * @brief Logging interface
* *
* The default logging function of the fluidsynth prints its messages * The default logging function of the fluidsynth prints its messages
* to the stderr. The synthesizer uses four level of messages: FLUID_PANIC, * to the stderr. The synthesizer uses five level of messages: #FLUID_PANIC,
* ERR, WARN, and FLUID_DBG. They are commented in the definition below. * #FLUID_ERR, #FLUID_WARN, #FLUID_INFO, and #FLUID_DBG.
* *
* A client application can install a new log function to handle the * A client application can install a new log function to handle the
* messages differently. In the following example, the application * 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 * and ignores all other messages by setting the log function to
* NULL: * NULL:
* *
* ... * DOCME (formatting)
* fluid_set_log_function(FLUID_PANIC, show_dialog, (void*) root_window); * fluid_set_log_function(FLUID_PANIC, show_dialog, (void*) root_window);
* fluid_set_log_function(ERR, NULL, NULL); * fluid_set_log_function(FLUID_ERR, NULL, NULL);
* fluid_set_log_function(WARN, NULL, NULL); * fluid_set_log_function(FLUID_WARN, NULL, NULL);
* fluid_set_log_function(FLUID_DBG, NULL, NULL); * fluid_set_log_function(FLUID_DBG, NULL, NULL);
* ...
*
*/ */
/**
* FluidSynth log levels.
*/
enum fluid_log_level { enum fluid_log_level {
FLUID_PANIC, /* the synth can't function correctly any more */ FLUID_PANIC, /**< The synth can't function correctly any more */
FLUID_ERR, /* the synth can function, but with serious limitation */ FLUID_ERR, /**< Serious error occurred */
FLUID_WARN, /* the synth might not function as expected */ FLUID_WARN, /**< Warning */
FLUID_INFO, /* verbose messages */ FLUID_INFO, /**< Verbose informational messages */
FLUID_DBG, /* debugging messages */ FLUID_DBG, /**< Debugging messages */
LAST_LOG_LEVEL 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); 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 FLUIDSYNTH_API
fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void* data); 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); 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, ...); FLUIDSYNTH_API int fluid_log(int level, char * fmt, ...);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+10 -26
View File
@@ -25,7 +25,10 @@
extern "C" { extern "C" {
#endif #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 fluid_midi_event_t* new_fluid_midi_event(void);
FLUIDSYNTH_API int delete_fluid_midi_event(fluid_midi_event_t* event); 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); 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 * Will be used between
* - MIDI driver and MIDI router * - MIDI driver and MIDI router
* - MIDI router and synth * - MIDI router and synth
@@ -58,48 +66,26 @@ 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); typedef int (*handle_midi_event_func_t)(void* data, fluid_midi_event_t* event);
/* /*
*
* MIDI router * MIDI router
* *
* The MIDI handler forwards incoming MIDI events to the synthesizer * 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, FLUIDSYNTH_API fluid_midi_router_t* new_fluid_midi_router(fluid_settings_t* settings,
handle_midi_event_func_t handler, handle_midi_event_func_t handler,
void* event_handler_data); 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); 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); 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); 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); FLUIDSYNTH_API int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event);
/* /*
*
* MIDI driver * MIDI driver
* *
* The MIDI handler forwards incoming MIDI events to the synthesizer * The MIDI handler forwards incoming MIDI events to the synthesizer
*
*/ */
FLUIDSYNTH_API FLUIDSYNTH_API
fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings, fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler, 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 * MIDI file player
* *
* The MIDI player allows you to play MIDI files with the FLUID Synth * 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); FLUIDSYNTH_API fluid_player_t* new_fluid_player(fluid_synth_t* synth);
+2 -2
View File
@@ -144,9 +144,9 @@ struct _fluid_sample_t
{ {
char name[21]; char name[21];
unsigned int start; 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 loopstart;
unsigned int loopend; unsigned int loopend; /* Note: first point following the loop (superimposed on loopstart) */
unsigned int samplerate; unsigned int samplerate;
int origpitch; int origpitch;
int pitchadj; int pitchadj;
+2 -2
View File
@@ -26,10 +26,10 @@
extern "C" { extern "C" {
#endif #endif
#define FLUIDSYNTH_VERSION "1.0.7" #define FLUIDSYNTH_VERSION "1.0.8"
#define FLUIDSYNTH_VERSION_MAJOR 1 #define FLUIDSYNTH_VERSION_MAJOR 1
#define FLUIDSYNTH_VERSION_MINOR 0 #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); FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
+11 -8
View File
@@ -6,10 +6,10 @@
[:Development:] [: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 fixes. The project was started by Peter Hanappe who is the main
author. Josh Green is the current maintainer. Below you'll find a 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 * 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). (the blue waves with FluidSynth letters partially submerged).
files: iiwu_defsfont.{c,h}, iiwu_alsa{c,h} and others. 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 * Markus Nentwig (re-)designed the resonant filter, the chorus, the
LADSPA subsystem, the MIDI router, optimized for SSE, made many LADSPA subsystem, the MIDI router, optimized for SSE, made many
changes and bug fixes and got the synthesizer to actually work. Most 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 iiwu_sse.h, iiwu_dsp_core.h, iiwu_rev.{c,h}, and basically all the
other files. 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 * Antoine Schmitt added the sequencer support, support for sample
loading (RAM Sfont), developed the loading (RAM Sfont), developed the
MacroMedia Director Xtra, and send in many many bug reports. Thanks MacroMedia Director Xtra, and send in many many bug reports. Thanks
@@ -67,8 +67,7 @@ summery of contributions.
portability. portability.
* The midi device uses code from jMax's alsarawmidi.c file and from * 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 Smurf's midi_alsaraw.c by Josh Green. file: iiwu_alsa.c
the alsa sequencer interface. file: iiwu_alsa.c
* The reverb algorithm was written by Jezar * The reverb algorithm was written by Jezar
(http://www.dreampoint.co.uk). His code is public domain. The code (http://www.dreampoint.co.uk). His code is public domain. The code
@@ -115,3 +114,7 @@ Gerald Pye
Rui Nuno Capela Rui Nuno Capela
Frieder Bürzele Frieder Bürzele
Henri Manson Henri Manson
Mihail Zenkov
Paul Millar
Nick Daly
David Hilvert
+1 -1
View File
@@ -14,6 +14,7 @@ SharedLibrary libfluidsynth.so :
fluid_cmd.c fluid_cmd.c
fluid_conv.c fluid_conv.c
fluid_defsfont.c fluid_defsfont.c
fluid_dsp_float.c
fluid_event.c fluid_event.c
fluid_gen.c fluid_gen.c
fluid_hash.c fluid_hash.c
@@ -28,7 +29,6 @@ SharedLibrary libfluidsynth.so :
fluid_seq.c fluid_seq.c
fluid_seqbind.c fluid_seqbind.c
fluid_settings.c fluid_settings.c
fluid_strtok.c
fluid_synth.c fluid_synth.c
fluid_sys.c fluid_sys.c
fluid_tuning.c fluid_tuning.c
+29
View File
@@ -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* fluid_audio_driver_t*
new_fluid_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth) 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; 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* fluid_audio_driver_t*
new_fluid_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data) 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; return NULL;
} }
/**
* Deletes an audio driver instance.
* @param driver Audio driver instance to delete
*
* Shuts down an audio driver and deletes its instance.
*/
void void
delete_fluid_audio_driver(fluid_audio_driver_t* driver) delete_fluid_audio_driver(fluid_audio_driver_t* driver)
{ {
+4 -25
View File
@@ -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) 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; fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) d;
float* handle[2]; int n, offset;
int i, k, n, offset;
float s;
unsigned int sample_time; unsigned int sample_time;
handle[0] = dev->left;
handle[1] = dev->right;
sample_time = (unsigned int) (dev->samples / dev->sample_rate * 1000.0); sample_time = (unsigned int) (dev->samples / dev->sample_rate * 1000.0);
if (sample_time > clock_time) { if (sample_time > clock_time) {
return 1; return 1;
} }
(*dev->callback)(dev->data, dev->period_size, 0, NULL, 2, handle); fluid_synth_write_s16(dev->data, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2);
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;
}
for (offset = 0; offset < dev->buf_size; offset += n) { for (offset = 0; offset < dev->buf_size; offset += n) {
n = fwrite((char*) dev->buf + offset, 1, dev->buf_size - offset, dev->file); n = fwrite((char*) dev->buf + offset, 1, dev->buf_size - offset, dev->file);
if (n < 0) { if (n < 0) {
FLUID_LOG(FLUID_ERR, "Audio file error"); FLUID_LOG(FLUID_ERR, "Audio output file write error: %s",
strerror (errno));
return 0; return 0;
} }
} }
@@ -197,8 +180,4 @@ static int fluid_file_audio_run_s16(void* d, unsigned int clock_time)
dev->samples += dev->period_size; dev->samples += dev->period_size;
return 1; return 1;
error_recovery:
return 0;
} }
+6
View File
@@ -41,6 +41,7 @@ new_fluid_channel(fluid_synth_t* synth, int num)
chan->synth = synth; chan->synth = synth;
chan->channum = num; chan->channum = num;
chan->preset = NULL;
fluid_channel_init(chan); fluid_channel_init(chan);
fluid_channel_init_ctrl(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->prognum = (chan->channum == 9)? 0 : chan->channum;
chan->banknum = (chan->channum == 9)? 128 : 0; chan->banknum = (chan->channum == 9)? 128 : 0;
chan->sfontnum = 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->preset = fluid_synth_find_preset(chan->synth, chan->banknum, chan->prognum);
chan->interp_method = FLUID_INTERP_DEFAULT; chan->interp_method = FLUID_INTERP_DEFAULT;
chan->tuning = NULL; chan->tuning = NULL;
chan->nrpn_select = 0; chan->nrpn_select = 0;
@@ -106,6 +110,7 @@ fluid_channel_reset(fluid_channel_t* chan)
int int
delete_fluid_channel(fluid_channel_t* chan) delete_fluid_channel(fluid_channel_t* chan)
{ {
if (chan->preset) delete_fluid_preset (chan->preset);
FLUID_FREE(chan); FLUID_FREE(chan);
return FLUID_OK; 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(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum); fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);
if (chan->preset) delete_fluid_preset (chan->preset);
chan->preset = preset; chan->preset = preset;
return FLUID_OK; return FLUID_OK;
} }
+6 -5
View File
@@ -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 /* The & in chorusbuf[...] is equivalent to a division modulo
MAX_SAMPLES, only faster. */ MAX_SAMPLES, only faster. */
d_out += (chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK] d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
* chorus->sinc_table[ii][pos_subsamples]); * chorus->sinc_table[ii][pos_subsamples];
pos_samples--; pos_samples--;
}; };
@@ -490,7 +490,7 @@ void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
} /* foreach sample */ } /* 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, void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out) 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 /* The & in chorusbuf[...] is equivalent to a division modulo
MAX_SAMPLES, only faster. */ 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--; pos_samples--;
}; };
@@ -546,7 +547,7 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
d_out *= chorus->level; 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; left_out[sample_index] = d_out;
right_out[sample_index] = d_out; right_out[sample_index] = d_out;
+27 -29
View File
@@ -21,7 +21,6 @@
#include "fluidsynth_priv.h" #include "fluidsynth_priv.h"
#include "fluid_cmd.h" #include "fluid_cmd.h"
#include "fluid_synth.h" #include "fluid_synth.h"
#include "fluid_strtok.h"
#include "fluid_settings.h" #include "fluid_settings.h"
#include "fluid_io.h" #include "fluid_io.h"
#include "fluid_hash.h" #include "fluid_hash.h"
@@ -36,6 +35,7 @@
#endif #endif
#define MAX_TOKENS 100 /* LADSPA plugins need lots of parameters */ #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 */ #define FLUID_WORKLINELENGTH 1024 /* LADSPA plugins use long command lines */
void fluid_shell_settings(fluid_settings_t* settings) void fluid_shell_settings(fluid_settings_t* settings)
@@ -157,43 +157,42 @@ fluid_cmd_t fluid_commands[] = {
{ NULL, NULL, NULL, NULL, NULL } { 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 int
fluid_command(fluid_cmd_handler_t* handler, char* cmd, fluid_ostream_t out) 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* token[MAX_TOKENS];
char buf[MAX_COMMAND_LEN+1];
char *strtok, *tok;
int num_tokens = 0; int num_tokens = 0;
if (cmd[0] == '#') { if (cmd[0] == '#') {
return 1; return 1;
} }
/* tokenize the input line */ if (strlen (cmd) > MAX_COMMAND_LEN)
fluid_strtok_set(st, cmd, " \t\n\r"); {
while (fluid_strtok_has_more(st)) { fluid_ostream_printf(out, "Command exceeded max length of %d chars\n",
token[num_tokens++] = fluid_strtok_next_token(st); MAX_COMMAND_LEN);
return -1;
} }
if (num_tokens == 0) { FLUID_STRCPY(buf, cmd); /* copy - since fluid_strtok thrashes it */
return 1; 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 */ /* handle the command */
return fluid_cmd_handler_handle(handler, num_tokens, &token[0], out); return fluid_cmd_handler_handle(handler, num_tokens, &token[0], out);
@@ -203,7 +202,6 @@ struct _fluid_shell_t {
fluid_settings_t* settings; fluid_settings_t* settings;
fluid_cmd_handler_t* handler; fluid_cmd_handler_t* handler;
fluid_thread_t* thread; fluid_thread_t* thread;
fluid_strtok_t* st;
fluid_istream_t in; fluid_istream_t in;
fluid_ostream_t out; fluid_ostream_t out;
}; };
@@ -247,7 +245,6 @@ void fluid_shell_init(fluid_shell_t* shell,
{ {
shell->settings = settings; shell->settings = settings;
shell->handler = handler; shell->handler = handler;
shell->st = new_fluid_strtok(NULL, NULL);
shell->in = in; shell->in = in;
shell->out = out; shell->out = out;
} }
@@ -257,6 +254,7 @@ void delete_fluid_shell(fluid_shell_t* shell)
if (shell->thread != NULL) { if (shell->thread != NULL) {
delete_fluid_thread(shell->thread); delete_fluid_thread(shell->thread);
} }
FLUID_FREE(shell); FLUID_FREE(shell);
} }
@@ -289,7 +287,7 @@ int fluid_shell_run(fluid_shell_t* shell)
#endif #endif
/* handle the command */ /* 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 */ case 1: /* empty line or comment */
break; break;
+67 -38
View File
@@ -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) int fluid_defpreset_preset_delete(fluid_preset_t* preset)
{ {
FLUID_FREE(preset); FLUID_FREE(preset);
/* printf("TODO: free modulators\n"); */
/* TODO: free modulators */
return 0; return 0;
} }
@@ -301,21 +303,20 @@ int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file)
sfont->samplesize = sfdata->samplesize; sfont->samplesize = sfdata->samplesize;
/* load sample data in one block */ /* load sample data in one block */
if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK) { if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK)
return FLUID_FAILED; goto err_exit;
}
/* Create all the sample headers */ /* Create all the sample headers */
p = sfdata->sample; p = sfdata->sample;
while (p != NULL) { while (p != NULL) {
sfsample = (SFSample *) p->data; sfsample = (SFSample *) p->data;
sample = new_fluid_sample(); sample = new_fluid_sample();
if (sample == NULL) { if (sample == NULL) goto err_exit;
return FLUID_FAILED;
} if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK)
if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK) { goto err_exit;
return FLUID_FAILED;
}
fluid_defsfont_add_sample(sfont, sample); fluid_defsfont_add_sample(sfont, sample);
fluid_voice_optimize_sample(sample); fluid_voice_optimize_sample(sample);
p = fluid_list_next(p); p = fluid_list_next(p);
@@ -326,18 +327,21 @@ int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file)
while (p != NULL) { while (p != NULL) {
sfpreset = (SFPreset *) p->data; sfpreset = (SFPreset *) p->data;
preset = new_fluid_defpreset(sfont); preset = new_fluid_defpreset(sfont);
if (preset == NULL) { if (preset == NULL) goto err_exit;
return FLUID_FAILED;
} if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK)
if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK) { goto err_exit;
return FLUID_FAILED;
}
fluid_defsfont_add_preset(sfont, preset); fluid_defsfont_add_preset(sfont, preset);
p = fluid_list_next(p); p = fluid_list_next(p);
} }
sfont_free_data(sfdata); sfont_close (sfdata);
return FLUID_OK; return FLUID_OK;
err_exit:
sfont_close (sfdata);
return FLUID_FAILED;
} }
/* fluid_defsfont_add_sample /* fluid_defsfont_add_sample
@@ -949,6 +953,18 @@ new_fluid_preset_zone(char *name)
int int
delete_fluid_preset_zone(fluid_preset_zone_t* zone) 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); FLUID_FREE(zone);
return FLUID_OK; return FLUID_OK;
} }
@@ -1331,6 +1347,17 @@ new_fluid_inst_zone(char* name)
int int
delete_fluid_inst_zone(fluid_inst_zone_t* zone) 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); FLUID_FREE(zone);
return FLUID_OK; return FLUID_OK;
} }
@@ -1770,8 +1797,12 @@ sfload_file (const char * fname)
return (NULL); return (NULL);
} }
if (!(sf = safe_malloc (sizeof (SFData)))) if (!(sf = FLUID_NEW (SFData)))
{
FLUID_LOG(FLUID_ERR, "Out of memory");
err = TRUE; err = TRUE;
}
if (!err) if (!err)
{ {
memset (sf, 0, sizeof (SFData)); /* zero sfdata */ 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)); " of %d bytes"), &chunk.id, chunk.size));
/* alloc for chunk id and da chunk */ /* 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); return (FAIL);
}
/* attach to INFO list, sfont_close will cleanup if FAIL occurs */ /* attach to INFO list, sfont_close will cleanup if FAIL occurs */
sf->info = fluid_list_append (sf->info, item); sf->info = fluid_list_append (sf->info, item);
@@ -2979,21 +3013,15 @@ unsigned short badpgen[] = { Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddr
Gen_OverrideRootKey, 0 Gen_OverrideRootKey, 0
}; };
/* close SoundFont file and delete a SoundFont structure */
void void
sfont_close (SFData * sf) sfont_close (SFData * sf)
{ {
fluid_list_t *p, *p2;
if (sf->sffd) if (sf->sffd)
fclose (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) if (sf->fname)
free (sf->fname); free (sf->fname);
@@ -3035,8 +3063,19 @@ sfont_free_data (SFData * sf)
FLUID_FREE (p->data); FLUID_FREE (p->data);
p = fluid_list_next (p); 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); delete_fluid_list (sf->sample);
sf->sample = NULL; sf->sample = NULL;
FLUID_FREE (sf);
} }
/* free all elements of a zone (Preset or Instrument) */ /* free all elements of a zone (Preset or Instrument) */
@@ -3173,13 +3212,3 @@ safe_fseek (FILE * fd, long ofs, int whence)
} }
return (OK); 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);
}
-2
View File
@@ -218,7 +218,6 @@ extern unsigned short badpgen[]; /* list of bad preset generators */
void sfont_init_chunks (void); void sfont_init_chunks (void);
void sfont_close (SFData * sf); void sfont_close (SFData * sf);
void sfont_free_data (SFData * sf);
void sfont_free_zone (SFZone * zone); void sfont_free_zone (SFZone * zone);
int sfont_preset_compare_func (void* a, void* b); int sfont_preset_compare_func (void* a, void* b);
@@ -427,7 +426,6 @@ enum
#define ErrnoEnd ErrWrite #define ErrnoEnd ErrWrite
int gerr (int ev, char * fmt, ...); int gerr (int ev, char * fmt, ...);
void *safe_malloc (size_t size);
int safe_fread (void *buf, int count, FILE * fd); int safe_fread (void *buf, int count, FILE * fd);
int safe_fwrite (void *buf, int count, FILE * fd); int safe_fwrite (void *buf, int count, FILE * fd);
int safe_fseek (FILE * fd, long ofs, int whence); int safe_fseek (FILE * fd, long ofs, int whence);
-26
View File
@@ -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
+594 -188
View File
@@ -18,43 +18,16 @@
* 02111-1307, USA * 02111-1307, USA
*/ */
#include "fluidsynth_priv.h"
#include "fluid_phase.h"
/* Purpose: /* Purpose:
* Low-level voice processing:
* *
* - interpolates (obtains values between the samples of the original waveform data) * Interpolates audio data (obtains values between the samples of the original
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor) * waveform data).
* - mixes the processed sample to left and right output using the pan setting
* - sends the processed sample to chorus and reverb
* *
* * Variables loaded from the voice structure (assigned in fluid_voice_write()):
* 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_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. * - dsp_phase: The position in the original waveform data.
* This has an integer and a fractional part (between samples). * This has an integer and a fractional part (between samples).
* - dsp_phase_incr: For each output sample, the position in the original * - 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: * A couple of variables are used internally, their results are discarded:
* - dsp_i: Index through the output buffer * - dsp_i: Index through the output buffer
* - dsp_phase_fractional: The fractional part of dsp_phase * - dsp_buf: Output buffer of floating point values (FLUID_BUFSIZE in length)
* - 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: #include "fluidsynth_priv.h"
* zap_almost_zero will return a number, as long as its #include "fluid_synth.h"
* absolute value is over a certain threshold. Otherwise 0. See #include "fluid_voice.h"
* 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) */ /* Interpolation (find a value between two samples of the original waveform) */
if ((fluid_phase_fract(dsp_phase) == 0) /* Linear interpolation table (2 coefficients centered on 1st) */
&& (fluid_phase_fract(dsp_phase_incr) == 0) static fluid_real_t interp_coeff_linear[FLUID_INTERP_MAX][2];
&& (fluid_phase_index(dsp_phase_incr) == 1)) {
/* Check for a special case: The current phase falls directly on an /* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */
* original sample. Also, the stepsize per output sample is exactly static fluid_real_t interp_coeff[FLUID_INTERP_MAX][4];
* one sample, no fractional part. In other words: The sample is
* played back at normal phase and root pitch. => No interpolation /* 7th order interpolation (7 coefficients centered on 3rd) */
* needed. static fluid_real_t sinc_table7[FLUID_INTERP_MAX][7];
*/
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* Mix to the buffer and advance the phase by one sample */ #define SINC_INTERP_ORDER 7 /* 7th order constant */
dsp_buf[dsp_i] = dsp_amp * dsp_data[fluid_phase_index_plusplus(dsp_phase)];
dsp_amp += dsp_amp_incr;
/* 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;
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
if (fabs (i_shifted) > 0.000001)
{
v = (fluid_real_t)sin (i_shifted * M_PI) / (M_PI * i_shifted);
/* Hamming window */
v *= (fluid_real_t)0.5 * (1.0 + cos (2.0 * M_PI * i_shifted / (fluid_real_t)SINC_INTERP_ORDER));
}
else v = 1.0;
sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
}
}
#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");
}
/* wave table interpolation: Choose the interpolation method */
switch(dsp_interp_method){
case FLUID_INTERP_NONE:
/* No interpolation. Just take the sample, which is closest to /* No interpolation. Just take the sample, which is closest to
* the playback pointer. Questionable quality, but very * the playback pointer. Questionable quality, but very
* efficient. */ * 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++) { /* Convert playback "speed" floating point value to phase index/fract */
dsp_phase_index = fluid_phase_index(dsp_phase); 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]; dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
/* increment phase and amplitude */ /* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr); fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_amp += dsp_amp_incr; dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
};
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);
dsp_amp += dsp_amp_incr; dsp_amp += dsp_amp_incr;
} }
break;
/* break out if not looping (buffer may not be full) */
if (!looping) break;
case FLUID_INTERP_7THORDER: /* go back to loop start */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) { if (dsp_phase_index > end_index)
int fract = fluid_phase_fract_to_tablerow(dsp_phase); {
dsp_phase_index = fluid_phase_index(dsp_phase); fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
dsp_buf[dsp_i] = (dsp_amp * voice->has_looped = 1;
(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;
} }
break;
} /* switch interpolation method */ /* break out if filled buffer */
} /* If interpolation is needed */ if (dsp_i >= FLUID_BUFSIZE) break;
}
/* filter (implement the voice filter according to Soundfont standard) */ voice->phase = dsp_phase;
if (dsp_use_filter_flag) { voice->amp = dsp_amp;
/* Check for denormal number (too close to zero) once in a return (dsp_i);
* 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 /* Straight line interpolation.
* changing towards its new setting. The other, if the filter * Returns number of samples processed (usually FLUID_BUFSIZE but could be
* doesn't change. * 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) { /* Convert playback "speed" floating point value to phase index/fract */
/* The increment is added to each filter coefficient fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
filter_coeff_incr_count times. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) { /* voice is currently looping? */
/* The filter is implemented in Direct-II form. */ looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; || (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; && voice->volenv_section < FLUID_VOICE_ENVRELEASE);
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
if (dsp_filter_coeff_incr_count-- > 0){ /* last index before 2nd interpolation point must be specially handled */
dsp_a1 += dsp_a1_incr; end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
dsp_a2 += dsp_a2_incr;
dsp_b02 += dsp_b02_incr; /* 2nd interpolation point to use at end of loop or sample */
dsp_b1 += dsp_b1_incr; 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 end_index++; /* we're now interpolating the last point */
* time. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) { /* interpolate within last point */
/* The filter is implemented in Direct-II form. */ for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
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; coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_hist2 = dsp_hist1; dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
dsp_hist1 = dsp_centernode; + 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 /* break out if filled buffer */
* panning generator has a range of -500 .. 500. If it is centered, if (dsp_i >= FLUID_BUFSIZE) break;
* 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. 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. */ /* Convert playback "speed" floating point value to phase index/fract */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) { fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
float v = voice->amp_left * dsp_buf[dsp_i];
dsp_left_buf[dsp_i] += v; /* voice is currently looping? */
dsp_right_buf[dsp_i] += v; 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 while (1)
* amplitudes will be zero. */ {
if (voice->amp_left != 0.0){ dsp_phase_index = fluid_phase_index (dsp_phase);
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i]; /* 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;
} }
if (voice->amp_right != 0.0){
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) { /* break out if buffer filled */
dsp_right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i]; 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];
} }
} }
/* reverb send. Buffer may be NULL. */ /* break out if filled buffer */
if ((dsp_reverb_buf != NULL) && (voice->amp_reverb != 0.0)) { if (dsp_i >= FLUID_BUFSIZE) break;
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i]; end_index -= 2; /* set end back to third to last sample point */
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (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;
/* 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];
} }
} }
/* chorus send. Buffer may be NULL. */ /* break out if filled buffer */
if ((dsp_chorus_buf != NULL) && (voice->amp_chorus != 0)) { if (dsp_i >= FLUID_BUFSIZE) break;
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i]; 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);
} }
-387
View File
@@ -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++;
}
}
+245 -5
View File
@@ -38,6 +38,10 @@
/* Event alloc/free */ /* Event alloc/free */
/**
* Create a new sequencer event structure.
* @return New sequencer event structure or NULL if out of memory
*/
fluid_event_t* fluid_event_t*
new_fluid_event() new_fluid_event()
{ {
@@ -59,6 +63,10 @@ new_fluid_event()
return(evt); return(evt);
} }
/**
* Delete a sequencer event structure.
* @param evt Sequencer event structure created by new_fluid_event().
*/
void void
delete_fluid_event(fluid_event_t* evt) delete_fluid_event(fluid_event_t* evt)
{ {
@@ -70,26 +78,45 @@ delete_fluid_event(fluid_event_t* evt)
FLUID_FREE(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 void
fluid_event_set_time(fluid_event_t* evt, unsigned int time) fluid_event_set_time(fluid_event_t* evt, unsigned int time)
{ {
evt->time = time; evt->time = time;
} }
/**
* Set source of a sequencer event (DOCME).
* @param evt Sequencer event structure
* @param src DOCME
*/
void void
fluid_event_set_source(fluid_event_t* evt, short src) fluid_event_set_source(fluid_event_t* evt, short src)
{ {
evt->src = src; evt->src = src;
} }
/**
* Set destination of a sequencer event (DOCME).
* @param evt Sequencer event structure
* @param dest DOCME
*/
void void
fluid_event_set_dest(fluid_event_t* evt, short dest) fluid_event_set_dest(fluid_event_t* evt, short dest)
{ {
evt->dest = dest; evt->dest = dest;
} }
/* Timer events */ /**
* Set a sequencer event to be a timer event.
* @param evt Sequencer event structure
* @param data DOCME
*/
void void
fluid_event_timer(fluid_event_t* evt, void* data) 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; 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 void
fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel) fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
{ {
@@ -108,6 +140,12 @@ fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
evt->vel = 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 void
fluid_event_noteoff(fluid_event_t* evt, int channel, short key) 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; 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 void
fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration) fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration)
{ {
@@ -126,6 +172,11 @@ fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned
evt->duration = duration; 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 void
fluid_event_all_sounds_off(fluid_event_t* evt, int channel) 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; 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 void
fluid_event_all_notes_off(fluid_event_t* evt, int channel) 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; 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 void
fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num) fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
{ {
@@ -148,6 +210,12 @@ fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
evt->control = 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 void
fluid_event_program_change(fluid_event_t* evt, int channel, short val) fluid_event_program_change(fluid_event_t* evt, int channel, short val)
{ {
@@ -156,6 +224,14 @@ fluid_event_program_change(fluid_event_t* evt, int channel, short val)
evt->value = 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 void
fluid_event_program_select(fluid_event_t* evt, int channel, fluid_event_program_select(fluid_event_t* evt, int channel,
unsigned int sfont_id, short bank_num, short preset_num) 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; 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 void
fluid_event_any_control_change(fluid_event_t* evt, int channel) 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; 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 void
fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch) fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch)
{ {
@@ -184,6 +272,12 @@ fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch)
evt->pitch = 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 void
fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value) fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
{ {
@@ -192,6 +286,12 @@ fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
evt->value = 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 void
fluid_event_modulation(fluid_event_t* evt, int channel, short val) 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; 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 void
fluid_event_sustain(fluid_event_t* evt, int channel, short val) 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; 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 void
fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val) fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val)
{ {
@@ -221,6 +334,12 @@ fluid_event_control_change(fluid_event_t* evt, int channel, short control, short
evt->value = val; 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 void
fluid_event_pan(fluid_event_t* evt, int channel, short val) 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; 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 void
fluid_event_volume(fluid_event_t* evt, int channel, short val) 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; 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 void
fluid_event_reverb_send(fluid_event_t* evt, int channel, short val) fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
{ {
@@ -251,6 +382,12 @@ fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
evt->value = 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 void
fluid_event_chorus_send(fluid_event_t* evt, int channel, short val) fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
{ {
@@ -261,75 +398,178 @@ fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
evt->value = 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) int fluid_event_get_type(fluid_event_t* evt)
{ {
return evt->type; 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) unsigned int fluid_event_get_time(fluid_event_t* evt)
{ {
return evt->time; return evt->time;
} }
/**
* Get the source field from a sequencer event structure.
* @param evt Sequencer event structure
* @return DOCME
*/
short fluid_event_get_source(fluid_event_t* evt) short fluid_event_get_source(fluid_event_t* evt)
{ {
return evt->src; 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) short fluid_event_get_dest(fluid_event_t* evt)
{ {
return evt->dest; return evt->dest;
} }
/**
* Get the MIDI channel field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI channel number (DOCME 0-15 or more?)
*/
int fluid_event_get_channel(fluid_event_t* evt) int fluid_event_get_channel(fluid_event_t* evt)
{ {
return evt->channel; 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) short fluid_event_get_key(fluid_event_t* evt)
{ {
return evt->key; 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) short fluid_event_get_velocity(fluid_event_t* evt)
{ {
return evt->vel; 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) short fluid_event_get_control(fluid_event_t* evt)
{ {
return evt->control; 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) short fluid_event_get_value(fluid_event_t* evt)
{ {
return evt->value; 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) void* fluid_event_get_data(fluid_event_t* evt)
{ {
return evt->data; return evt->data;
} }
/**
* Get the duration field from a sequencer event structure.
* @param evt Sequencer event structure
* @return Note duration value (DOCME units?)
*
* Used by the #FLUID_SEQ_NOTE event type.
*/
unsigned int fluid_event_get_duration(fluid_event_t* evt) unsigned int fluid_event_get_duration(fluid_event_t* evt)
{ {
return evt->duration; return evt->duration;
} }
/**
* 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) short fluid_event_get_bank(fluid_event_t* evt)
{ {
return evt->control; 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) int fluid_event_get_pitch(fluid_event_t* evt)
{ {
return evt->pitch; 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 short
fluid_event_get_program(fluid_event_t* evt) fluid_event_get_program(fluid_event_t* evt)
{ {
return evt->value; 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 unsigned int
fluid_event_get_sfont_id(fluid_event_t* evt) fluid_event_get_sfont_id(fluid_event_t* evt)
{ {
+4 -3
View File
@@ -89,9 +89,10 @@ fluid_gen_info_t fluid_gen_info[] = {
}; };
/* fluid_gen_set_default_values /**
* * Set an array of generators to their default values.
* Set an array of generators to their initial value * @param gen Array of generators (should be #GEN_LAST in size).
* @return Always returns 0
*/ */
int int
fluid_gen_set_default_values(fluid_gen_t* gen) fluid_gen_set_default_values(fluid_gen_t* gen)
+2
View File
@@ -17,7 +17,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA * 02111-1307, USA
*/ */
#if HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif
#if defined(HAVE_LASH) || defined(HAVE_LADCCA) #if defined(HAVE_LASH) || defined(HAVE_LADCCA)
+12 -1
View File
@@ -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) fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings, handle_midi_event_func_t handler, void* event_handler_data)
{ {
int i; int i;
@@ -171,6 +178,10 @@ fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings, handle_mi
return NULL; return NULL;
} }
/**
* Delete a MIDI driver instance.
* @param driver MIDI driver to delete
*/
void delete_fluid_midi_driver(fluid_midi_driver_t* driver) void delete_fluid_midi_driver(fluid_midi_driver_t* driver)
{ {
int i; int i;
+136 -51
View File
@@ -55,8 +55,12 @@ static int remains_80e0[] = {
* *
* MIDIFILE * 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) fluid_midi_file* new_fluid_midi_file(char* filename)
{ {
@@ -86,8 +90,10 @@ fluid_midi_file* new_fluid_midi_file(char* filename)
return mf; 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) 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) 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 * 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() fluid_midi_event_t* new_fluid_midi_event()
{ {
@@ -680,8 +687,10 @@ fluid_midi_event_t* new_fluid_midi_event()
return evt; 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) 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; 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) int fluid_midi_event_get_type(fluid_midi_event_t* evt)
{ {
return evt->type; 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) 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; 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) int fluid_midi_event_get_channel(fluid_midi_event_t* evt)
{ {
return evt->channel; 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) 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; 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) int fluid_midi_event_get_key(fluid_midi_event_t* evt)
{ {
return evt->param1; 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) 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; 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) int fluid_midi_event_get_velocity(fluid_midi_event_t* evt)
{ {
return evt->param2; 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) 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; 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) int fluid_midi_event_get_control(fluid_midi_event_t* evt)
{ {
return evt->param1; 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) 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; 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) int fluid_midi_event_get_value(fluid_midi_event_t* evt)
{ {
return evt->param2; 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) 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; 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) int fluid_midi_event_get_program(fluid_midi_event_t* evt)
{ {
return evt->param1; 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) int fluid_midi_event_set_program(fluid_midi_event_t* evt, int val)
{ {
evt->param1 = val; evt->param1 = val;
return FLUID_OK; 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) int fluid_midi_event_get_pitch(fluid_midi_event_t* evt)
{ {
return evt->param1; 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) int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val)
{ {
evt->param1 = val; evt->param1 = val;
@@ -1046,8 +1109,11 @@ fluid_track_send_events(fluid_track_t* track,
* *
* fluid_player * 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) 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; 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) int delete_fluid_player(fluid_player_t* player)
{ {
@@ -1240,8 +1308,10 @@ int fluid_player_callback(void* data, unsigned int msec)
return 1; 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) int fluid_player_play(fluid_player_t* player)
{ {
@@ -1263,8 +1333,10 @@ int fluid_player_play(fluid_player_t* player)
return FLUID_OK; 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) int fluid_player_stop(fluid_player_t* player)
{ {
@@ -1276,8 +1348,13 @@ int fluid_player_stop(fluid_player_t* player)
return FLUID_OK; return FLUID_OK;
} }
/* /* FIXME - Looping seems to not actually be implemented? */
* fluid_player_set_loop
/**
* 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) 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; 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) 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; 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) int fluid_player_set_bpm(fluid_player_t* player, int bpm)
{ {
return fluid_player_set_midi_tempo(player, (int)((double) 60 * 1e6 / bpm)); return fluid_player_set_midi_tempo(player, (int)((double) 60 * 1e6 / bpm));
} }
/* /**
* 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) 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; return FLUID_OK;
} }
+39 -29
View File
@@ -26,14 +26,22 @@
#include "fluid_synth.h" #include "fluid_synth.h"
#include "fluid_io.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* fluid_midi_router_t*
new_fluid_midi_router(fluid_settings_t* settings, handle_midi_event_func_t handler, void* event_handler_data) 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_t* router=NULL;
fluid_midi_router_rule_t* rule=NULL;; fluid_midi_router_rule_t* rule=NULL;
/* create the router */ /* create the router */
router = FLUID_NEW(fluid_midi_router_t); if (router == NULL){ router = FLUID_NEW(fluid_midi_router_t); if (router == NULL){
FLUID_LOG(FLUID_ERR, "Out of memory"); 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; return NULL;
} }
/* /**
* delete_fluid_midi_router * Delete a MIDI router instance.
* @param router MIDI router to delete
* @return Always returns 0
*/ */
int int
delete_fluid_midi_router(fluid_midi_router_t* router) 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; 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 * Purpose: The midi router is called for each event, that is received
* via the 'physical' midi input. Each event can trigger an arbitrary number * via the 'physical' midi input. Each event can trigger an arbitrary number
* of generated events. * 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. * MIDI event callback function to display event information to stdout
* It prints a message to stdout (which can be used to hook up an external user interface), * @param data MIDI router instance
* and hands the event on to the MIDI router. * @param event MIDI event data
* It is not a part of the MIDI router, but an added link in the MIDI chain. * @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) 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: case NOTE_ON:
fprintf(stdout, "event_pre_noteon %i %i %i\n", fprintf(stdout, "event_pre_noteon %i %i %i\n",
event->channel, event->param1, event->param2); event->channel, event->param1, event->param2);
fflush(stdout);
break; break;
case NOTE_OFF: case NOTE_OFF:
fprintf(stdout, "event_pre_noteoff %i %i %i\n", fprintf(stdout, "event_pre_noteoff %i %i %i\n",
event->channel, event->param1, event->param2); event->channel, event->param1, event->param2);
fflush(stdout);
break;
break; break;
case CONTROL_CHANGE: case CONTROL_CHANGE:
fprintf(stdout, "event_pre_cc %i %i %i\n", fprintf(stdout, "event_pre_cc %i %i %i\n",
event->channel, event->param1, event->param2); event->channel, event->param1, event->param2);
fflush(stdout);
break; break;
case PROGRAM_CHANGE: case PROGRAM_CHANGE:
fprintf(stdout, "event_pre_prog %i %i\n", event->channel, event->param1); fprintf(stdout, "event_pre_prog %i %i\n", event->channel, event->param1);
fflush(stdout);
break; break;
case PITCH_BEND: case PITCH_BEND:
fprintf(stdout, "event_pre_pitch %i %i\n", event->channel, event->param1); fprintf(stdout, "event_pre_pitch %i %i\n", event->channel, event->param1);
fflush(stdout);
break; break;
case CHANNEL_PRESSURE: case CHANNEL_PRESSURE:
fprintf(stdout, "event_pre_cpress %i %i\n", event->channel, event->param1); fprintf(stdout, "event_pre_cpress %i %i\n", event->channel, event->param1);
fflush(stdout);
break; break;
case KEY_PRESSURE: case KEY_PRESSURE:
fprintf(stdout, "event_pre_kpress %i %i %i\n", fprintf(stdout, "event_pre_kpress %i %i %i\n",
event->channel, event->param1, event->param2); event->channel, event->param1, event->param2);
fflush(stdout);
break; break;
default: default:
break; 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); 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 * MIDI event callback function to display event information to stdout
* router to the synth. * @param data MIDI router instance
* Again, it prints a message to stdout and hands the event on to the synth. * @param event MIDI event data
* It is not a part of the MIDI router, but an added link in the MIDI chain. * @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) 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: case NOTE_ON:
fprintf(stdout, "event_post_noteon %i %i %i\n", fprintf(stdout, "event_post_noteon %i %i %i\n",
event->channel, event->param1, event->param2); event->channel, event->param1, event->param2);
fflush(stdout);
break; break;
case NOTE_OFF: case NOTE_OFF:
fprintf(stdout, "event_post_noteoff %i %i %i\n", fprintf(stdout, "event_post_noteoff %i %i %i\n",
event->channel, event->param1, event->param2); event->channel, event->param1, event->param2);
fflush(stdout);
break;
break; break;
case CONTROL_CHANGE: case CONTROL_CHANGE:
fprintf(stdout, "event_post_cc %i %i %i\n", fprintf(stdout, "event_post_cc %i %i %i\n",
event->channel, event->param1, event->param2); event->channel, event->param1, event->param2);
fflush(stdout);
break; break;
case PROGRAM_CHANGE: case PROGRAM_CHANGE:
fprintf(stdout, "event_post_prog %i %i\n", event->channel, event->param1); fprintf(stdout, "event_post_prog %i %i\n", event->channel, event->param1);
+23 -83
View File
@@ -46,61 +46,41 @@
* This playing pointer is implemented using fluid_phase_t. * This playing pointer is implemented using fluid_phase_t.
* It is a 64 bit number. The higher 32 bits contain the 'index' (number of * 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. * 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 { typedef unsigned long long fluid_phase_t;
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;
/* Purpose: /* Purpose:
* Set a to b. * Set a to b.
* a: fluid_phase_t * a: fluid_phase_t
* b: fluid_phase_t * b: fluid_phase_t
*/ */
#ifdef USE_LONGLONG
#define fluid_phase_set(a,b) a=b; #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) { \ #define fluid_phase_set_int(a, b) ((a) = ((unsigned long long)(b)) << 32)
(a).b32.index = (sint32) (b); \
(a).b32.fract = 0; \
}
/* Purpose: /* Purpose:
* Sets the phase a to a phase increment given in b. * 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 * 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. */ * the playing pointer will advance it by 0.9 samples. */
#define fluid_phase_set_float(a, b) { \ #define fluid_phase_set_float(a, b) \
(a).b32.index = (sint32) (b); \ (a) = (((unsigned long long)(b)) << 32) \
(a).b32.fract = (uint32) (((double)(b) - (double)((a).b32.index)) * (double)FLUID_FRACT_MAX); \ | (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: /* Purpose:
* Return the index and the fractional part, respectively. */ * Return the index and the fractional part, respectively. */
#define fluid_phase_index(_x) \ #define fluid_phase_index(_x) \
((int)(_x).b32.index) ((unsigned int)((_x) >> 32))
#define fluid_phase_fract(_x) \ #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: /* Purpose:
* Takes the fractional part of the argument phase and * Takes the fractional part of the argument phase and
@@ -110,68 +90,28 @@ typedef union {
* coefficients for each possible fractional part... * coefficients for each possible fractional part...
*/ */
#define fluid_phase_fract_to_tablerow(_x) \ #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) \ #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: /* Purpose:
* Advance a by a step of b (both are fluid_phase_t). * Advance a by a step of b (both are fluid_phase_t).
*/ */
#ifdef USE_LONGLONG #define fluid_phase_incr(a, b) a += b
#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
/* Purpose: /* Purpose:
* Subtract b from a (both are fluid_phase_t). * Subtract b from a (both are fluid_phase_t).
*/ */
#ifdef USE_LONGLONG #define fluid_phase_decr(a, b) a -= b
#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
/* Purpose: /* Purpose:
* Subtract b samples from a. * Subtract b samples from a.
*/ */
#define fluid_phase_sub_int(a, b) { (a).b32.index -= b; } #define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32)
#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
/* Purpose: /* Purpose:
* The playing pointer is _phase. How many output samples are produced, until the point _p1 in the sample is reached, * Creates the expression a.index++. */
* if _phase advances in steps of _incr? #define fluid_phase_index_plusplus(a) (((a) += 0x100000000LL)
*/
#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)++)
#endif /* _FLUID_PHASE_H */ #endif /* _FLUID_PHASE_H */
+3 -1
View File
@@ -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) int fluid_rampreset_preset_delete(fluid_preset_t* preset)
{ {
FLUID_FREE(preset); FLUID_FREE(preset);
printf("TODO: free modulators\n");
/* TODO: free modulators */
return 0; return 0;
} }
+6 -5
View File
@@ -227,11 +227,11 @@ fluid_comb_getfeedback(fluid_comb* comb)
#define numallpasses 4 #define numallpasses 4
#define fixedgain 0.015f #define fixedgain 0.015f
#define scalewet 3.0f #define scalewet 3.0f
#define scaledamp 0.4f #define scaledamp 1.0f
#define scaleroom 0.28f #define scaleroom 0.28f
#define offsetroom 0.7f #define offsetroom 0.7f
#define initialroom 0.5f #define initialroom 0.5f
#define initialdamp 0.5f #define initialdamp 0.2f
#define initialwet 1 #define initialwet 1
#define initialdry 0 #define initialdry 0
#define initialwidth 1 #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->combL[i], rev->roomsize);
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize); fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
} }
for (i = 0; i < numcombs; i++) { for (i = 0; i < numcombs; i++) {
fluid_comb_setdamp(&rev->combL[i], rev->damp); fluid_comb_setdamp(&rev->combL[i], rev->damp);
fluid_comb_setdamp(&rev->combR[i], rev->damp); fluid_comb_setdamp(&rev->combR[i], rev->damp);
@@ -534,9 +535,9 @@ fluid_revmodel_getdamp(fluid_revmodel_t* rev)
void void
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value) fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
{ {
/* fluid_clip(value, 0.0f, 1.0f); */ fluid_clip(value, 0.0f, 1.0f);
/* rev->wet = value * scalewet; */ rev->wet = value * scalewet;
/* fluid_revmodel_update(rev); */ fluid_revmodel_update(rev);
} }
fluid_real_t fluid_real_t
+76 -63
View File
@@ -19,14 +19,17 @@
*/ */
#include "fluidsynth_priv.h" #include "fluidsynth_priv.h"
#include "fluid_settings.h" #include "fluid_sys.h"
#include "fluid_hash.h" #include "fluid_hash.h"
#include "fluid_strtok.h"
#include "fluid_synth.h" #include "fluid_synth.h"
#include "fluid_cmd.h" #include "fluid_cmd.h"
#include "fluid_adriver.h" #include "fluid_adriver.h"
#include "fluid_mdriver.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_init(fluid_settings_t* settings);
static void fluid_settings_hash_delete(void* value, int type); static void fluid_settings_hash_delete(void* value, int type);
@@ -66,6 +69,13 @@ static void delete_fluid_str_setting(fluid_str_setting_t* str)
FLUID_FREE(str->def); FLUID_FREE(str->def);
} }
if (str->options) { 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); delete_fluid_list(str->options);
} }
FLUID_FREE(str); FLUID_FREE(str);
@@ -189,22 +199,31 @@ void fluid_settings_init(fluid_settings_t* settings)
fluid_midi_driver_settings(settings); fluid_midi_driver_settings(settings);
} }
static fluid_strtok_t* fluid_settings_strtok = NULL; static int fluid_settings_tokenize(char* s, char *buf, char** ptr)
int fluid_settings_tokenize(char* s, char* buf, char** ptr)
{ {
char *tokstr, *tok;
int n = 0; int n = 0;
FLUID_STRCPY(buf, s); if (strlen (s) > MAX_SETTINGS_LABEL)
{
if (fluid_settings_strtok == NULL) { FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
fluid_settings_strtok = new_fluid_strtok(buf, "."); MAX_SETTINGS_LABEL);
} else { return 0;
fluid_strtok_set(fluid_settings_strtok, buf, ".");
} }
while (fluid_strtok_has_more(fluid_settings_strtok)) { FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
ptr[n++] = fluid_strtok_next_token(fluid_settings_strtok); 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; return n;
@@ -244,7 +263,6 @@ static int fluid_settings_get(fluid_settings_t* settings,
return 1; return 1;
} }
/** returns 1 if the value has been set, zero otherwise */ /** returns 1 if the value has been set, zero otherwise */
static int fluid_settings_set(fluid_settings_t* settings, static int fluid_settings_set(fluid_settings_t* settings,
char** name, int len, char** name, int len,
@@ -281,15 +299,15 @@ static int fluid_settings_set(fluid_settings_t* settings,
return 1; return 1;
} }
/** returns 1 if the value has been resgister correctly, 0 /** returns 1 if the value has been registered correctly, 0
otherwise */ otherwise */
int fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, int hints, int fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, int hints,
fluid_str_update_t fun, void* data) fluid_str_update_t fun, void* data)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
fluid_str_setting_t* setting; fluid_str_setting_t* setting;
@@ -323,8 +341,8 @@ int fluid_settings_register_num(fluid_settings_t* settings, char* name, double d
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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 fluid_settings_get_type(fluid_settings_t* settings, char* name)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; 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 fluid_settings_get_hints(fluid_settings_t* settings, char* name)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); ntokens = fluid_settings_tokenize(name, buf, tokens);
@@ -439,8 +455,8 @@ int fluid_settings_is_realtime(fluid_settings_t* settings, char* name)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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) int fluid_settings_setstr(fluid_settings_t* settings, char* name, char* str)
{ {
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
int type; int type;
void* value; void* value;
@@ -504,8 +519,8 @@ int fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; return 0;
} }
int fluid_settings_str_equal(fluid_settings_t* settings, char* name, char* s) int fluid_settings_str_equal(fluid_settings_t* settings, char* name, char* s)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; return 0;
} }
char* char*
fluid_settings_getstr_default(fluid_settings_t* settings, char* name) fluid_settings_getstr_default(fluid_settings_t* settings, char* name)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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) { while (list) {
char* option = (char*) fluid_list_get(list); char* option = (char*) fluid_list_get(list);
if (FLUID_STRCMP(s, option) == 0) { if (FLUID_STRCMP(s, option) == 0) {
FLUID_FREE (option);
setting->options = fluid_list_remove_link(setting->options, list); setting->options = fluid_list_remove_link(setting->options, list);
return 1; 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 fluid_settings_setnum(fluid_settings_t* settings, char* name, double val)
{ {
int type; int type;
void* value; void* value;
fluid_num_setting_t* setting; fluid_num_setting_t* setting;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); ntokens = fluid_settings_tokenize(name, buf, tokens);
@@ -698,8 +711,8 @@ fluid_settings_getnum_default(fluid_settings_t* settings, char* name)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
fluid_int_setting_t* setting; fluid_int_setting_t* setting;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); ntokens = fluid_settings_tokenize(name, buf, tokens);
@@ -799,8 +812,8 @@ fluid_settings_getint_default(fluid_settings_t* settings, char* name)
{ {
int type; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens); 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; int type;
void* value; void* value;
char buf[1024]; char* tokens[MAX_SETTINGS_TOKENS];
char* tokens[16]; char buf[MAX_SETTINGS_LABEL+1];
int ntokens; int ntokens;
if (!func) { if (!func) {
-263
View File
@@ -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
-123
View File
@@ -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;
}
-44
View File
@@ -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 */
+149 -80
View File
@@ -18,6 +18,7 @@
* 02111-1307, USA * 02111-1307, USA
*/ */
#include <math.h>
#include "fluid_synth.h" #include "fluid_synth.h"
#include "fluid_sys.h" #include "fluid_sys.h"
@@ -26,6 +27,14 @@
#include "fluid_settings.h" #include "fluid_settings.h"
#include "fluid_sfont.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); 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? */ /* has the synth module been initialized? */
static int fluid_synth_initialized = 0; static int fluid_synth_initialized = 0;
static void fluid_synth_init(void); static void fluid_synth_init(void);
static void init_dither(void);
/* default modulators /* default modulators
* SF2.01 page 52 ff: * SF2.01 page 52 ff:
@@ -150,12 +160,19 @@ fluid_synth_init()
{ {
fluid_synth_initialized++; 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_conversion_config();
fluid_voice_config(); fluid_dsp_float_config();
fluid_sys_config(); fluid_sys_config();
init_dither();
/* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */ /* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */ fluid_mod_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 /* 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.
*/
synth->left_buf = NULL; synth->left_buf = NULL;
synth->right_buf = NULL; synth->right_buf = NULL;
synth->left_ubuf = NULL;
synth->right_ubuf = NULL;
synth->fx_left_buf = NULL; synth->fx_left_buf = NULL;
synth->fx_right_buf = NULL; synth->fx_right_buf = NULL;
synth->fx_left_ubuf = NULL;
synth->fx_right_ubuf = NULL;
/* Left and right audio buffers */ /* Left and right audio buffers */
synth->left_buf = FLUID_ARRAY(fluid_real_t*, synth->nbuf); synth->left_buf = FLUID_ARRAY(fluid_real_t*, synth->nbuf);
synth->right_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) || if ((synth->left_buf == NULL) || (synth->right_buf == NULL)) {
(synth->left_ubuf == NULL) || (synth->right_ubuf == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory"); FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery; goto error_recovery;
} }
FLUID_MEMSET(synth->left_buf, 0, synth->nbuf * sizeof(fluid_real_t*)); 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->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++) { 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); if ((synth->left_buf[i] == NULL) || (synth->right_buf[i] == NULL)) {
synth->right_ubuf[i] = FLUID_ARRAY(fluid_real_t, FLUID_BUFSIZE + 4);
if ((synth->left_ubuf[i] == NULL) || (synth->right_ubuf[i] == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory"); FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery; 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 */ /* Effects audio buffers */
synth->fx_left_buf = FLUID_ARRAY(fluid_real_t*, synth->effects_channels); 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_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) || if ((synth->fx_left_buf == NULL) || (synth->fx_right_buf == NULL)) {
(synth->fx_right_buf == NULL) || (synth->fx_right_ubuf == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory"); FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery; 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_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*)); FLUID_MEMSET(synth->fx_right_buf, 0, 2 * sizeof(fluid_real_t*));
for (i = 0; i < synth->effects_channels; i++) { 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 */ if ((synth->fx_left_buf[i] == NULL) || (synth->fx_right_buf[i] == NULL)) {
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)) {
FLUID_LOG(FLUID_ERR, "Out of memory"); FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery; 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->cur = FLUID_BUFSIZE;
synth->dither_index = 0;
/* allocate the reverb module */ /* allocate the reverb module */
synth->reverb = new_fluid_revmodel(); synth->reverb = new_fluid_revmodel();
@@ -596,6 +584,14 @@ delete_fluid_synth(fluid_synth_t* synth)
synth->state = FLUID_SYNTH_STOPPED; 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 */ /* delete all the SoundFonts */
for (list = synth->sfont; list; list = fluid_list_next(list)) { for (list = synth->sfont; list; list = fluid_list_next(list)) {
sfont = (fluid_sfont_t*) fluid_list_get(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 */ /* free all the sample buffers */
if (synth->left_ubuf != NULL) { if (synth->left_buf != NULL) {
for (i = 0; i < synth->nbuf; i++) { for (i = 0; i < synth->nbuf; i++) {
if (synth->left_ubuf[i] != NULL) { if (synth->left_buf[i] != NULL) {
FLUID_FREE(synth->left_ubuf[i]); 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++) { for (i = 0; i < synth->nbuf; i++) {
if (synth->right_ubuf[i] != NULL) { if (synth->right_buf[i] != NULL) {
FLUID_FREE(synth->right_ubuf[i]); 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++) { for (i = 0; i < 2; i++) {
if (synth->fx_left_ubuf[i] != NULL) { if (synth->fx_left_buf[i] != NULL) {
FLUID_FREE(synth->fx_left_ubuf[i]); 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 */ /* release the reverb module */
@@ -1675,6 +1680,37 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
return 0; 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 * 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 left_sample;
fluid_real_t right_sample; fluid_real_t right_sample;
double time = fluid_utime(); double time = fluid_utime();
int di = synth->dither_index;
double prof_ref_on_block;
/* make sure we're playing */ /* make sure we're playing */
if (synth->state != FLUID_SYNTH_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 */ /* fill up the buffers as needed */
if (cur == FLUID_BUFSIZE) { if (cur == FLUID_BUFSIZE) {
prof_ref_on_block = fluid_profile_ref();
double prof_ref_on_block = fluid_profile_ref();
fluid_synth_one_block(synth, 0); fluid_synth_one_block(synth, 0);
cur = 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); fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref_on_block);
} }
left_sample=left_in[cur]* 32767.0f; left_sample = roundi (left_in[cur] * 32766.0f + rand_table[0][di]);
right_sample=right_in[cur] * 32767.0f; right_sample = roundi (right_in[cur] * 32766.0f + rand_table[1][di]);
di++;
if (di >= DITHER_SIZE) di = 0;
/* digital clipping */ /* digital clipping */
if (left_sample > 32767.0f) { if (left_sample > 32767.0f) left_sample = 32767.0f;
left_sample = 32767; if (left_sample < -32768.0f) left_sample = -32768.0f;
} if (right_sample > 32767.0f) right_sample = 32767.0f;
if (left_sample < -32768.0f) { if (right_sample < -32768.0f) right_sample = -32768.0f;
left_sample = -32768;
}
if (right_sample > 32767.0f) {
right_sample = 32767;
}
if (right_sample < -32768.0f) {
right_sample = -32768;
}
left_out[j] = (signed short) left_sample; left_out[j] = (signed short) left_sample;
right_out[k] = (signed short) right_sample; right_out[k] = (signed short) right_sample;
} }
synth->cur = cur; synth->cur = cur;
synth->dither_index = di; /* keep dither buffer continous */
fluid_profile(FLUID_PROF_WRITE_S16, prof_ref); fluid_profile(FLUID_PROF_WRITE_S16, prof_ref);
@@ -1747,6 +1781,49 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
return 0; 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 * 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->left_buf[i], 0, byte_size);
FLUID_MEMSET(synth->right_buf[i], 0, byte_size); FLUID_MEMSET(synth->right_buf[i], 0, byte_size);
} }
for (i = 0; i < synth->effects_channels; i++) { for (i = 0; i < synth->effects_channels; i++) {
FLUID_MEMSET(synth->fx_left_buf[i], 0, byte_size); FLUID_MEMSET(synth->fx_left_buf[i], 0, byte_size);
FLUID_MEMSET(synth->fx_right_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 * enabled on synth level. Nonexisting buffers are detected in the
* DSP loop. Not sending the reverb / chorus signal saves some time * DSP loop. Not sending the reverb / chorus signal saves some time
* in that case. */ * in that case. */
if (synth->with_reverb) { reverb_buf = synth->with_reverb ? synth->fx_left_buf[0] : NULL;
reverb_buf = synth->fx_left_buf[0]; chorus_buf = synth->with_chorus ? synth->fx_left_buf[1] : NULL;
} else {
reverb_buf = NULL;
}
if (synth->with_chorus) {
chorus_buf = synth->fx_left_buf[1];
} else {
chorus_buf = NULL;
}
fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref); 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_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref_voice);
} }
} }
fluid_check_fpe("Synthesis processes"); fluid_check_fpe("Synthesis processes");
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref); fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref);
+4 -8
View File
@@ -128,14 +128,10 @@ struct _fluid_synth_t
fluid_real_t** fx_left_buf; fluid_real_t** fx_left_buf;
fluid_real_t** fx_right_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_revmodel_t* reverb;
fluid_chorus_t* chorus; fluid_chorus_t* chorus;
int cur; /** the current sample in the audio buffers to be output */ 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 */ char outbuf[256]; /** buffer for message output */
double cpu_load; double cpu_load;
@@ -153,7 +149,6 @@ struct _fluid_synth_t
#endif #endif
}; };
/** returns 1 if the value has been set, 0 otherwise */ /** returns 1 if the value has been set, 0 otherwise */
int fluid_synth_setstr(fluid_synth_t* synth, char* name, char* str); 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); 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_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 * misc
*/ */
+105 -16
View File
@@ -20,7 +20,6 @@
#include "fluid_sys.h" #include "fluid_sys.h"
//#include <fpu_control.h>
static char fluid_errbuf[512]; /* buffer for error message */ static char fluid_errbuf[512]; /* buffer for error message */
@@ -63,8 +62,12 @@ int fluid_debug(int level, char * fmt, ...)
} }
#endif #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_log_function_t
fluid_set_log_function(int level, fluid_log_function_t fun, void* data) fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
@@ -79,8 +82,11 @@ fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
return old; 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 void
fluid_default_log_function(int level, char* message, void* data) 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 int
fluid_log(int level, char* fmt, ...) fluid_log(int level, char* fmt, ...)
@@ -176,6 +186,75 @@ fluid_log(int level, char* fmt, ...)
return FLUID_FAILED; 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 * fluid_error
@@ -555,6 +634,7 @@ unsigned int fluid_curtime()
return (ms); return (ms);
} }
#elif __BEOS__ #elif __BEOS__
struct _fluid_timer_t struct _fluid_timer_t
@@ -806,6 +886,7 @@ void fluid_time_config(void)
{ {
if (fluid_cpu_frequency < 0.0) { if (fluid_cpu_frequency < 0.0) {
fluid_cpu_frequency = fluid_estimate_cpu_frequency() / 1000000.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 #endif
#if 0 #ifdef FPE_CHECK
/*************************************************************** /***************************************************************
* *
@@ -900,7 +981,8 @@ double fluid_estimate_cpu_frequency(void)
#define _FPU_CLR_SW() __asm__ ("fnclex" : : ) #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
/* Purpose: /* 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) 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_GET_SW(s);
_FPU_CLR_SW(); _FPU_CLR_SW();
if ((s & _FPU_STATUS_IE) s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
|| (s & _FPU_STATUS_DE)
|| (s & _FPU_STATUS_ZE) if (s)
|| (s & _FPU_STATUS_OE) {
|| (s & _FPU_STATUS_UE)) {
FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation, 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_IE) ? "Invalid operation " : "",
(s & _FPU_STATUS_DE) ? "Denormal number " : "", (s & _FPU_STATUS_DE) ? "Denormal number " : "",
@@ -925,10 +1006,18 @@ unsigned int fluid_check_fpe_i386(char* explanation)
return s; 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)
/*************************************************************** /***************************************************************
+12 -4
View File
@@ -43,6 +43,13 @@ void fluid_sys_config(void);
void fluid_log_config(void); void fluid_log_config(void);
void fluid_time_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 Additional debugging system, separate from the log system. This
@@ -153,6 +160,7 @@ typedef pthread_mutex_t fluid_mutex_t;
#endif #endif
#endif #endif
/** /**
Threads Threads
@@ -291,15 +299,15 @@ extern fluid_profile_data_t fluid_profile_data[];
fluid_check_fpe() checks for "unnormalized numbers" and other fluid_check_fpe() checks for "unnormalized numbers" and other
exceptions of the floating point processsor. exceptions of the floating point processsor.
*/ */
#if 0 #ifdef FPE_CHECK
/* Enable FPE exception check */
#define fluid_check_fpe(expl) fluid_check_fpe_i386(expl) #define fluid_check_fpe(expl) fluid_check_fpe_i386(expl)
#define fluid_clear_fpe() fluid_clear_fpe_i386()
#else #else
/* Disable FPE exception check */
#define fluid_check_fpe(expl) #define fluid_check_fpe(expl)
#define fluid_clear_fpe()
#endif #endif
unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe); unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe);
void fluid_clear_fpe_i386(void);
#endif /* _FLUID_SYS_H */ #endif /* _FLUID_SYS_H */
+256 -337
View File
@@ -27,18 +27,6 @@
#include "fluid_sys.h" #include "fluid_sys.h"
#include "fluid_sfont.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 /* 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 */ specified value and filter q is below the other value, turn filter off */
#define FLUID_MAX_AUDIBLE_FILTER_FC 19000.0f #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 */ /* these should be the absolute minimum that FluidSynth can deal with */
#define FLUID_MIN_LOOP_SIZE 2 #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 */ /* min vol envelope release (to stop clicks) in SoundFont timecents */
#define FLUID_MIN_VOLENVRELEASE -7200.0f /* ~16ms */ #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 * new_fluid_voice
*/ */
@@ -324,66 +246,26 @@ fluid_voice_write(fluid_voice_t* voice,
fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf, fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf,
fluid_real_t* dsp_reverb_buf, fluid_real_t* dsp_chorus_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 incr;
fluid_real_t fres; 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; int dsp_interp_method = voice->interp_method;
fluid_real_t dsp_buf[FLUID_BUFSIZE];
#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_env_data_t* env_data; fluid_env_data_t* env_data;
fluid_real_t x; fluid_real_t x;
/* make sure we're playing and that we have sample data */ /* make sure we're playing and that we have sample data */
if (!_PLAYING(voice)) { if (!_PLAYING(voice)) return FLUID_OK;
return FLUID_OK;
}
/******************* sample **********************/ /******************* sample **********************/
if (voice->sample == NULL) { if (voice->sample == NULL)
{
fluid_voice_off(voice); fluid_voice_off(voice);
return FLUID_OK; return FLUID_OK;
} }
@@ -399,18 +281,22 @@ fluid_voice_write(fluid_voice_t* voice,
env_data = &voice->volenv_data[voice->volenv_section]; env_data = &voice->volenv_data[voice->volenv_section];
/* skip to the next section of the envelope if necessary */ /* 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]; env_data = &voice->volenv_data[++voice->volenv_section];
voice->volenv_count = 0; voice->volenv_count = 0;
} }
/* calculate the envelope value and check for valid range */ /* calculate the envelope value and check for valid range */
x = env_data->coeff * voice->volenv_val + env_data->incr; x = env_data->coeff * voice->volenv_val + env_data->incr;
if (x < env_data->min) { if (x < env_data->min)
{
x = env_data->min; x = env_data->min;
voice->volenv_section++; voice->volenv_section++;
voice->volenv_count = 0; voice->volenv_count = 0;
} else if (x > env_data->max) { }
else if (x > env_data->max)
{
x = env_data->max; x = env_data->max;
voice->volenv_section++; voice->volenv_section++;
voice->volenv_count = 0; voice->volenv_count = 0;
@@ -419,11 +305,13 @@ fluid_voice_write(fluid_voice_t* voice,
voice->volenv_val = x; voice->volenv_val = x;
voice->volenv_count++; voice->volenv_count++;
if (voice->volenv_section == FLUID_VOICE_ENVFINISHED) { if (voice->volenv_section == FLUID_VOICE_ENVFINISHED)
{
fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref); fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off (voice); fluid_voice_off (voice);
return FLUID_OK; return FLUID_OK;
} }
fluid_check_fpe ("voice_write vol env"); fluid_check_fpe ("voice_write vol env");
/******************* mod env **********************/ /******************* mod env **********************/
@@ -431,7 +319,8 @@ fluid_voice_write(fluid_voice_t* voice,
env_data = &voice->modenv_data[voice->modenv_section]; env_data = &voice->modenv_data[voice->modenv_section];
/* skip to the next section of the envelope if necessary */ /* 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]; env_data = &voice->modenv_data[++voice->modenv_section];
voice->modenv_count = 0; voice->modenv_count = 0;
} }
@@ -439,11 +328,14 @@ fluid_voice_write(fluid_voice_t* voice,
/* calculate the envelope value and check for valid range */ /* calculate the envelope value and check for valid range */
x = env_data->coeff * voice->modenv_val + env_data->incr; x = env_data->coeff * voice->modenv_val + env_data->incr;
if (x < env_data->min) { if (x < env_data->min)
{
x = env_data->min; x = env_data->min;
voice->modenv_section++; voice->modenv_section++;
voice->modenv_count = 0; voice->modenv_count = 0;
} else if (x > env_data->max) { }
else if (x > env_data->max)
{
x = env_data->max; x = env_data->max;
voice->modenv_section++; voice->modenv_section++;
voice->modenv_count = 0; voice->modenv_count = 0;
@@ -455,30 +347,42 @@ fluid_voice_write(fluid_voice_t* voice,
/******************* mod lfo **********************/ /******************* mod lfo **********************/
if (voice->ticks >= voice->modlfo_delay) { if (voice->ticks >= voice->modlfo_delay)
{
voice->modlfo_val += voice->modlfo_incr; 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_incr = -voice->modlfo_incr;
voice->modlfo_val = (fluid_real_t) 2.0 - voice->modlfo_val; 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_incr = -voice->modlfo_incr;
voice->modlfo_val = (fluid_real_t) -2.0 - voice->modlfo_val; 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 **********************/ /******************* vib lfo **********************/
if (voice->ticks >= voice->viblfo_delay) { if (voice->ticks >= voice->viblfo_delay)
{
voice->viblfo_val += voice->viblfo_incr; 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_incr = -voice->viblfo_incr;
voice->viblfo_val = (fluid_real_t) 2.0 - voice->viblfo_val; 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_incr = -voice->viblfo_incr;
voice->viblfo_val = (fluid_real_t) -2.0 - voice->viblfo_val; 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 **********************/ /******************* amplitude **********************/
@@ -488,35 +392,28 @@ fluid_voice_write(fluid_voice_t* voice,
* - amplitude envelope * - amplitude envelope
*/ */
if (voice->volenv_section == FLUID_VOICE_ENVDELAY) { if (voice->volenv_section == FLUID_VOICE_ENVDELAY)
/* The volume amplitude is in hold phase. No sound is produced. */ goto post_process; /* 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_ENVATTACK)
{
/* the envelope is in the attack section: ramp linearly to max value. /* the envelope is in the attack section: ramp linearly to max value.
* A positive modlfo_to_vol should increase volume (negative attenuation). * 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) * fluid_cb2amp (voice->modlfo_val * -voice->modlfo_to_vol)
* voice->volenv_val; * voice->volenv_val;
} else { }
else
{
fluid_real_t amplitude_that_reaches_noise_floor; fluid_real_t amplitude_that_reaches_noise_floor;
fluid_real_t amp_max; 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) * fluid_cb2amp (960.0f * (1.0f - voice->volenv_val)
+ voice->modlfo_val * -voice->modlfo_to_vol); + voice->modlfo_val * -voice->modlfo_to_vol);
/* Here we are trying to turn off a voice, if the volume has dropped /* We turn off a voice, if the volume has dropped low enough. */
* 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).
*/
/* A voice can be turned off, when an estimate for the volume /* A voice can be turned off, when an estimate for the volume
* (upper bound) falls below that volume, that will drop the * (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 /* If the loop amplitude is known, we can use it if the voice loop is within
* the sample loop * 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? */ /* 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; 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; 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 /* voice->attenuation_min is a lower boundary for the attenuation
* now and in the future (possibly 0 in the worst case). Now the * now and in the future (possibly 0 in the worst case). Now the
@@ -548,77 +438,39 @@ fluid_voice_write(fluid_voice_t* voice,
amp_max = fluid_atten2amp (voice->min_attenuation_cB) * voice->volenv_val; 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);
/* And if amp_max is already smaller than the known amplitude, /* And if amp_max is already smaller than the known amplitude,
* which will attenuate the sample below the noise floor, then we * which will attenuate the sample below the noise floor, then we
* can safely turn off the voice. Duh. */ * can safely turn off the voice. Duh. */
if (amp_max < amplitude_that_reaches_noise_floor){ if (amp_max < amplitude_that_reaches_noise_floor)
{
fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref); 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); fluid_voice_off (voice);
goto post_process; goto post_process;
} }
} }
/* At this point, dsp_amp is the desired amplitude for the voice. /* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
* This value will be reached at the end of the next buffer. So we voice->amp_incr = (target_amp - voice->amp) / FLUID_BUFSIZE;
* 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;
/* 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; goto post_process;
}
/* Calculate the number of samples, that the DSP loop advances /* Calculate the number of samples, that the DSP loop advances
* through the original waveform with each step in the output * through the original waveform with each step in the output
* buffer. It is the ratio between the frequencies of original * buffer. It is the ratio between the frequencies of original
* waveform and output waveform.*/ * waveform and output waveform.*/
incr = fluid_ct2hz_real(voice->pitch voice->phase_incr = fluid_ct2hz_real
+ voice->modlfo_val * voice->modlfo_to_pitch (voice->pitch + voice->modlfo_val * voice->modlfo_to_pitch
+ voice->viblfo_val * voice->viblfo_to_pitch + voice->viblfo_val * voice->viblfo_to_pitch
+ voice->modenv_val * voice->modenv_to_pitch) / voice->root_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);
/* 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"); fluid_check_fpe ("voice_write phase calculation");
/* Check, if we are really making progress through the original /* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
* sample. If the step size is rounded to 0, the DSP loop would get if (voice->phase_incr == 0) voice->phase_incr = 1;
* 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;
}
/*************** resonant filter ******************/ /*************** resonant filter ******************/
@@ -627,46 +479,27 @@ fluid_voice_write(fluid_voice_t* voice,
+ voice->modlfo_val * voice->modlfo_to_fc + voice->modlfo_val * voice->modlfo_to_fc
+ voice->modenv_val * voice->modenv_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 /* FIXME - Still potential for a click during turn on, can we interpolate
between 20khz cutoff and 0 Q? */ 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 /* I removed the optimization of turning the filter off when the
* resonance frequence is above the maximum frequency. Instead, 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 * 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 * synthesizer was run at lower sampling rates. Thanks to Stephan
* Tassart for pointing me to this bug. By turning the filter on and * Tassart for pointing me to this bug. By turning the filter on and
* clipping the maximum filter frequency at 0.45*srate, the filter * clipping the maximum filter frequency at 0.45*srate, the filter
* is used as an anti-aliasing 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; fres = 0.45f * voice->output_rate;
} else if (fres < 5) { else if (fres < 5)
fres = 5; fres = 5;
}
/* if filter enabled and there is a significant frequency change.. */ /* 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 /* The filter coefficients have to be recalculated (filter
* parameters have changed). Recalculation for various reasons is * parameters have changed). Recalculation for various reasons is
* forced by setting last_fres to -1. The flag filter_startup * 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 */ /* both b0 -and- b2 */
fluid_real_t b02_temp = b1_temp * 0.5f; 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. /* The filter is calculated, because the voice was started up.
* In this case set the filter coefficients without delay. * 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_coeff_incr_count = 0;
voice->filter_startup = 0; voice->filter_startup = 0;
// printf("Setting initial filter coefficients.\n"); // printf("Setting initial filter coefficients.\n");
} else { }
else
{
/* The filter frequency is changed. Calculate an increment /* The filter frequency is changed. Calculate an increment
* factor, so that the new setting is reached after one buffer * factor, so that the new setting is reached after one buffer
@@ -738,26 +574,6 @@ fluid_voice_write(fluid_voice_t* voice,
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");
@@ -766,94 +582,196 @@ fluid_voice_write(fluid_voice_t* voice,
* The buffer has to be filled from 0 to FLUID_BUFSIZE-1. * The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
* Depending on the position in the loop and the loop size, this * Depending on the position in the loop and the loop size, this
* may require several runs. */ * may require several runs. */
fluid_check_fpe("voice_write DSP processing");
if (((_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE)) voice->dsp_buf = dsp_buf;
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
/* At which index does the loop point occur in the output buffer? switch (voice->interp_method)
* This calculates the first index in the buffer, which uses {
* sample data taken after the looparound. */ case FLUID_INTERP_NONE:
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loopend, incr); count = fluid_dsp_float_interpolate_none (voice);
break;
if (end_in_buffer >= FLUID_BUFSIZE) { case FLUID_INTERP_LINEAR:
/* The loop occurs after the end of the buffer. count = fluid_dsp_float_interpolate_linear (voice);
* Process the whole buffer in one run. */ break;
dsp_start = 0; case FLUID_INTERP_4THORDER:
dsp_end = FLUID_BUFSIZE; default:
#include "fluid_dsp_core.c" count = fluid_dsp_float_interpolate_4th_order (voice);
break;
} else { case FLUID_INTERP_7THORDER:
/* The loop occurs during the current buffer length. Note, that count = fluid_dsp_float_interpolate_7th_order (voice);
* this method is unable to cope with a 'skipped' loop point. * break;
* 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"
} }
} else { fluid_check_fpe ("voice_write interpolation");
/* Not looping right now. */
dsp_start = 0; if (count > 0)
end_in_buffer = fluid_phase_steps(dsp_phase, voice->end, incr); fluid_voice_effects (voice, count, dsp_left_buf, dsp_right_buf,
dsp_reverb_buf, dsp_chorus_buf);
if (end_in_buffer >= FLUID_BUFSIZE) { /* turn off voice if short count (sample ended and not looping) */
/* Run the whole buffer at once */ if (count < FLUID_BUFSIZE)
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"
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref); fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off(voice); 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 ******************/ /* pan (Copy the signal to the left and right output buffer) The voice
/* copy back the state for the next cycle */ * 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->hist1 = dsp_hist1;
voice->hist2 = dsp_hist2; voice->hist2 = dsp_hist2;
voice->phase = dsp_phase;
voice->amp = dsp_amp;
voice->a1 = dsp_a1; voice->a1 = dsp_a1;
voice->a2 = dsp_a2; voice->a2 = dsp_a2;
voice->b02 = dsp_b02; voice->b02 = dsp_b02;
voice->b1 = dsp_b1; voice->b1 = dsp_b1;
voice->filter_coeff_incr_count = dsp_filter_coeff_incr_count; voice->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
/* if (dsp_filter_coeff_incr_count) { */ fluid_check_fpe ("voice_effects");
/* 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;
} }
/* /*
@@ -1718,9 +1636,10 @@ fluid_voice_off(fluid_voice_t* voice)
voice->status = FLUID_VOICE_OFF; voice->status = FLUID_VOICE_OFF;
/* Decrement the reference count of the sample. */ /* Decrement the reference count of the sample. */
if (voice->sample) {
fluid_sample_decr_ref(voice->sample); fluid_sample_decr_ref(voice->sample);
voice->sample = NULL; voice->sample = NULL;
}
return FLUID_OK; 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 */ /* make sure we have enough samples surrounding the loop */
int min_index_loop=(int) voice->sample->start + FLUID_MIN_LOOP_PAD; 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"); fluid_check_fpe("voice_check_sample_sanity start");
if (!voice->check_sample_sanity_flag){ if (!voice->check_sample_sanity_flag){
+17 -14
View File
@@ -60,14 +60,6 @@ enum fluid_voice_envelope_index_t{
FLUID_VOICE_ENVLAST 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 * fluid_voice_t
*/ */
@@ -116,12 +108,16 @@ struct _fluid_voice_t
unsigned int start_time; unsigned int start_time;
unsigned int ticks; 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 */ fluid_phase_t phase; /* the phase of the sample wave */
#if 0 /* Temporary variables used in fluid_voice_write() */
fluid_real_t incr; /* the phase increment for the next 64 samples [NEW, PH] */
#endif 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 */ /* basic parameters */
fluid_real_t pitch; /* the pitch in midicents */ fluid_real_t pitch; /* the pitch in midicents */
@@ -134,7 +130,7 @@ struct _fluid_voice_t
int start; int start;
int end; int end;
int loopstart; int loopstart;
int loopend; int loopend; /* Note: first point following the loop (superimposed on loopstart) */
/* master gain */ /* master gain */
fluid_real_t synth_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_CHECK (1 << 0)
#define FLUID_SAMPLESANITY_STARTUP (1 << 1) #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 */ #endif /* _FLUID_VOICE_H */
+9 -8
View File
@@ -18,7 +18,9 @@
* 02111-1307, USA * 02111-1307, USA
*/ */
#if HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -37,10 +39,6 @@
#include "fluidsynth.h" #include "fluidsynth.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(WIN32) && !defined(MINGW32) #if defined(WIN32) && !defined(MINGW32)
#include "config_win32.h" #include "config_win32.h"
#endif #endif
@@ -458,13 +456,16 @@ int main(int argc, char** argv)
fluid_source(cmd_handler, buf); 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++) { for (i = arg1; i < argc; i++) {
if ((argv[i][0] != '-') && fluid_is_soundfont(argv[i])) { if (fluid_is_soundfont(argv[i]))
if (fluid_synth_sfload(synth, argv[i], 1) == -1) { {
if (fluid_synth_sfload(synth, argv[i], 1) == -1)
fprintf(stderr, "Failed to load the SoundFont %s\n", argv[i]); 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 #ifdef HAVE_SIGNAL_H
+3 -18
View File
@@ -26,9 +26,9 @@
#include "config.h" #include "config.h"
#endif #endif
//#if defined(__POWERPC__) && !(defined(__APPLE__) && defined(__MACH__)) #if defined(__POWERPC__) && !(defined(__APPLE__) && defined(__MACH__))
//#include "config_maxmsp43.h" #include "config_maxmsp43.h"
//#endif #endif
#if defined(WIN32) && !defined(MINGW32) #if defined(WIN32) && !defined(MINGW32)
#include "config_win32.h" #include "config_win32.h"
@@ -283,21 +283,6 @@ typedef FILE* fluid_file;
#define fluid_clip(_val, _min, _max) \ #define fluid_clip(_val, _min, _max) \
{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); } { (_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 #if WITH_FTS
#define FLUID_PRINTF post #define FLUID_PRINTF post
#define FLUID_FLUSH() #define FLUID_FLUSH()