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