imported a stripped down fluidsynth 1.0.7

* a shared library is built, no audio driver is included
* implemented some platform specific functions (fluid_sys.*)
* a test app is provided in fluidsynth.c
* on target Haiku, posix mutex are used, else mutexes are implemented with simple semaphores (I could be wrong here)
well I hope it can provide a good enough backend for a softsynth
Note that needed SF2 banks would probably not be included.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17799 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2006-06-12 15:55:38 +00:00
parent 5522045320
commit 2814f73c87
86 changed files with 32111 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
/* 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 _FLUIDSYNTH_H
#define _FLUIDSYNTH_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(WIN32)
#if defined(FLUIDSYNTH_DLL_EXPORTS)
#define FLUIDSYNTH_API __declspec(dllexport)
#elif defined(FLUIDSYNTH_NOT_A_DLL)
#define FLUIDSYNTH_API
#else
#define FLUIDSYNTH_API __declspec(dllimport)
#endif
#elif defined(MACOS9)
#define FLUIDSYNTH_API __declspec(export)
#else
#define FLUIDSYNTH_API
#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.
*/
#include "fluidsynth/types.h"
#include "fluidsynth/settings.h"
#include "fluidsynth/synth.h"
#include "fluidsynth/shell.h"
#include "fluidsynth/sfont.h"
#include "fluidsynth/ramsfont.h"
#include "fluidsynth/audio.h"
#include "fluidsynth/event.h"
#include "fluidsynth/midi.h"
#include "fluidsynth/seq.h"
#include "fluidsynth/seqbind.h"
#include "fluidsynth/log.h"
#include "fluidsynth/misc.h"
#include "fluidsynth/mod.h"
#include "fluidsynth/gen.h"
#include "fluidsynth/voice.h"
#include "fluidsynth/version.h"
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_H */
@@ -0,0 +1,56 @@
/* 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 _FLUIDSYNTH_AUDIO_H
#define _FLUIDSYNTH_AUDIO_H
#ifdef __cplusplus
extern "C" {
#endif
/** Audio driver
*
*
*/
/** The function should return non-zero if an error occured. */
typedef int (*fluid_audio_func_t)(void* data, int len,
int nin, float** in,
int nout, float** out);
FLUIDSYNTH_API fluid_audio_driver_t* new_fluid_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
FLUIDSYNTH_API fluid_audio_driver_t* new_fluid_audio_driver2(fluid_settings_t* settings,
fluid_audio_func_t func,
void* data);
FLUIDSYNTH_API void delete_fluid_audio_driver(fluid_audio_driver_t* driver);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_AUDIO_H */
+114
View File
@@ -0,0 +1,114 @@
/* 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 _FLUIDSYNTH_EVENT_H
#define _FLUIDSYNTH_EVENT_H
#ifdef __cplusplus
extern "C" {
#endif
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
};
/* Event alloc/free */
FLUIDSYNTH_API fluid_event_t* new_fluid_event(void);
FLUIDSYNTH_API void delete_fluid_event(fluid_event_t* evt);
/* Initializing events */
FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t* evt, short src);
FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t* evt, short dest);
/* Timer events */
FLUIDSYNTH_API void fluid_event_timer(fluid_event_t* evt, void* data);
/* Note events */
FLUIDSYNTH_API void fluid_event_note(fluid_event_t* evt, int channel,
short key, short vel,
unsigned int duration);
FLUIDSYNTH_API void fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel);
FLUIDSYNTH_API void fluid_event_noteoff(fluid_event_t* evt, int channel, short key);
FLUIDSYNTH_API void fluid_event_all_sounds_off(fluid_event_t* evt, int channel);
FLUIDSYNTH_API void fluid_event_all_notes_off(fluid_event_t* evt, int channel);
/* Instrument selection */
FLUIDSYNTH_API void fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num);
FLUIDSYNTH_API void fluid_event_program_change(fluid_event_t* evt, int channel, short preset_num);
FLUIDSYNTH_API void fluid_event_program_select(fluid_event_t* evt, int channel, unsigned int sfont_id, short bank_num, short preset_num);
/* Real-time generic instrument controllers */
FLUIDSYNTH_API
void fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val);
/* Real-time instrument controllers shortcuts */
FLUIDSYNTH_API void fluid_event_pitch_bend(fluid_event_t* evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_pan(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_volume(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t* evt, int channel, short val);
/* Only for removing events */
FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel);
/* Accessing event data */
FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_source(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_dest(fluid_event_t* evt);
FLUIDSYNTH_API int fluid_event_get_channel(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_key(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_velocity(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_control(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_value(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_program(fluid_event_t* evt);
FLUIDSYNTH_API void* fluid_event_get_data(fluid_event_t* evt);
FLUIDSYNTH_API unsigned int fluid_event_get_duration(fluid_event_t* evt);
FLUIDSYNTH_API short fluid_event_get_bank(fluid_event_t* evt);
FLUIDSYNTH_API int fluid_event_get_pitch(fluid_event_t* evt);
FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t* evt);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_EVENT_H */
+129
View File
@@ -0,0 +1,129 @@
/* 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 _FLUIDSYNTH_GEN_H
#define _FLUIDSYNTH_GEN_H
#ifdef __cplusplus
extern "C" {
#endif
/** List of generator 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,
/* 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
};
/*
* fluid_gen_t
* Sound font generator
*/
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 */
} fluid_gen_t;
enum fluid_gen_flags
{
GEN_UNUSED,
GEN_SET,
GEN_ABS_NRPN
};
/** Reset an array of generators to the SF2.01 default values */
FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_GEN_H */
+85
View File
@@ -0,0 +1,85 @@
/* 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 _FLUIDSYNTH_LOG_H
#define _FLUIDSYNTH_LOG_H
#ifdef __cplusplus
extern "C" {
#endif
/**
*
* 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.
*
* 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,
* and ignores all other messages by setting the log function to
* NULL:
*
* ...
* 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_DBG, NULL, NULL);
* ...
*
*/
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 */
LAST_LOG_LEVEL
};
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
#endif /* _FLUIDSYNTH_LOG_H */
+134
View File
@@ -0,0 +1,134 @@
/* 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 _FLUIDSYNTH_MIDI_H
#define _FLUIDSYNTH_MIDI_H
#ifdef __cplusplus
extern "C" {
#endif
FLUIDSYNTH_API fluid_midi_event_t* new_fluid_midi_event(void);
FLUIDSYNTH_API int delete_fluid_midi_event(fluid_midi_event_t* event);
FLUIDSYNTH_API int fluid_midi_event_set_type(fluid_midi_event_t* evt, int type);
FLUIDSYNTH_API int fluid_midi_event_get_type(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_channel(fluid_midi_event_t* evt, int chan);
FLUIDSYNTH_API int fluid_midi_event_get_channel(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_get_key(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_key(fluid_midi_event_t* evt, int key);
FLUIDSYNTH_API int fluid_midi_event_get_velocity(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_velocity(fluid_midi_event_t* evt, int vel);
FLUIDSYNTH_API int fluid_midi_event_get_control(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_control(fluid_midi_event_t* evt, int ctrl);
FLUIDSYNTH_API int fluid_midi_event_get_value(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_value(fluid_midi_event_t* evt, int val);
FLUIDSYNTH_API int fluid_midi_event_get_program(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t* evt, int val);
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.
* Will be used between
* - MIDI driver and MIDI router
* - MIDI router and synth
* to communicate events.
* In the not-so-far future...
*/
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,
void* event_handler_data);
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);
FLUIDSYNTH_API int delete_fluid_player(fluid_player_t* player);
FLUIDSYNTH_API int fluid_player_add(fluid_player_t* player, char* midifile);
FLUIDSYNTH_API int fluid_player_play(fluid_player_t* player);
FLUIDSYNTH_API int fluid_player_stop(fluid_player_t* player);
FLUIDSYNTH_API int fluid_player_join(fluid_player_t* player);
FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t* player, int loop);
FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t* player, int tempo);
FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t* player, int bpm);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MIDI_H */
+65
View File
@@ -0,0 +1,65 @@
/* 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 _FLUIDSYNTH_MISC_H
#define _FLUIDSYNTH_MISC_H
#ifdef __cplusplus
extern "C" {
#endif
/*
*
* Utility functions
*/
/**
* fluid_is_soundfont returns 1 if the specified filename is a
* soundfont. It retuns 0 otherwise. The current implementation only
* checks for the "RIFF" header in the file. It is useful only to
* distinguish between SoundFonts and MIDI files.
*/
FLUIDSYNTH_API int fluid_is_soundfont(char* filename);
/**
* fluid_is_midifile returns 1 if the specified filename is a MIDI
* file. It retuns 0 otherwise. The current implementation only checks
* for the "MThd" header in the file.
*/
FLUIDSYNTH_API int fluid_is_midifile(char* filename);
#ifdef WIN32
/** Set the handle to the instance of the application on the Windows
platform. The handle is needed to open DirectSound. */
FLUIDSYNTH_API void* fluid_get_hinstance(void);
FLUIDSYNTH_API void fluid_set_hinstance(void* hinstance);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MISC_H */
+112
View File
@@ -0,0 +1,112 @@
/* 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 _FLUIDSYNTH_MOD_H
#define _FLUIDSYNTH_MOD_H
#ifdef __cplusplus
extern "C" {
#endif
/* Modulator-related definitions */
/* Maximum number of modulators in a voice */
#define FLUID_NUM_MOD 64
/*
* fluid_mod_t
*/
struct _fluid_mod_t
{
unsigned char dest;
unsigned char src1;
unsigned char flags1;
unsigned char src2;
unsigned char flags2;
double amount;
/* The 'next' field allows to link modulators into a list. It is
* not used in fluid_voice.c, there each voice allocates memory for a
* fixed number of modulators. Since there may be a huge number of
* different zones, this is more efficient.
*/
fluid_mod_t * next;
};
/* Flags telling the polarity of a modulator. Compare with SF2.01
section 8.2. Note: The numbers of the bits are different! (for
example: in the flags of a SF modulator, the polarity bit is bit
nr. 9) */
enum fluid_mod_flags
{
FLUID_MOD_POSITIVE = 0,
FLUID_MOD_NEGATIVE = 1,
FLUID_MOD_UNIPOLAR = 0,
FLUID_MOD_BIPOLAR = 2,
FLUID_MOD_LINEAR = 0,
FLUID_MOD_CONCAVE = 4,
FLUID_MOD_CONVEX = 8,
FLUID_MOD_SWITCH = 12,
FLUID_MOD_GC = 0,
FLUID_MOD_CC = 16
};
/* Flags telling the source of a modulator. This corresponds to
* SF2.01 section 8.2.1 */
enum fluid_mod_src
{
FLUID_MOD_NONE = 0,
FLUID_MOD_VELOCITY = 2,
FLUID_MOD_KEY = 3,
FLUID_MOD_KEYPRESSURE = 10,
FLUID_MOD_CHANNELPRESSURE = 13,
FLUID_MOD_PITCHWHEEL = 14,
FLUID_MOD_PITCHWHEELSENS = 16
};
/* Allocates memory for a new modulator */
FLUIDSYNTH_API fluid_mod_t * fluid_mod_new(void);
/* Frees the modulator */
FLUIDSYNTH_API void fluid_mod_delete(fluid_mod_t * mod);
FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags);
FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags);
FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t* mod, int dst);
FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t* mod, double amount);
FLUIDSYNTH_API int fluid_mod_get_source1(fluid_mod_t* mod);
FLUIDSYNTH_API int fluid_mod_get_flags1(fluid_mod_t* mod);
FLUIDSYNTH_API int fluid_mod_get_source2(fluid_mod_t* mod);
FLUIDSYNTH_API int fluid_mod_get_flags2(fluid_mod_t* mod);
FLUIDSYNTH_API int fluid_mod_get_dest(fluid_mod_t* mod);
FLUIDSYNTH_API double fluid_mod_get_amount(fluid_mod_t* mod);
/* Determines, if two modulators are 'identical' (all parameters
except the amount match) */
FLUIDSYNTH_API int fluid_mod_test_identity(fluid_mod_t * mod1, fluid_mod_t * mod2);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MOD_H */
@@ -0,0 +1,113 @@
/* 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 _FLUIDSYNTH_RAMSFONT_H
#define _FLUIDSYNTH_RAMSFONT_H
#ifdef __cplusplus
extern "C" {
#endif
/********************************************************************************/
/********************************************************************************/
/* ram soundfonts:
October 2002 - Antoine Schmitt
ram soundfonts live in ram. The samples are loaded from files
or from RAM. A minimal API manages a soundFont structure,
with presets, each preset having only one preset-zone, which
instrument has potentially many instrument-zones. No global
zones, and nor generator nor modulator other than the default
ones are permitted. This may be extensible in the future.
*/
/********************************************************************************/
/********************************************************************************/
/*
We are not using the sfloader protocol, as we need more arguments
than what it provides.
*/
/** Creates a fluid_sfont_t wrapping an fluid_ramsfont_t */
FLUIDSYNTH_API fluid_sfont_t* fluid_ramsfont_create_sfont(void);
/***********************
* ramsfont specific API
***********************/
FLUIDSYNTH_API int fluid_ramsfont_set_name(fluid_ramsfont_t* sfont, char * name);
/* Creates one instrument zone for the sample inside the preset defined
* by bank/num
* \returns 0 if success
*/
FLUIDSYNTH_API
int fluid_ramsfont_add_izone(fluid_ramsfont_t* sfont,
unsigned int bank, unsigned int num, fluid_sample_t* sample,
int lokey, int hikey);
/* Removes the instrument zone corresponding to bank/num and to the sample
* \returns 0 if success
*/
FLUIDSYNTH_API
int fluid_ramsfont_remove_izone(fluid_ramsfont_t* sfont,
unsigned int bank, unsigned int num, fluid_sample_t* sample);
/* Sets a generator on an instrument zone
* \returns 0 if success
*/
FLUIDSYNTH_API
int fluid_ramsfont_izone_set_gen(fluid_ramsfont_t* sfont,
unsigned int bank, unsigned int num, fluid_sample_t* sample,
int gen_type, float value);
/* Utility : sets the loop start/end values
* \on = 0 or 1; if 0, loopstart and loopend are not used
* \loopstart and loopend are floats, in frames
* \loopstart is counted from frame 0
* \loopend is counted from the last frame, thus is < 0
* \returns 0 if success
*/
FLUIDSYNTH_API
int fluid_ramsfont_izone_set_loop(fluid_ramsfont_t* sfont,
unsigned int bank, unsigned int num, fluid_sample_t* sample,
int on, float loopstart, float loopend);
/***************************************
* sample_t specific API for ramsfont
***************************************/
FLUIDSYNTH_API fluid_sample_t* new_fluid_ramsample(void);
FLUIDSYNTH_API int delete_fluid_ramsample(fluid_sample_t* sample);
FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t* sample, char * name);
/* Sets the sound data of the sample
* Warning : if copy_data is FALSE, data should have 8 unused frames at start
* and 8 unused frames at the end.
*/
FLUIDSYNTH_API
int fluid_sample_set_sound_data(fluid_sample_t* sample, short *data,
unsigned int nbframes, short copy_data, int rootkey);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_RAMSFONT_H */
+109
View File
@@ -0,0 +1,109 @@
/* 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 _FLUIDSYNTH_SEQ_H
#define _FLUIDSYNTH_SEQ_H
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*fluid_event_callback_t)(unsigned int time, fluid_event_t* event,
fluid_sequencer_t* seq, void* data);
/** Allocate a new sequencer structure */
FLUIDSYNTH_API fluid_sequencer_t* new_fluid_sequencer(void);
/** Free the sequencer structure */
FLUIDSYNTH_API void delete_fluid_sequencer(fluid_sequencer_t* seq);
/** clients can be sources or destinations of events. These functions ensure a unique ID for any
source or dest, for filtering purposes.
sources only dont need to register a callback.
*/
/** Register a client. The registration returns a unique client ID (-1 if error) */
FLUIDSYNTH_API
short fluid_sequencer_register_client(fluid_sequencer_t* seq, char* name,
fluid_event_callback_t callback, void* data);
/** Unregister a previously registered client. */
FLUIDSYNTH_API void fluid_sequencer_unregister_client(fluid_sequencer_t* seq, short id);
/** Returns the number of register clients. */
FLUIDSYNTH_API int fluid_sequencer_count_clients(fluid_sequencer_t* seq);
/** Returns the id of a registered client (-1 if non existing) */
FLUIDSYNTH_API short fluid_sequencer_get_client_id(fluid_sequencer_t* seq, int index);
/** Returns the name of a registered client, given its id. */
FLUIDSYNTH_API char* fluid_sequencer_get_client_name(fluid_sequencer_t* seq, int id);
/** Returns 1 if client is a destination (has a callback) */
FLUIDSYNTH_API int fluid_sequencer_client_is_dest(fluid_sequencer_t* seq, int id);
/** Sending an event immediately. */
FLUIDSYNTH_API void fluid_sequencer_send_now(fluid_sequencer_t* seq, fluid_event_t* evt);
/** Schedule an event for later sending. If absolute is 0, the time of
the event will be offset with the current tick of the
sequencer. If absolute is different from 0, the time will assumed
to be absolute (starting from the creation of the sequencer).
MAKES A COPY */
FLUIDSYNTH_API
int fluid_sequencer_send_at(fluid_sequencer_t* seq, fluid_event_t* evt,
unsigned int time, int absolute);
/** Remove events from the event queue. The events can be filtered on
the source, the destination, and the type of the event. To avoid
filtering, set either source, dest, or type to -1. */
FLUIDSYNTH_API
void fluid_sequencer_remove_events(fluid_sequencer_t* seq, short source, short dest, int type);
/** Get the current tick */
FLUIDSYNTH_API unsigned int fluid_sequencer_get_tick(fluid_sequencer_t* seq);
/** Set the conversion from tick to absolute time. scale should be
expressed as ticks per second. */
FLUIDSYNTH_API void fluid_sequencer_set_time_scale(fluid_sequencer_t* seq, double scale);
/** Set the conversion from tick to absolute time (ticks per
second). */
FLUIDSYNTH_API double fluid_sequencer_get_time_scale(fluid_sequencer_t* seq);
// compile in internal traceing functions
#define FLUID_SEQ_WITH_TRACE 0
#if FLUID_SEQ_WITH_TRACE
FLUIDSYNTH_API char * fluid_seq_gettrace(fluid_sequencer_t* seq);
FLUIDSYNTH_API void fluid_seq_cleartrace(fluid_sequencer_t* seq);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SEQ_H */
@@ -0,0 +1,44 @@
/* 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 _FLUIDSYNTH_SEQBIND_H
#define _FLUIDSYNTH_SEQBIND_H
#include "fluidsynth/seq.h"
#ifdef __cplusplus
extern "C" {
#endif
/** registers fluidsynth as a client of the given sequencer.
The fluidsynth is registered with the name "fluidsynth".
\returns the fluidsynth destID.
*/
FLUIDSYNTH_API
short fluid_sequencer_register_fluidsynth(fluid_sequencer_t* seq, fluid_synth_t* synth);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SEQBIND_H */
@@ -0,0 +1,223 @@
/* 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 _FLUIDSYNTH_SETTINGS_H
#define _FLUIDSYNTH_SETTINGS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
*
* Synthesizer settings
*
*
* The create a synthesizer object you will have to specify its
* settings. These settings are stored in the structure below.
* void my_synthesizer()
* {
* fluid_settings_t* settings;
* fluid_synth_t* synth;
* fluid_audio_driver_t* adriver;
*
*
* settings = new_fluid_settings();
* fluid_settings_setstr(settings, "audio.driver", "alsa");
* // ... change settings ...
* synth = new_fluid_synth(settings);
* adriver = new_fluid_audio_driver(settings, synth);
*
* ...
*
* }
*
*
*/
/* Hint FLUID_HINT_BOUNDED_BELOW indicates that the LowerBound field
of the FLUID_PortRangeHint should be considered meaningful. The
value in this field should be considered the (inclusive) lower
bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also
specified then the value of LowerBound should be multiplied by the
sample rate. */
#define FLUID_HINT_BOUNDED_BELOW 0x1
/* Hint FLUID_HINT_BOUNDED_ABOVE indicates that the UpperBound field
of the FLUID_PortRangeHint should be considered meaningful. The
value in this field should be considered the (inclusive) upper
bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also
specified then the value of UpperBound should be multiplied by the
sample rate. */
#define FLUID_HINT_BOUNDED_ABOVE 0x2
/* Hint FLUID_HINT_TOGGLED indicates that the data item should be
considered a Boolean toggle. Data less than or equal to zero should
be considered `off' or `false,' and data above zero should be
considered `on' or `true.' FLUID_HINT_TOGGLED may not be used in
conjunction with any other hint except FLUID_HINT_DEFAULT_0 or
FLUID_HINT_DEFAULT_1. */
#define FLUID_HINT_TOGGLED 0x4
/* Hint FLUID_HINT_SAMPLE_RATE indicates that any bounds specified
should be interpreted as multiples of the sample rate. For
instance, a frequency range from 0Hz to the Nyquist frequency (half
the sample rate) could be requested by this hint in conjunction
with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
at all must support this hint to retain meaning. */
#define FLUID_HINT_SAMPLE_RATE 0x8
/* Hint FLUID_HINT_LOGARITHMIC indicates that it is likely that the
user will find it more intuitive to view values using a logarithmic
scale. This is particularly useful for frequencies and gains. */
#define FLUID_HINT_LOGARITHMIC 0x10
/* Hint FLUID_HINT_INTEGER indicates that a user interface would
probably wish to provide a stepped control taking only integer
values. Any bounds set should be slightly wider than the actual
integer range required to avoid floating point rounding errors. For
instance, the integer set {0,1,2,3} might be described as [-0.1,
3.1]. */
#define FLUID_HINT_INTEGER 0x20
#define FLUID_HINT_FILENAME 0x01
#define FLUID_HINT_OPTIONLIST 0x02
enum fluid_types_enum {
FLUID_NO_TYPE = -1,
FLUID_NUM_TYPE,
FLUID_INT_TYPE,
FLUID_STR_TYPE,
FLUID_SET_TYPE
};
FLUIDSYNTH_API fluid_settings_t* new_fluid_settings(void);
FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t* settings);
FLUIDSYNTH_API
int fluid_settings_get_type(fluid_settings_t* settings, char* name);
FLUIDSYNTH_API
int fluid_settings_get_hints(fluid_settings_t* settings, char* name);
/** Returns whether the setting is changeable in real-time. */
FLUIDSYNTH_API int fluid_settings_is_realtime(fluid_settings_t* settings, char* name);
/** returns 1 if the value has been set, 0 otherwise */
FLUIDSYNTH_API
int fluid_settings_setstr(fluid_settings_t* settings, char* name, char* str);
/**
Get the value of a string setting. If the value does not exists,
'str' is set to NULL. Otherwise, 'str' will point to the
value. The application does not own the returned value. Instead,
the application should make a copy of the value if it needs it
later.
\returns 1 if the value exists, 0 otherwise
*/
FLUIDSYNTH_API
int fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str);
/** Get the default value of a string setting. */
FLUIDSYNTH_API
char* fluid_settings_getstr_default(fluid_settings_t* settings, char* name);
/** Get the value of a numeric setting.
\returns 1 if the value exists and is equal to 'value', 0
otherwise
*/
FLUIDSYNTH_API
int fluid_settings_str_equal(fluid_settings_t* settings, char* name, char* value);
/** returns 1 if the value has been set, 0 otherwise */
FLUIDSYNTH_API
int fluid_settings_setnum(fluid_settings_t* settings, char* name, double val);
/** returns 1 if the value exists, 0 otherwise */
FLUIDSYNTH_API
int fluid_settings_getnum(fluid_settings_t* settings, char* name, double* val);
/** Get the default value of a string setting. */
FLUIDSYNTH_API
double fluid_settings_getnum_default(fluid_settings_t* settings, char* name);
/** Get the range of values of a numeric settings. */
FLUIDSYNTH_API
void fluid_settings_getnum_range(fluid_settings_t* settings, char* name,
double* min, double* max);
/** returns 1 if the value has been set, 0 otherwise */
FLUIDSYNTH_API
int fluid_settings_setint(fluid_settings_t* settings, char* name, int val);
/** returns 1 if the value exists, 0 otherwise */
FLUIDSYNTH_API
int fluid_settings_getint(fluid_settings_t* settings, char* name, int* val);
/** Get the default value of a string setting. */
FLUIDSYNTH_API
int fluid_settings_getint_default(fluid_settings_t* settings, char* name);
/** Get the range of values of a numeric settings. */
FLUIDSYNTH_API
void fluid_settings_getint_range(fluid_settings_t* settings, char* name,
int* min, int* max);
typedef void (*fluid_settings_foreach_option_t)(void* data, char* name, char* option);
FLUIDSYNTH_API
void fluid_settings_foreach_option(fluid_settings_t* settings,
char* name, void* data,
fluid_settings_foreach_option_t func);
typedef void (*fluid_settings_foreach_t)(void* data, char* s, int type);
FLUIDSYNTH_API
void fluid_settings_foreach(fluid_settings_t* settings, void* data,
fluid_settings_foreach_t func);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SETTINGS_H */
+193
View File
@@ -0,0 +1,193 @@
/* 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 _FLUIDSYNTH_SFONT_H
#define _FLUIDSYNTH_SFONT_H
#ifdef __cplusplus
extern "C" {
#endif
/**
*
* SoundFont plugins
*
* It is possible to add new SoundFont loaders to the
* synthesizer. The API uses a couple of "interfaces" (structures
* with callback functions): fluid_sfloader_t, fluid_sfont_t, and
* fluid_preset_t.
*
* To add a new SoundFont loader to the synthesizer, call
* fluid_synth_add_sfloader() and pass a pointer to an
* fluid_sfloader_t structure. The important callback function in
* this structure is "load", which should try to load a file and
* returns a fluid_sfont_t structure, or NULL if it fails.
*
* The fluid_sfont_t structure contains a callback to obtain the
* name of the soundfont. It contains two functions to iterate
* though the contained presets, and one function to obtain a
* preset corresponding to a bank and preset number. This
* function should return an fluid_preset_t structure.
*
* The fluid_preset_t structure contains some functions to obtain
* information from the preset (name, bank, number). The most
* important callback is the noteon function. The noteon function
* should call fluid_synth_alloc_voice() for every sample that has
* to be played. fluid_synth_alloc_voice() expects a pointer to a
* fluid_sample_t structure and returns a pointer to the opaque
* fluid_voice_t structure. To set or increments the values of a
* generator, use fluid_voice_gen_{set,incr}. When you are
* finished initializing the voice call fluid_voice_start() to
* start playing the synthesis voice.
* */
enum {
FLUID_PRESET_SELECTED,
FLUID_PRESET_UNSELECTED,
FLUID_SAMPLE_DONE
};
/*
* fluid_sfloader_t
*/
struct _fluid_sfloader_t {
/** Private data */
void* data;
/** The free must free the memory allocated for the loader in
* addition to any private data. It should return 0 if no error
* occured, non-zero otherwise.*/
int (*free)(fluid_sfloader_t* loader);
/** Load a file. Returns NULL if an error occured. */
fluid_sfont_t* (*load)(fluid_sfloader_t* loader, const char* filename);
};
/*
* fluid_sfont_t
*/
struct _fluid_sfont_t {
void* data;
unsigned int id;
/** The 'free' callback function should return 0 when it was able to
free all resources. It should return a non-zero value if some of
the samples could not be freed because they are still in use. */
int (*free)(fluid_sfont_t* sfont);
/** Return the name of the sfont */
char* (*get_name)(fluid_sfont_t* sfont);
/** Return the preset with the specified bank and preset number. All
* the fields, including the 'sfont' field, should * be filled
* in. If the preset cannot be found, the function returns NULL. */
fluid_preset_t* (*get_preset)(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
void (*iteration_start)(fluid_sfont_t* sfont);
/* return 0 when no more presets are available, 1 otherwise */
int (*iteration_next)(fluid_sfont_t* sfont, fluid_preset_t* preset);
};
#define fluid_sfont_get_id(_sf) ((_sf)->id)
/*
* fluid_preset_t
*/
struct _fluid_preset_t {
void* data;
fluid_sfont_t* sfont;
int (*free)(fluid_preset_t* preset);
char* (*get_name)(fluid_preset_t* preset);
int (*get_banknum)(fluid_preset_t* preset);
int (*get_num)(fluid_preset_t* preset);
/** handle a noteon event. Returns 0 if no error occured. */
int (*noteon)(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
/** Implement this function if the preset needs to be notified about
preset select and unselect events. */
int (*notify)(fluid_preset_t* preset, int reason, int chan);
};
/*
* fluid_sample_t
*/
struct _fluid_sample_t
{
char name[21];
unsigned int start;
unsigned int end;
unsigned int loopstart;
unsigned int loopend;
unsigned int samplerate;
int origpitch;
int pitchadj;
int sampletype;
int valid;
short* data;
/** The amplitude, that will lower the level of the sample's loop to
the noise floor. Needed for note turnoff optimization, will be
filled out automatically */
/* Set this to zero, when submitting a new sample. */
int amplitude_that_reaches_noise_floor_is_valid;
double amplitude_that_reaches_noise_floor;
/** Count the number of playing voices that use this sample. */
unsigned int refcount;
/** Implement this function if the sample or SoundFont needs to be
notified when the sample is no longer used. */
int (*notify)(fluid_sample_t* sample, int reason);
/** Pointer to SoundFont specific data */
void* userdata;
};
#define fluid_sample_refcount(_sample) ((_sample)->refcount)
/** Sample types */
#define FLUID_SAMPLETYPE_MONO 1
#define FLUID_SAMPLETYPE_RIGHT 2
#define FLUID_SAMPLETYPE_LEFT 4
#define FLUID_SAMPLETYPE_LINKED 8
#define FLUID_SAMPLETYPE_ROM 0x8000
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SFONT_H */
+137
View File
@@ -0,0 +1,137 @@
/* 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 _FLUIDSYNTH_SHELL_H
#define _FLUIDSYNTH_SHELL_H
#ifdef __cplusplus
extern "C" {
#endif
/*
*
* Shell interface
*
* The shell interface allows you to send simple textual commands to
* the synthesizer, to parse a command file, or to read commands
* from the stdin or other input streams.
*
* To find the list of currently supported commands, please check the
* fluid_cmd.c file.
*
*/
FLUIDSYNTH_API fluid_istream_t fluid_get_stdin(void);
FLUIDSYNTH_API fluid_ostream_t fluid_get_stdout(void);
FLUIDSYNTH_API char* fluid_get_userconf(char* buf, int len);
FLUIDSYNTH_API char* fluid_get_sysconf(char* buf, int len);
/** The command structure */
typedef int (*fluid_cmd_func_t)(void* data, int ac, char** av, fluid_ostream_t out);
typedef struct {
char* name; /** The name of the command, as typed in in the shell */
char* topic; /** The help topic group of this command */
fluid_cmd_func_t handler; /** Pointer to the handler for this command */
void* data; /** Pointer to the user data */
char* help; /** A help string */
} fluid_cmd_t;
/** The command handler */
/**
Create a new command handler. If the synth object passed as
argument is not NULL, the handler will add all the default
synthesizer commands to the command list.
\param synth The synthesizer object
\returns A new command handler
*/
FLUIDSYNTH_API
fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth);
FLUIDSYNTH_API
void delete_fluid_cmd_handler(fluid_cmd_handler_t* handler);
FLUIDSYNTH_API
void fluid_cmd_handler_set_synth(fluid_cmd_handler_t* handler, fluid_synth_t* synth);
/**
Register a new command to the handler. The handler makes a private
copy of the 'cmd' structure passed as argument.
\param handler A pointer to the command handler
\param cmd A pointer to the command structure
\returns 0 if the command was inserted, non-zero if error
*/
FLUIDSYNTH_API
int fluid_cmd_handler_register(fluid_cmd_handler_t* handler, fluid_cmd_t* cmd);
FLUIDSYNTH_API
int fluid_cmd_handler_unregister(fluid_cmd_handler_t* handler, char* cmd);
/** Command function */
FLUIDSYNTH_API
int fluid_command(fluid_cmd_handler_t* handler, char* cmd, fluid_ostream_t out);
FLUIDSYNTH_API
int fluid_source(fluid_cmd_handler_t* handler, char* filename);
FLUIDSYNTH_API
void fluid_usershell(fluid_settings_t* settings, fluid_cmd_handler_t* handler);
/** Shell */
FLUIDSYNTH_API
fluid_shell_t* new_fluid_shell(fluid_settings_t* settings, fluid_cmd_handler_t* handler,
fluid_istream_t in, fluid_ostream_t out, int thread);
FLUIDSYNTH_API void delete_fluid_shell(fluid_shell_t* shell);
/** TCP/IP server */
typedef fluid_cmd_handler_t* (*fluid_server_newclient_func_t)(void* data, char* addr);
FLUIDSYNTH_API
fluid_server_t* new_fluid_server(fluid_settings_t* settings,
fluid_server_newclient_func_t func,
void* data);
FLUIDSYNTH_API void delete_fluid_server(fluid_server_t* server);
FLUIDSYNTH_API int fluid_server_join(fluid_server_t* server);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SHELL_H */
+700
View File
@@ -0,0 +1,700 @@
/* 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 _FLUIDSYNTH_SYNTH_H
#define _FLUIDSYNTH_SYNTH_H
#ifdef __cplusplus
extern "C" {
#endif
/** Embedded synthesizer
*
* You create a new synthesizer with new_fluid_synth() and you destroy
* if with delete_fluid_synth(). Use the settings structure to specify
* the synthesizer characteristics.
*
* You have to load a SoundFont in order to hear any sound. For that
* you use the fluid_synth_sfload() function.
*
* You can use the audio driver functions described below to open
* the audio device and create a background audio thread.
*
* The API for sending MIDI events is probably what you expect:
* fluid_synth_noteon(), fluid_synth_noteoff(), ...
*
*/
/** Creates a new synthesizer object.
*
* Creates a new synthesizer object. As soon as the synthesizer is
* created, it will start playing.
*
* \param settings a pointer to a settings structure
* \return a newly allocated synthesizer or NULL in case of error
*/
FLUIDSYNTH_API fluid_synth_t* new_fluid_synth(fluid_settings_t* settings);
/**
* Deletes the synthesizer previously created with new_fluid_synth.
*
* \param synth the synthesizer object
* \return 0 if no error occured, -1 otherwise
*/
FLUIDSYNTH_API int delete_fluid_synth(fluid_synth_t* synth);
/** Get a reference to the settings of the synthesizer.
*
* \param synth the synthesizer object
* \return pointer to the settings
*/
FLUIDSYNTH_API fluid_settings_t* fluid_synth_get_settings(fluid_synth_t* synth);
/*
*
* MIDI channel messages
*
*/
/** Send a noteon message. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel);
/** Send a noteoff message. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key);
/** Send a control change message. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t* synth, int chan, int ctrl, int val);
/** Get a control value. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t* synth, int chan, int ctrl, int* pval);
/** Send a pitch bend message. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val);
/** Get the pitch bend value. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API
int fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend);
/** Set the pitch wheel sensitivity. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val);
/** Get the pitch wheel sensitivity. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
/** Send a program change message. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
/** Select a bank. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API
int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
/** Select a sfont. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API
int fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id);
/** Select a preset for a channel. The preset is specified by the
SoundFont ID, the bank number, and the preset number. This
allows any preset to be selected and circumvents preset masking
due to previously loaded SoundFonts on the SoundFont stack.
\param synth The synthesizer
\param chan The channel on which to set the preset
\param sfont_id The ID of the SoundFont
\param bank_num The bank number
\param preset_num The preset number
\return 0 if no errors occured, -1 otherwise
*/
FLUIDSYNTH_API
int fluid_synth_program_select(fluid_synth_t* synth, int chan,
unsigned int sfont_id,
unsigned int bank_num,
unsigned int preset_num);
/** Returns the program, bank, and SoundFont number of the preset on
a given channel. Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API
int fluid_synth_get_program(fluid_synth_t* synth, int chan,
unsigned int* sfont_id,
unsigned int* bank_num,
unsigned int* preset_num);
/** Send a bank select and a program change to every channel to
* reinitialize the preset of the channel. This function is useful
* mainly after a SoundFont has been loaded, unloaded or
* reloaded. . Returns 0 if no error occurred, -1 otherwise. */
FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
/** Send a reset. A reset turns all the notes off and resets the
controller values. */
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
/*
*
* Low level access
*
*/
/** Create and start voices using a preset. The id passed as
* argument will be used as the voice group id. */
FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t* synth, unsigned int id,
fluid_preset_t* preset, int audio_chan,
int midi_chan, int key, int vel);
/** Stop the voices in the voice group defined by id. */
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t* synth, unsigned int id);
/** Change the value of a generator of the voices in the voice group
* defined by id. */
/* FLUIDSYNTH_API int fluid_synth_ctrl(fluid_synth_t* synth, int id, */
/* int gen, float value, */
/* int absolute, int normalized); */
/*
*
* SoundFont management
*
*/
/** Loads a SoundFont file and creates a new SoundFont. The newly
loaded SoundFont will be put on top of the SoundFont
stack. Presets are searched starting from the SoundFont on the
top of the stack, working the way down the stack until a preset
is found.
\param synth The synthesizer object
\param filename The file name
\param reset_presets If non-zero, the presets on the channels will be reset
\returns The ID of the loaded SoundFont, or -1 in case of error
*/
FLUIDSYNTH_API
int fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets);
/** Reload a SoundFont. The reloaded SoundFont retains its ID and
index on the stack.
\param synth The synthesizer object
\param id The id of the SoundFont
\returns The ID of the loaded SoundFont, or -1 in case of error
*/
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
/** Removes a SoundFont from the stack and deallocates it.
\param synth The synthesizer object
\param id The id of the SoundFont
\param reset_presets If TRUE then presets will be reset for all channels
\returns 0 if no error, -1 otherwise
*/
FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets);
/** Add a SoundFont. The SoundFont will be put on top of
the SoundFont stack.
\param synth The synthesizer object
\param sfont The SoundFont
\returns The ID of the loaded SoundFont, or -1 in case of error
*/
FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
/** Remove a SoundFont that was previously added using
* fluid_synth_add_sfont(). The synthesizer does not delete the
* SoundFont; this is responsability of the caller.
\param synth The synthesizer object
\param sfont The SoundFont
*/
FLUIDSYNTH_API void fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
/** Count the number of loaded SoundFonts.
\param synth The synthesizer object
\returns The number of loaded SoundFonts
*/
FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t* synth);
/** Get a SoundFont. The SoundFont is specified by its index on the
stack. The top of the stack has index zero.
\param synth The synthesizer object
\param num The number of the SoundFont (0 <= num < sfcount)
\returns A pointer to the SoundFont
*/
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num);
/** Get a SoundFont. The SoundFont is specified by its ID.
\param synth The synthesizer object
\param id The id of the sfont
\returns A pointer to the SoundFont
*/
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id);
/** Get the preset of a channel */
FLUIDSYNTH_API fluid_preset_t* fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan);
/** Offset the bank numbers in a SoundFont. Returns -1 if an error
* occured (out of memory or negative offset) */
FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset);
/** Get the offset of the bank numbers in a SoundFont. */
FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id);
/*
*
* Reverb
*
*/
/** Set the parameters for the built-in reverb unit */
FLUIDSYNTH_API void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize,
double damping, double width, double level);
/** Turn on (1) / off (0) the built-in reverb unit */
FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t* synth, int on);
/** Query the current state of the reverb. */
FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t* synth);
FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t* synth);
FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t* synth);
FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t* synth);
/* Those are the default settings for the reverb */
#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f
#define FLUID_REVERB_DEFAULT_DAMP 0.0f
#define FLUID_REVERB_DEFAULT_WIDTH 0.5f
#define FLUID_REVERB_DEFAULT_LEVEL 0.9f
/*
*
* Chorus
*
*/
enum fluid_chorus_mod {
FLUID_CHORUS_MOD_SINE = 0,
FLUID_CHORUS_MOD_TRIANGLE = 1
};
/** Set up the chorus. It should be turned on with fluid_synth_set_chorus_on.
* If faulty parameters are given, all new settings are discarded.
* Keep in mind, that the needed CPU time is proportional to 'nr'.
*/
FLUIDSYNTH_API void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
double speed, double depth_ms, int type);
/** Turn on (1) / off (0) the built-in chorus unit */
FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t* synth, int on);
/** Query the current state of the chorus. */
FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t* synth);
FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t* synth);
FLUIDSYNTH_API double fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth);
FLUIDSYNTH_API double fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t* synth); /* see fluid_chorus_mod */
/* Those are the default settings for the chorus. */
#define FLUID_CHORUS_DEFAULT_N 3
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f
#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
/*
*
* Audio and MIDI channels
*
*/
/** Returns the number of MIDI channels that the synthesizer uses
internally */
FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t* synth);
/** Returns the number of audio channels that the synthesizer uses
internally */
FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t* synth);
/** Returns the number of audio groups that the synthesizer uses
internally. This is usually identical to audio_channels. */
FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t* synth);
/** Returns the number of effects channels that the synthesizer uses
internally */
FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t* synth);
/*
*
* Synthesis parameters
*
*/
/** Set the master gain */
FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t* synth, float gain);
/** Get the master gain */
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t* synth);
/** Set the polyphony limit (FluidSynth >= 1.0.6) */
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony);
/** Get the polyphony limit (FluidSynth >= 1.0.6) */
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t* synth);
/** Get the internal buffer size. The internal buffer size if not the
same thing as the buffer size specified in the
settings. Internally, the synth *always* uses a specific buffer
size independent of the buffer size used by the audio driver. The
internal buffer size is normally 64 samples. The reason why it
uses an internal buffer size is to allow audio drivers to call the
synthesizer with a variable buffer length. The internal buffer
size is useful for client who want to optimize their buffer sizes.
*/
FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t* synth);
/** Set the interpolation method for one channel or all channels (chan = -1) */
FLUIDSYNTH_API
int fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method);
/* Flags to choose the interpolation method */
enum fluid_interp {
/* no interpolation: Fastest, but questionable audio quality */
FLUID_INTERP_NONE = 0,
/* Straight-line interpolation: A bit slower, reasonable audio quality */
FLUID_INTERP_LINEAR = 1,
/* Fourth-order interpolation: Requires 50 % of the whole DSP processing time, good quality
* Default. */
FLUID_INTERP_DEFAULT = 4,
FLUID_INTERP_4THORDER = 4,
FLUID_INTERP_7THORDER = 7,
FLUID_INTERP_HIGHEST=7
};
/*
*
* Generator interface
*
*/
/** Change the value of a generator. This function allows to control
all synthesis parameters in real-time. The changes are additive,
i.e. they add up to the existing parameter value. This function is
similar to sending an NRPN message to the synthesizer. The
function accepts a float as the value of the parameter. The
parameter numbers and ranges are described in the SoundFont 2.01
specification, paragraph 8.1.3, page 48. See also 'fluid_gen_type'.
\param synth The synthesizer object.
\param chan The MIDI channel number.
\param param The parameter number.
\param value The parameter value.
\returns Your favorite dish.
*/
FLUIDSYNTH_API
int fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value);
/** Retreive the value of a generator. This function returns the value
set by a previous call 'fluid_synth_set_gen' or by an NRPN message.
\param synth The synthesizer object.
\param chan The MIDI channel number.
\param param The generator number.
\returns The value of the generator.
*/
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
/*
*
* Tuning
*
*/
/** Create a new key-based tuning with given name, number, and
pitches. The array 'pitches' should have length 128 and contains
the pitch in cents of every key in cents. However, if 'pitches' is
NULL, a new tuning is created with the well-tempered scale.
\param synth The synthesizer object
\param tuning_bank The tuning bank number [0-127]
\param tuning_prog The tuning program number [0-127]
\param name The name of the tuning
\param pitch The array of pitch values. The array length has to be 128.
*/
FLUIDSYNTH_API
int fluid_synth_create_key_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
char* name, double* pitch);
/** Create a new octave-based tuning with given name, number, and
pitches. The array 'pitches' should have length 12 and contains
derivation in cents from the well-tempered scale. For example, if
pitches[0] equals -33, then the C-keys will be tuned 33 cents
below the well-tempered C.
\param synth The synthesizer object
\param tuning_bank The tuning bank number [0-127]
\param tuning_prog The tuning program number [0-127]
\param name The name of the tuning
\param pitch The array of pitch derivations. The array length has to be 12.
*/
FLUIDSYNTH_API
int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
char* name, double* pitch);
/** Request a note tuning changes. Both they 'keys' and 'pitches'
arrays should be of length 'num_pitches'. If 'apply' is non-zero,
the changes should be applied in real-time, i.e. sounding notes
will have their pitch updated. 'APPLY' IS CURRENTLY IGNORED. The
changes will be available for newly triggered notes only.
\param synth The synthesizer object
\param tuning_bank The tuning bank number [0-127]
\param tuning_prog The tuning program number [0-127]
\param len The length of the keys and pitch arrays
\param keys The array of keys values.
\param pitch The array of pitch values.
\param apply Flag to indicate whether to changes should be applied in real-time.
*/
FLUIDSYNTH_API
int fluid_synth_tune_notes(fluid_synth_t* synth, int tuning_bank, int tuning_prog,
int len, int *keys, double* pitch, int apply);
/** Select a tuning for a channel.
\param synth The synthesizer object
\param chan The channel number [0-max channels]
\param tuning_bank The tuning bank number [0-127]
\param tuning_prog The tuning program number [0-127]
*/
FLUIDSYNTH_API
int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int tuning_bank, int tuning_prog);
/** Set the tuning to the default well-tempered tuning on a channel.
\param synth The synthesizer object
\param chan The channel number [0-max channels]
*/
FLUIDSYNTH_API int fluid_synth_reset_tuning(fluid_synth_t* synth, int chan);
/** Start the iteration throught the list of available tunings.
\param synth The synthesizer object
*/
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t* synth);
/** Get the next tuning in the iteration. This functions stores the
bank and program number of the next tuning in the pointers given as
arguments.
\param synth The synthesizer object
\param bank Pointer to an int to store the bank number
\param prog Pointer to an int to store the program number
\returns 1 if there is a next tuning, 0 otherwise
*/
FLUIDSYNTH_API
int fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog);
/** Dump the data of a tuning. This functions stores the name and
pitch values of a tuning in the pointers given as arguments. Both
name and pitch can be NULL is the data is not needed.
\param synth The synthesizer object
\param bank The tuning bank number [0-127]
\param prog The tuning program number [0-127]
\param name Pointer to a buffer to store the name
\param len The length of the name buffer
\param pitch Pointer to buffer to store the pitch values
*/
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
char* name, int len, double* pitch);
/*
*
* Misc
*
*/
/** Get an estimation of the CPU load due to the audio synthesis.
Returns a percentage (0-100).
\param synth The synthesizer object
*/
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t* synth);
/** Get a textual representation of the last error */
FLUIDSYNTH_API char* fluid_synth_error(fluid_synth_t* synth);
/*
*
* Synthesizer plugin
*
*
* To create a synthesizer plugin, create the synthesizer as
* explained above. Once the synthesizer is created you can call
* any of the functions below to get the audio.
*
*/
/** Generate a number of samples. This function expects two signed
* 16bits buffers (left and right channel) that will be filled with
* samples.
*
* \param synth The synthesizer
* \param len The number of samples to generate
* \param lout The sample buffer for the left channel
* \param loff The offset, in samples, in the left buffer where the writing pointer starts
* \param lincr The increment, in samples, of the writing pointer in the left buffer
* \param rout The sample buffer for the right channel
* \param roff The offset, in samples, in the right buffer where the writing pointer starts
* \param rincr The increment, in samples, of the writing pointer in the right buffer
* \returns 0 if no error occured, non-zero otherwise
*/
FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t* synth, int len,
void* lout, int loff, int lincr,
void* rout, int roff, int rincr);
/** Generate a number of samples. This function expects two floating
* point buffers (left and right channel) that will be filled with
* samples.
*
* \param synth The synthesizer
* \param len The number of samples to generate
* \param lout The sample buffer for the left channel
* \param loff The offset, in samples, in the left buffer where the writing pointer starts
* \param lincr The increment, in samples, of the writing pointer in the left buffer
* \param rout The sample buffer for the right channel
* \param roff The offset, in samples, in the right buffer where the writing pointer starts
* \param rincr The increment, in samples, of the writing pointer in the right buffer
* \returns 0 if no error occured, non-zero otherwise
*/
FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t* synth, int len,
void* lout, int loff, int lincr,
void* rout, int roff, int rincr);
FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
float** left, float** right,
float** fx_left, float** fx_right);
/** Generate a number of samples. This function implements the
* default interface defined in fluidsynth/audio.h. This function
* ignores the input buffers and expects at least two output
* buffer.
*
* \param synth The synthesizer
* \param len The number of samples to generate
* \param nin The number of input buffers
* \param in The array of input buffers
* \param nout The number of output buffers
* \param out The array of output buffers
* \returns 0 if no error occured, non-zero otherwise
*/
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t* synth, int len,
int nin, float** in,
int nout, float** out);
/* Type definition of the synthesizer's audio callback function. */
typedef int (*fluid_audio_callback_t)(fluid_synth_t* synth, int len,
void* out1, int loff, int lincr,
void* out2, int roff, int rincr);
/*
* Synthesizer's interface to handle SoundFont loaders
*/
/** Add a SoundFont loader to the synthesizer. Note that SoundFont
loader don't necessarily load SoundFonts. They can load any type
of wavetable data but export a SoundFont interface. */
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader);
/** Allocate a synthesis voice. This function is called by a
soundfont's preset in response to a noteon event.
The returned voice comes with default modulators installed (velocity-to-attenuation,
velocity to filter, ...)
Note: A single noteon event may create any number of voices, when the preset is layered.
Typically 1 (mono) or 2 (stereo).*/
FLUIDSYNTH_API fluid_voice_t* fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample,
int channum, int key, int vel);
/** Start a synthesis voice. This function is called by a
soundfont's preset in response to a noteon event after the voice
has been allocated with fluid_synth_alloc_voice() and
initialized.
Exclusive classes are processed here.*/
FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice);
/** Write a list of all voices matching ID into buf, but not more than bufsize voices.
* If ID <0, return all voices. */
FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t* synth,
fluid_voice_t* buf[], int bufsize, int ID);
/** Callback function for the MIDI router. Any event goes through this. */
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event);
/** This is a hack to get command handlers working */
FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
fluid_midi_router_t* router);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SYNTH_H */
@@ -0,0 +1,66 @@
/* 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 _FLUIDSYNTH_TYPES_H
#define _FLUIDSYNTH_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
/*
Forward declarations
*/
typedef struct _fluid_hashtable_t fluid_settings_t;
typedef struct _fluid_synth_t fluid_synth_t;
typedef struct _fluid_voice_t fluid_voice_t;
typedef struct _fluid_sfloader_t fluid_sfloader_t;
typedef struct _fluid_sfont_t fluid_sfont_t;
typedef struct _fluid_preset_t fluid_preset_t;
typedef struct _fluid_sample_t fluid_sample_t;
typedef struct _fluid_mod_t fluid_mod_t;
typedef struct _fluid_audio_driver_t fluid_audio_driver_t;
typedef struct _fluid_player_t fluid_player_t;
typedef struct _fluid_midi_event_t fluid_midi_event_t;
typedef struct _fluid_midi_driver_t fluid_midi_driver_t;
typedef struct _fluid_midi_router_t fluid_midi_router_t;
typedef struct _fluid_midi_router_rule_t fluid_midi_router_rule_t;
typedef struct _fluid_hashtable_t fluid_cmd_handler_t;
typedef struct _fluid_shell_t fluid_shell_t;
typedef struct _fluid_server_t fluid_server_t;
typedef struct _fluid_event_t fluid_event_t;
typedef struct _fluid_sequencer_t fluid_sequencer_t;
typedef struct _fluid_ramsfont_t fluid_ramsfont_t;
typedef struct _fluid_rampreset_t fluid_rampreset_t;
typedef int fluid_istream_t;
typedef int fluid_ostream_t;
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_TYPES_H */
@@ -0,0 +1,44 @@
/* 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 _FLUIDSYNTH_VERSION_H
#define _FLUIDSYNTH_VERSION_H
#ifdef __cplusplus
extern "C" {
#endif
#define FLUIDSYNTH_VERSION "1.0.7"
#define FLUIDSYNTH_VERSION_MAJOR 1
#define FLUIDSYNTH_VERSION_MINOR 0
#define FLUIDSYNTH_VERSION_MICRO 7
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
FLUIDSYNTH_API char* fluid_version_str(void);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_VERSION_H */
@@ -0,0 +1,97 @@
/* 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 _FLUIDSYNTH_VOICE_H
#define _FLUIDSYNTH_VOICE_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* The interface to the synthesizer's voices
* Examples on using them can be found in fluid_defsfont.c
*/
/** Update all the synthesis parameters, which depend on generator gen.
This is only necessary after changing a generator of an already operating voice.
Most applications will not need this function.*/
FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t* voice, int gen);
/* for fluid_voice_add_mod */
enum fluid_voice_add_mod{
FLUID_VOICE_OVERWRITE,
FLUID_VOICE_ADD,
FLUID_VOICE_DEFAULT
};
/* Add a modulator to a voice (SF2.1 only). */
FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t* voice, fluid_mod_t* mod, int mode);
/** Set the value of a generator */
FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t* voice, int gen, float val);
/** Get the value of a generator */
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t* voice, int gen);
/** Modify the value of a generator by val */
FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t* voice, int gen, float val);
/** Return the unique ID of the noteon-event. A sound font loader
* may store the voice processes it has created for * real-time
* control during the operation of a voice (for example: parameter
* changes in sound font editor). The synth uses a pool of
* voices, which are 'recycled' and never deallocated.
*
* Before modifying an existing voice, check
* - that its state is still 'playing'
* - that the ID is still the same
* Otherwise the voice has finished playing.
*/
FLUIDSYNTH_API unsigned int fluid_voice_get_id(fluid_voice_t* voice);
FLUIDSYNTH_API int fluid_voice_is_playing(fluid_voice_t* voice);
/** If the peak volume during the loop is known, then the voice can
* be released earlier during the release phase. Otherwise, the
* voice will operate (inaudibly), until the envelope is at the
* nominal turnoff point. In many cases the loop volume is many dB
* below the maximum volume. For example, the loop volume for a
* typical acoustic piano is 20 dB below max. Taking that into
* account in the turn-off algorithm we can save 20 dB / 100 dB =>
* 1/5 of the total release time.
* So it's a good idea to call fluid_voice_optimize_sample
* on each sample once.
*/
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t* s);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_VOICE_H */
+1
View File
@@ -1,6 +1,7 @@
SubDir HAIKU_TOP src libs ;
SubInclude HAIKU_TOP src libs agg ;
SubInclude HAIKU_TOP src libs fluidsynth ;
SubInclude HAIKU_TOP src libs freetype2 ;
SubInclude HAIKU_TOP src libs zlib ;
SubInclude HAIKU_TOP src libs png ;
+117
View File
@@ -0,0 +1,117 @@
[:Idea:]
* Samuel Bianchini, Peter Hanappe and Johnathan Lee
[:Development:]
Many people contributed to FluidSynth, send 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.
* Peter Hanappe. Initiated the project. files: sticked his nose in all
files.
* Josh Green is the current maintainer and contributed a lot of code
directly or indirectly through the Swami and Smurf code base.
The SoundFont loader is completely based on his code. He also wrote
the alsa sequencer driver. He made many changes and bug fixes,
but above all, he's one of the driver forces behind the synthesizer.
He also created the current FluidSynth graphic logo with Blender
(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
importantly, he used it on stage to make music. files:
iiwu_ladspa.{c,h}, iiwu_cmd.{c,h}, iiwu_voice.{c,h}, iiwu_synth.c,
iiwu_sse.h, iiwu_dsp_core.h, iiwu_rev.{c,h}, and basically all the
other files.
* 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
to Antoine, the synthesizer finds its way to multi-media
developers. files: in bindings/director/ and iiwu_seq.{c,h},
iiwu_event.{c,h}, iiwu_event_priv.h, iiwu_seqbind.{c,h},
iiwu_ramsfont.{c,h}
* Bob Ham added the code for "bank select" MIDI messages and send code
to define the synth's ALSA sequencer client name. files:
iiwu_midi.c, iiwu_alsa.c, iiwusynth.c, iiwusynth.h.
* Tim Goetze sent many patches and implemented the all_notes_off. He
also sent his code for the new ALSA driver. files: iiwu_synth.c,
iiwu_chan.c, iiwu_voice.c, iiwu_alsa.c
* Norbert Schnell from Ircam's jMax Team wrote most of the jMax/FTS
interface in a record time. He also pointed me to the technique of
using a lookup table for the interpolation coefficients. file:
iiwu_fts.c, iiwu_synth.c
* The initial alsa driver was based on the jMax alsa driver by
Francois Dechelle and his Real-time Team at Ircam
(http://www.ircam.fr/jmax). The jMax code was based upon Ardour's
alsa_device.cc by Paul Barton-Davis. file: iiwu_alsa.c
* Code was borrowed from the glib library to the smurf files. The goal was
to make iiwusynth independent from any library for maximum
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
* The reverb algorithm was written by Jezar
(http://www.dreampoint.co.uk). His code is public domain. The code
was translated to C by Peter Hanappe. file: iiwu_synth.c
* The original code for the chorus effect was written by Juergen
Mueller and sundry contributors.
* Bob Ham added LADCCA support.
* Ebrahim Mayat made big efforts for compiling and running FluidSynth
on MacOS X. He also wrote the README-OSX file.
* Martin Uddén's midi package was used. His files are integrated into
the iiwu_midi file. Martin Uddén <[email protected]> file:
iiwu_midi.c
* Ken Ellinwood send in a patch to add bank offsets to SoundFonts. An
adapted version was integrated in the source code. files:
fluid_cmd.c, fluidsynth/synth.h, fluid_synth.c.
* Some interpolation algorihms were used that were found in
the music-dsp archives (http://www.smartelectronix.com/musicdsp).
They were written by Joshua Scholar and others. file: iiwu_synth.c
* Macros to {increment,decrement} the 64-bit fixed point phase were
borrowed from Mozilla's macros to handle the Long-long type (64-bit
signed integer type). Mozilla NSPR library, www.mozilla.org. file:
iiwu_phase.h
* Growing list of individuals who contributed bug fixes and corrections:
Werner Schweer
Dave Philips
Anthony Green
Jake Commander
Fernando Pablo Lopez-Lezcano
Raoul Bonisch
Sergey Pavlishin
Eric Van Buggenhaut
Ken Ellinwood
Takashi Iwai
Bob Ham
Gerald Pye
Rui Nuno Capela
Frieder Bürzele
Henri Manson
+482
View File
@@ -0,0 +1,482 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+3
View File
@@ -0,0 +1,3 @@
SubDir HAIKU_TOP src libs fluidsynth ;
SubInclude HAIKU_TOP src libs fluidsynth src ;
+40
View File
@@ -0,0 +1,40 @@
SubDir HAIKU_TOP src libs fluidsynth src ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UseLibraryHeaders fluidsynth ;
SubDirCcFlags -DHAVE_CONFIG_H ;
SharedLibrary libfluidsynth.so :
fluid_adriver.c
fluid_aufile.c
fluid_chan.c
fluid_chorus.c
fluid_cmd.c
fluid_conv.c
fluid_defsfont.c
fluid_event.c
fluid_gen.c
fluid_hash.c
fluid_io.c
fluid_list.c
fluid_mdriver.c
fluid_midi.c
fluid_midi_router.c
fluid_mod.c
fluid_ramsfont.c
fluid_rev.c
fluid_seq.c
fluid_seqbind.c
fluid_settings.c
fluid_strtok.c
fluid_synth.c
fluid_sys.c
fluid_tuning.c
fluid_voice.c
;
# // for testing purpose
#StdBinCommands fluidsynth.c : libfluidsynth.so ;
+191
View File
@@ -0,0 +1,191 @@
/* src/config.h. Generated by configure. */
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Define to enable ALSA driver */
/* #undef ALSA_SUPPORT */
/* whether or not we are supporting CoreAudio */
/* #undef COREAUDIO_SUPPORT */
/* Define if building for Mac OS X Darwin */
/* #undef DARWIN */
/* Define to activate debugging message */
#define DEBUG 0
/* Use the SSE instructions of Pentium3+ (not recommended) */
/* #undef ENABLE_SSE */
/* Define to 1 if you have the <arpa/inet.h> header file. */
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
#define HAVE_ARPA_INET_H 1
#endif
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* whether or not we are supporting ladcca */
/* #undef HAVE_LADCCA */
/* whether or not we are supporting lash */
/* #undef HAVE_LASH */
/* Define to 1 if you have the `dl' library (-ldl). */
/* #undef HAVE_LIBDL */
/* Define to 1 if you have the `MidiShare' library (-lMidiShare). */
/* #undef HAVE_LIBMIDISHARE */
/* Define to 1 if you have the `pthread' library (-lpthread). */
/* #undef HAVE_LIBPTHREAD */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <machine/soundcard.h> header file. */
/* #undef HAVE_MACHINE_SOUNDCARD_H */
/* Define to 1 if you have the <math.h> header file. */
#define HAVE_MATH_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <MidiShare.h> header file. */
/* #undef HAVE_MIDISHARE_H */
/* Define to 1 if you have the <netinet/in.h> header file. */
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
#define HAVE_NETINET_IN_H 1
/* Define to 1 if you have the <netinet/tcp.h> header file. */
#define HAVE_NETINET_TCP_H 1
/* Define to 1 if you have the <pthread.h> header file. */
#define HAVE_PTHREAD_H 1
#endif
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/mman.h> header file. */
/* #undef HAVE_SYS_MMAN_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
#define HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/soundcard.h> header file. */
/* #undef HAVE_SYS_SOUNDCARD_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */
/* Define to enable JACK driver */
/* #undef JACK_SUPPORT */
/* Include the LADSPA Fx unit */
/* #undef LADSPA */
/* Define to enable MidiShare driver */
/* #undef MIDISHARE_SUPPORT */
/* Define if using the MinGW32 environment */
/* #undef MINGW32 */
/* Define to enable OSS driver */
/* #undef OSS_SUPPORT */
/* Name of package */
#define PACKAGE "fluidsynth"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to use long long type, where appropriate */
/* #undef USE_LONGLONG */
/* Version number of package */
#define VERSION "1.0.7"
/* Define to do all DSP in single floating point precision */
#define WITH_FLOAT 1
/* Define to profile the DSP code */
/* #undef WITH_PROFILING */
/* Define to use the readline library for line editing */
/* #undef WITH_READLINE */
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
/* #undef WORDS_BIGENDIAN */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Additional config for us */
#ifdef __BEOS__
#define WITHOUT_SERVER 1
#endif
+308
View File
@@ -0,0 +1,308 @@
/* 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_adriver.h"
#include "fluid_settings.h"
/*
* fluid_adriver_definition_t
*/
typedef struct _fluid_audriver_definition_t
{
char* name;
fluid_audio_driver_t* (*new)(fluid_settings_t* settings, fluid_synth_t* synth);
fluid_audio_driver_t* (*new2)(fluid_settings_t* settings,
fluid_audio_func_t func,
void* data);
int (*free)(fluid_audio_driver_t* driver);
void (*settings)(fluid_settings_t* settings);
} fluid_audriver_definition_t;
#if ALSA_SUPPORT
fluid_audio_driver_t* new_fluid_alsa_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
fluid_audio_driver_t* new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
fluid_audio_func_t func, void* data);
int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p);
void fluid_alsa_audio_driver_settings(fluid_settings_t* settings);
#endif
#if OSS_SUPPORT
fluid_audio_driver_t* new_fluid_oss_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
fluid_audio_driver_t* new_fluid_oss_audio_driver2(fluid_settings_t* settings,
fluid_audio_func_t func, void* data);
int delete_fluid_oss_audio_driver(fluid_audio_driver_t* p);
void fluid_oss_audio_driver_settings(fluid_settings_t* settings);
#endif
#if COREAUDIO_SUPPORT
fluid_audio_driver_t* new_fluid_core_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
fluid_audio_driver_t* new_fluid_core_audio_driver2(fluid_settings_t* settings,
fluid_audio_func_t func,
void* data);
int delete_fluid_core_audio_driver(fluid_audio_driver_t* p);
void fluid_core_audio_driver_settings(fluid_settings_t* settings);
#endif
#if DSOUND_SUPPORT
fluid_audio_driver_t* new_fluid_dsound_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
int delete_fluid_dsound_audio_driver(fluid_audio_driver_t* p);
void fluid_dsound_audio_driver_settings(fluid_settings_t* settings);
#endif
#if PORTAUDIO_SUPPORT
fluid_audio_driver_t* new_fluid_portaudio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
int delete_fluid_portaudio_driver(fluid_audio_driver_t* p);
#endif
#if JACK_SUPPORT
fluid_audio_driver_t* new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth);
fluid_audio_driver_t* new_fluid_jack_audio_driver2(fluid_settings_t* settings,
fluid_audio_func_t func, void* data);
int delete_fluid_jack_audio_driver(fluid_audio_driver_t* p);
void fluid_jack_audio_driver_settings(fluid_settings_t* settings);
#endif
#if SNDMAN_SUPPORT
fluid_audio_driver_t* new_fluid_sndmgr_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
fluid_audio_driver_t* new_fluid_sndmgr_audio_driver2(fluid_settings_t* settings,
fluid_audio_func_t func,
void* data);
int delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t* p);
#endif
#define AUFILE_SUPPORT 1
#if AUFILE_SUPPORT
fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p);
void fluid_file_audio_driver_settings(fluid_settings_t* settings);
#endif
fluid_audriver_definition_t fluid_audio_drivers[] = {
#if OSS_SUPPORT
{ "oss",
new_fluid_oss_audio_driver,
new_fluid_oss_audio_driver2,
delete_fluid_oss_audio_driver,
fluid_oss_audio_driver_settings },
#endif
#if ALSA_SUPPORT
{ "alsa",
new_fluid_alsa_audio_driver,
new_fluid_alsa_audio_driver2,
delete_fluid_alsa_audio_driver,
fluid_alsa_audio_driver_settings },
#endif
#if COREAUDIO_SUPPORT
{ "coreaudio",
new_fluid_core_audio_driver,
new_fluid_core_audio_driver2,
delete_fluid_core_audio_driver,
fluid_core_audio_driver_settings },
#endif
#if DSOUND_SUPPORT
{ "dsound",
new_fluid_dsound_audio_driver,
NULL,
delete_fluid_dsound_audio_driver,
fluid_dsound_audio_driver_settings },
#endif
#if PORTAUDIO_SUPPORT
{ "portaudio",
new_fluid_portaudio_driver,
NULL,
delete_fluid_portaudio_driver,
NULL },
#endif
#if SNDMAN_SUPPORT
{ "sndman",
new_fluid_sndmgr_audio_driver,
new_fluid_sndmgr_audio_driver2,
delete_fluid_sndmgr_audio_driver,
NULL },
#endif
#if JACK_SUPPORT
{ "jack",
new_fluid_jack_audio_driver,
new_fluid_jack_audio_driver2,
delete_fluid_jack_audio_driver,
fluid_jack_audio_driver_settings },
#endif
#if AUFILE_SUPPORT
{ "file",
new_fluid_file_audio_driver,
NULL,
delete_fluid_file_audio_driver,
fluid_file_audio_driver_settings },
#endif
{ NULL, NULL, NULL, NULL, NULL }
};
void fluid_audio_driver_settings(fluid_settings_t* settings)
{
int i;
fluid_settings_register_str(settings, "audio.sample-format", "16bits", 0, NULL, NULL);
fluid_settings_add_option(settings, "audio.sample-format", "16bits");
fluid_settings_add_option(settings, "audio.sample-format", "float");
fluid_settings_register_int(settings, "audio.output-channels", 2, 2, 32, 0, NULL, NULL);
fluid_settings_register_int(settings, "audio.input-channels", 0, 0, 2, 0, NULL, NULL);
#if defined(WIN32)
fluid_settings_register_int(settings, "audio.period-size", 512, 64, 8192, 0, NULL, NULL);
fluid_settings_register_int(settings, "audio.periods", 8, 2, 64, 0, NULL, NULL);
#elif defined(MACOS9)
fluid_settings_register_int(settings, "audio.period-size", 64, 64, 8192, 0, NULL, NULL);
fluid_settings_register_int(settings, "audio.periods", 8, 2, 64, 0, NULL, NULL);
#else
fluid_settings_register_int(settings, "audio.period-size", 64, 64, 8192, 0, NULL, NULL);
fluid_settings_register_int(settings, "audio.periods", 16, 2, 64, 0, NULL, NULL);
#endif
/* Set the default driver */
#if ALSA_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "alsa", 0, NULL, NULL);
#elif OSS_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "oss", 0, NULL, NULL);
#elif COREAUDIO_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "coreaudio", 0, NULL, NULL);
#elif DSOUND_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "dsound", 0, NULL, NULL);
#elif SNDMAN_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "sndman", 0, NULL, NULL);
#elif PORTAUDIO_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "portaudio", 0, NULL, NULL);
#elif JACK_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "jack", 0, NULL, NULL);
#elif AUFILE_SUPPORT
fluid_settings_register_str(settings, "audio.driver", "file", 0, NULL, NULL);
#else
fluid_settings_register_str(settings, "audio.driver", "", 0, NULL, NULL);
#endif
/* Add all drivers to the list of options */
#if ALSA_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "alsa");
#endif
#if OSS_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "oss");
#endif
#if COREAUDIO_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "coreaudio");
#endif
#if DSOUND_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "dsound");
#endif
#if SNDMAN_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "sndman");
#endif
#if PORTAUDIO_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "portaudio");
#endif
#if JACK_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "jack");
#endif
#if AUFILE_SUPPORT
fluid_settings_add_option(settings, "audio.driver", "file");
#endif
for (i = 0; fluid_audio_drivers[i].name != NULL; i++) {
if (fluid_audio_drivers[i].settings != NULL) {
fluid_audio_drivers[i].settings(settings);
}
}
}
fluid_audio_driver_t*
new_fluid_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
{
int i;
fluid_audio_driver_t* driver = NULL;
char* name;
fluid_settings_getstr(settings, "audio.driver", &name);
for (i = 0; fluid_audio_drivers[i].name != NULL; i++) {
if (fluid_settings_str_equal(settings, "audio.driver", fluid_audio_drivers[i].name)) {
FLUID_LOG(FLUID_DBG, "Using '%s' audio driver", fluid_audio_drivers[i].name);
driver = (*fluid_audio_drivers[i].new)(settings, synth);
if (driver) {
driver->name = fluid_audio_drivers[i].name;
}
return driver;
}
}
FLUID_LOG(FLUID_ERR, "Couldn't find the requested audio driver: %s", name);
return NULL;
}
fluid_audio_driver_t*
new_fluid_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data)
{
int i;
fluid_audio_driver_t* driver = NULL;
char* name;
fluid_settings_getstr(settings, "audio.driver", &name);
for (i = 0; fluid_audio_drivers[i].name != NULL; i++) {
if (fluid_settings_str_equal(settings, "audio.driver", fluid_audio_drivers[i].name) &&
(fluid_audio_drivers[i].new2 != NULL)) {
FLUID_LOG(FLUID_DBG, "Using '%s' audio driver", fluid_audio_drivers[i].name);
driver = (*fluid_audio_drivers[i].new2)(settings, func, data);
if (driver) {
driver->name = fluid_audio_drivers[i].name;
}
return driver;
}
}
FLUID_LOG(FLUID_ERR, "Couldn't find the requested audio driver: %s", name);
return NULL;
}
void
delete_fluid_audio_driver(fluid_audio_driver_t* driver)
{
int i;
for (i = 0; fluid_audio_drivers[i].name != NULL; i++) {
if (fluid_audio_drivers[i].name == driver->name) {
fluid_audio_drivers[i].free(driver);
return;
}
}
}
+39
View File
@@ -0,0 +1,39 @@
/* 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_AUDRIVER_H
#define _FLUID_AUDRIVER_H
#include "fluidsynth_priv.h"
void fluid_audio_driver_settings(fluid_settings_t* settings);
/*
* fluid_audio_driver_t
*/
struct _fluid_audio_driver_t
{
char* name;
};
#endif /* _FLUID_AUDRIVER_H */
+204
View File
@@ -0,0 +1,204 @@
/* 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
*/
/* fluid_aufile.c
*
* Audio driver, outputs the audio to a file (non real-time)
*
*/
#include "fluid_adriver.h"
#include "fluid_settings.h"
#include "fluid_sys.h"
#include <stdio.h>
/** fluid_file_audio_driver_t
*
* This structure should not be accessed directly. Use audio port
* functions instead.
*/
typedef struct {
fluid_audio_driver_t driver;
fluid_audio_func_t callback;
void* data;
int period_size;
double sample_rate;
FILE* file;
fluid_timer_t* timer;
float* left;
float* right;
short* buf;
int buf_size;
unsigned int samples;
} fluid_file_audio_driver_t;
fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p);
void fluid_file_audio_driver_settings(fluid_settings_t* settings);
static int fluid_file_audio_run_s16(void* d, unsigned int msec);
/**************************************************************
*
* 'file' audio driver
*
*/
void fluid_file_audio_driver_settings(fluid_settings_t* settings)
{
fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.raw", 0, NULL, NULL);
}
fluid_audio_driver_t*
new_fluid_file_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth)
{
fluid_file_audio_driver_t* dev;
int err;
char* filename;
int msec;
dev = FLUID_NEW(fluid_file_audio_driver_t);
if (dev == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(dev, 0, sizeof(fluid_file_audio_driver_t));
fluid_settings_getint(settings, "audio.period-size", &dev->period_size);
fluid_settings_getnum(settings, "synth.sample-rate", &dev->sample_rate);
dev->data = synth;
dev->callback = (fluid_audio_func_t) fluid_synth_process;
dev->samples = 0;
dev->left = FLUID_ARRAY(float, dev->period_size);
dev->right = FLUID_ARRAY(float, dev->period_size);
dev->buf = FLUID_ARRAY(short, 2 * dev->period_size);
dev->buf_size = 2 * dev->period_size * sizeof(short);
if (fluid_settings_getstr(settings, "audio.file.name", &filename) == 0) {
FLUID_LOG(FLUID_ERR, "No file name specified");
goto error_recovery;
}
dev->file = fopen(filename, "wb");
if (dev->file == NULL) {
FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'", filename);
goto error_recovery;
}
msec = (int) (0.5 + dev->period_size / dev->sample_rate * 1000.0);
dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void*) dev, 1, 0);
if (dev->timer == NULL) {
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
goto error_recovery;
}
return (fluid_audio_driver_t*) dev;
error_recovery:
delete_fluid_file_audio_driver((fluid_audio_driver_t*) dev);
return NULL;
}
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p)
{
fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) p;
if (dev == NULL) {
return FLUID_OK;
}
if (dev->timer != NULL) {
delete_fluid_timer(dev->timer);
}
if (dev->file != NULL) {
fclose(dev->file);
}
if (dev->left != NULL) {
FLUID_FREE(dev->left);
}
if (dev->right != NULL) {
FLUID_FREE(dev->right);
}
if (dev->buf != NULL) {
FLUID_FREE(dev->buf);
}
FLUID_FREE(dev);
return FLUID_OK;
}
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;
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;
}
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");
return 0;
}
}
dev->samples += dev->period_size;
return 1;
error_recovery:
return 0;
}
+352
View File
@@ -0,0 +1,352 @@
/* 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_chan.h"
#include "fluid_mod.h"
#include "fluid_synth.h"
#include "fluid_sfont.h"
#define SETCC(_c,_n,_v) _c->cc[_n] = _v
/*
* new_fluid_channel
*/
fluid_channel_t*
new_fluid_channel(fluid_synth_t* synth, int num)
{
fluid_channel_t* chan;
chan = FLUID_NEW(fluid_channel_t);
if (chan == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
chan->synth = synth;
chan->channum = num;
fluid_channel_init(chan);
fluid_channel_init_ctrl(chan);
return chan;
}
void
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;
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;
}
void
fluid_channel_init_ctrl(fluid_channel_t* chan)
{
int i;
chan->key_pressure = 0;
chan->channel_pressure = 0;
chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
chan->bank_msb = 0;
for (i = 0; i < GEN_LAST; i++) {
chan->gen[i] = 0.0f;
chan->gen_abs[i] = 0;
}
for (i = 0; i < 128; i++) {
SETCC(chan, i, 0);
}
/* Volume / initial attenuation (MSB & LSB) */
SETCC(chan, 7, 127);
SETCC(chan, 39, 0);
/* Pan (MSB & LSB) */
SETCC(chan, 10, 64);
SETCC(chan, 10, 64);
/* Expression (MSB & LSB) */
SETCC(chan, 11, 127);
SETCC(chan, 43, 127);
}
void
fluid_channel_reset(fluid_channel_t* chan)
{
fluid_channel_init(chan);
fluid_channel_init_ctrl(chan);
}
/*
* delete_fluid_channel
*/
int
delete_fluid_channel(fluid_channel_t* chan)
{
FLUID_FREE(chan);
return FLUID_OK;
}
/*
* fluid_channel_set_preset
*/
int
fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
{
fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);
chan->preset = preset;
return FLUID_OK;
}
/*
* fluid_channel_get_preset
*/
fluid_preset_t*
fluid_channel_get_preset(fluid_channel_t* chan)
{
return chan->preset;
}
/*
* fluid_channel_get_banknum
*/
unsigned int
fluid_channel_get_banknum(fluid_channel_t* chan)
{
return chan->banknum;
}
/*
* fluid_channel_set_prognum
*/
int
fluid_channel_set_prognum(fluid_channel_t* chan, int prognum)
{
chan->prognum = prognum;
return FLUID_OK;
}
/*
* fluid_channel_get_prognum
*/
int
fluid_channel_get_prognum(fluid_channel_t* chan)
{
return chan->prognum;
}
/*
* fluid_channel_set_banknum
*/
int
fluid_channel_set_banknum(fluid_channel_t* chan, unsigned int banknum)
{
chan->banknum = banknum;
return FLUID_OK;
}
/*
* fluid_channel_cc
*/
int
fluid_channel_cc(fluid_channel_t* chan, int num, int value)
{
chan->cc[num] = value;
switch (num) {
case SUSTAIN_SWITCH:
{
if (value < 64) {
/* printf("** sustain off\n"); */
fluid_synth_damp_voices(chan->synth, chan->channum);
} else {
/* printf("** sustain on\n"); */
}
}
break;
case BANK_SELECT_MSB:
{
chan->bank_msb = (unsigned char) (value & 0x7f);
/* printf("** bank select msb recieved: %d\n", value); */
/* I fixed the handling of a MIDI bank select controller 0,
e.g., bank select MSB (or "coarse" bank select according to
my spec). Prior to this fix a channel's bank number was only
changed upon reception of MIDI bank select controller 32,
e.g, bank select LSB (or "fine" bank-select according to my
spec). [KLE]
FIXME: is this correct? [PH] */
fluid_channel_set_banknum(chan, (unsigned int)(value & 0x7f)); /* KLE */
}
break;
case BANK_SELECT_LSB:
{
/* FIXME: according to the Downloadable Sounds II specification,
bit 31 should be set when we receive the message on channel
10 (drum channel) */
fluid_channel_set_banknum(chan, (((unsigned int) value & 0x7f)
+ ((unsigned int) chan->bank_msb << 7)));
}
break;
case ALL_NOTES_OFF:
fluid_synth_all_notes_off(chan->synth, chan->channum);
break;
case ALL_SOUND_OFF:
fluid_synth_all_sounds_off(chan->synth, chan->channum);
break;
case ALL_CTRL_OFF:
fluid_channel_init_ctrl(chan);
fluid_synth_modulate_voices_all(chan->synth, chan->channum);
break;
case DATA_ENTRY_MSB:
{
int data = (value << 7) + chan->cc[DATA_ENTRY_LSB];
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
if ((chan->cc[NRPN_MSB] == 120) && (chan->cc[NRPN_LSB] < 100)) {
float val = fluid_gen_scale_nrpn(chan->nrpn_select, data);
FLUID_LOG(FLUID_WARN, "%s: %d: Data = %d, value = %f", __FILE__, __LINE__, data, val);
fluid_synth_set_gen(chan->synth, chan->channum, chan->nrpn_select, val);
}
break;
}
case NRPN_MSB:
chan->cc[NRPN_LSB] = 0;
chan->nrpn_select = 0;
break;
case NRPN_LSB:
/* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */
if (chan->cc[NRPN_MSB] == 120) {
if (value == 100) {
chan->nrpn_select += 100;
} else if (value == 101) {
chan->nrpn_select += 1000;
} else if (value == 102) {
chan->nrpn_select += 10000;
} else if (value < 100) {
chan->nrpn_select += value;
FLUID_LOG(FLUID_WARN, "%s: %d: NRPN Select = %d", __FILE__, __LINE__, chan->nrpn_select);
}
}
break;
case RPN_MSB:
break;
case RPN_LSB:
/* erase any previously received NRPN message */
chan->cc[NRPN_MSB] = 0;
chan->cc[NRPN_LSB] = 0;
chan->nrpn_select = 0;
break;
default:
fluid_synth_modulate_voices(chan->synth, chan->channum, 1, num);
}
return FLUID_OK;
}
/*
* fluid_channel_get_cc
*/
int
fluid_channel_get_cc(fluid_channel_t* chan, int num)
{
return ((num >= 0) && (num < 128))? chan->cc[num] : 0;
}
/*
* fluid_channel_pitch_bend
*/
int
fluid_channel_pitch_bend(fluid_channel_t* chan, int val)
{
chan->pitch_bend = val;
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_PITCHWHEEL);
return FLUID_OK;
}
/*
* fluid_channel_pitch_wheel_sens
*/
int
fluid_channel_pitch_wheel_sens(fluid_channel_t* chan, int val)
{
chan->pitch_wheel_sensitivity = val;
fluid_synth_modulate_voices(chan->synth, chan->channum, 0, FLUID_MOD_PITCHWHEELSENS);
return FLUID_OK;
}
/*
* fluid_channel_get_num
*/
int
fluid_channel_get_num(fluid_channel_t* chan)
{
return chan->channum;
}
/* Purpose:
* Sets the index of the interpolation method used on this channel,
* as in fluid_interp in fluidsynth.h
*/
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method)
{
chan->interp_method = new_method;
}
/* Purpose:
* Returns the index of the interpolation method used on this channel,
* as in fluid_interp in fluidsynth.h
*/
int fluid_channel_get_interp_method(fluid_channel_t* chan)
{
return chan->interp_method;
}
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan)
{
return chan->sfontnum;
}
int fluid_channel_set_sfontnum(fluid_channel_t* chan, unsigned int sfontnum)
{
chan->sfontnum = sfontnum;
return FLUID_OK;
}
+105
View File
@@ -0,0 +1,105 @@
/* 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_CHAN_H
#define _FLUID_CHAN_H
#include "fluidsynth_priv.h"
#include "fluid_midi.h"
#include "fluid_tuning.h"
/*
* fluid_channel_t
*/
struct _fluid_channel_t
{
int channum;
unsigned int sfontnum;
unsigned int banknum;
unsigned int prognum;
fluid_preset_t* preset;
fluid_synth_t* synth;
short key_pressure;
short channel_pressure;
short pitch_bend;
short pitch_wheel_sensitivity;
/* controller values */
short cc[128];
/* cached values of last MSB values of MSB/LSB controllers */
unsigned char bank_msb;
int interp_method;
/* the micro-tuning */
fluid_tuning_t* tuning;
/* NRPN system */
short nrpn_select;
/* The values of the generators, set by NRPN messages, or by
* fluid_synth_set_gen(), are cached in the channel so they can be
* applied to future notes. They are copied to a voice's generators
* in fluid_voice_init(), wihich calls fluid_gen_init(). */
fluid_real_t gen[GEN_LAST];
/* By default, the NRPN values are relative to the values of the
* generators set in the SoundFont. For example, if the NRPN
* specifies an attack of 100 msec then 100 msec will be added to the
* combined attack time of the sound font and the modulators.
*
* However, it is useful to be able to specify the generator value
* absolutely, completely ignoring the generators of the sound font
* and the values of modulators. The gen_abs field, is a boolean
* flag indicating whether the NRPN value is absolute or not.
*/
char gen_abs[GEN_LAST];
};
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
int delete_fluid_channel(fluid_channel_t* chan);
void fluid_channel_init(fluid_channel_t* chan);
void fluid_channel_init_ctrl(fluid_channel_t* chan);
void fluid_channel_reset(fluid_channel_t* chan);
int fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset);
fluid_preset_t* fluid_channel_get_preset(fluid_channel_t* chan);
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan);
int fluid_channel_set_sfontnum(fluid_channel_t* chan, unsigned int sfont);
unsigned int fluid_channel_get_banknum(fluid_channel_t* chan);
int fluid_channel_set_banknum(fluid_channel_t* chan, unsigned int bank);
int fluid_channel_set_prognum(fluid_channel_t* chan, int prognum);
int fluid_channel_get_prognum(fluid_channel_t* chan);
int fluid_channel_cc(fluid_channel_t* chan, int ctrl, int val);
int fluid_channel_pitch_bend(fluid_channel_t* chan, int val);
int fluid_channel_pitch_wheel_sens(fluid_channel_t* chan, int val);
int fluid_channel_get_cc(fluid_channel_t* chan, int num);
int fluid_channel_get_num(fluid_channel_t* chan);
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method);
int fluid_channel_get_interp_method(fluid_channel_t* chan);
#define fluid_channel_set_tuning(_c, _t) { (_c)->tuning = _t; }
#define fluid_channel_has_tuning(_c) ((_c)->tuning != NULL)
#define fluid_channel_get_tuning(_c) ((_c)->tuning)
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
#define fluid_channel_set_gen(_c, _n, _v, _a) { (_c)->gen[_n] = _v; (_c)->gen_abs[_n] = _a; }
#define fluid_channel_get_gen(_c, _n) ((_c)->gen[_n])
#define fluid_channel_get_gen_abs(_c, _n) ((_c)->gen_abs[_n])
#endif /* _FLUID_CHAN_H */
+605
View File
@@ -0,0 +1,605 @@
/*
* August 24, 1998
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Juergen Mueller And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
CHANGES
- Adapted for fluidsynth, Peter Hanappe, March 2002
- Variable delay line implementation using bandlimited
interpolation, code reorganization: Markus Nentwig May 2002
*/
/*
* Chorus effect.
*
* Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ):
*
* * gain-in ___
* ibuff -----+--------------------------------------------->| |
* | _________ | |
* | | | * level 1 | |
* +---->| delay 1 |----------------------------->| |
* | |_________| | |
* | /|\ | |
* : | | |
* : +-----------------+ +--------------+ | + |
* : | Delay control 1 |<--| mod. speed 1 | | |
* : +-----------------+ +--------------+ | |
* | _________ | |
* | | | * level n | |
* +---->| delay n |----------------------------->| |
* |_________| | |
* /|\ |___|
* | |
* +-----------------+ +--------------+ | * gain-out
* | Delay control n |<--| mod. speed n | |
* +-----------------+ +--------------+ +----->obuff
*
*
* The delay i is controlled by a sine or triangle modulation i ( 1 <= i <= n).
*
* The delay of each block is modulated between 0..depth ms
*
*/
/* Variable delay line implementation
* ==================================
*
* The modulated delay needs the value of the delayed signal between
* samples. A lowpass filter is used to obtain intermediate values
* between samples (bandlimited interpolation). The sample pulse
* train is convoluted with the impulse response of the low pass
* filter (sinc function). To make it work with a small number of
* samples, the sinc function is windowed (Hamming window).
*
*/
#include "fluid_chorus.h"
#include "fluid_sys.h"
#define MAX_CHORUS 99
#define MAX_DELAY 100
#define MAX_DEPTH 10
#define MIN_SPEED_HZ 0.29
#define MAX_SPEED_HZ 5
/* Length of one delay line in samples:
* Set through MAX_SAMPLES_LN2.
* For example:
* MAX_SAMPLES_LN2=12
* => MAX_SAMPLES=pow(2,12)=4096
* => MAX_SAMPLES_ANDMASK=4095
*/
#define MAX_SAMPLES_LN2 12
#define MAX_SAMPLES (1 << (MAX_SAMPLES_LN2-1))
#define MAX_SAMPLES_ANDMASK (MAX_SAMPLES-1)
/* Interpolate how many steps between samples? Must be power of two
For example: 8 => use a resolution of 256 steps between any two
samples
*/
#define INTERPOLATION_SUBSAMPLES_LN2 8
#define INTERPOLATION_SUBSAMPLES (1 << (INTERPOLATION_SUBSAMPLES_LN2-1))
#define INTERPOLATION_SUBSAMPLES_ANDMASK (INTERPOLATION_SUBSAMPLES-1)
/* Use how many samples for interpolation? Must be odd. '7' sounds
relatively clean, when listening to the modulated delay signal
alone. For a demo on aliasing try '1' With '3', the aliasing is
still quite pronounced for some input frequencies
*/
#define INTERPOLATION_SAMPLES 5
/* Private data for SKEL file */
struct _fluid_chorus_t {
/* Store the values between fluid_chorus_set_xxx and fluid_chorus_update
* Logic behind this:
* - both 'parameter' and 'new_parameter' hold the same value.
* - To change the chorus settings, 'new_parameter' is modified and
* fluid_chorus_update is called.
* - If the new value is valid, it is copied to 'parameter'.
* - If it is invalid, 'new_parameter' is restored to 'parameter'.
*/
int type; /* current value */
int new_type; /* next value, if parameter check is OK */
fluid_real_t depth_ms; /* current value */
fluid_real_t new_depth_ms; /* next value, if parameter check is OK */
fluid_real_t level; /* current value */
fluid_real_t new_level; /* next value, if parameter check is OK */
fluid_real_t speed_Hz; /* current value */
fluid_real_t new_speed_Hz; /* next value, if parameter check is OK */
int number_blocks; /* current value */
int new_number_blocks; /* next value, if parameter check is OK */
fluid_real_t *chorusbuf;
int counter;
long phase[MAX_CHORUS];
long modulation_period_samples;
int *lookup_tab;
fluid_real_t sample_rate;
/* sinc lookup table */
fluid_real_t sinc_table[INTERPOLATION_SAMPLES][INTERPOLATION_SUBSAMPLES];
};
void fluid_chorus_triangle(int *buf, int len, int depth);
void fluid_chorus_sine(int *buf, int len, int depth);
fluid_chorus_t*
new_fluid_chorus(fluid_real_t sample_rate)
{
int i; int ii;
fluid_chorus_t* chorus;
chorus = FLUID_NEW(fluid_chorus_t);
if (chorus == NULL) {
fluid_log(FLUID_PANIC, "chorus: Out of memory");
return NULL;
}
FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
chorus->sample_rate = sample_rate;
/* Lookup table for the SI function (impulse response of an ideal low pass) */
/* i: Offset in terms of whole samples */
for (i = 0; i < INTERPOLATION_SAMPLES; i++){
/* ii: Offset in terms of fractional samples ('subsamples') */
for (ii = 0; ii < INTERPOLATION_SUBSAMPLES; ii++){
/* Move the origin into the center of the table */
double i_shifted = ((double) i- ((double) INTERPOLATION_SAMPLES) / 2.
+ (double) ii / (double) INTERPOLATION_SUBSAMPLES);
if (fabs(i_shifted) < 0.000001) {
/* sinc(0) cannot be calculated straightforward (limit needed
for 0/0) */
chorus->sinc_table[i][ii] = (fluid_real_t)1.;
} else {
chorus->sinc_table[i][ii] = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
/* Hamming window */
chorus->sinc_table[i][ii] *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)INTERPOLATION_SAMPLES));
};
};
};
/* allocate lookup tables */
chorus->lookup_tab = FLUID_ARRAY(int, (int) (chorus->sample_rate / MIN_SPEED_HZ));
if (chorus->lookup_tab == NULL) {
fluid_log(FLUID_PANIC, "chorus: Out of memory");
goto error_recovery;
}
/* allocate sample buffer */
chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
if (chorus->chorusbuf == NULL) {
fluid_log(FLUID_PANIC, "chorus: Out of memory");
goto error_recovery;
}
if (fluid_chorus_init(chorus) != FLUID_OK){
goto error_recovery;
};
return chorus;
error_recovery:
delete_fluid_chorus(chorus);
return NULL;
}
int
fluid_chorus_init(fluid_chorus_t* chorus)
{
int i;
for (i = 0; i < MAX_SAMPLES; i++) {
chorus->chorusbuf[i] = 0.0;
}
/* initialize the chorus with the default settings */
fluid_chorus_set_nr(chorus, FLUID_CHORUS_DEFAULT_N);
fluid_chorus_set_level(chorus, FLUID_CHORUS_DEFAULT_LEVEL);
fluid_chorus_set_speed_Hz(chorus, FLUID_CHORUS_DEFAULT_SPEED);
fluid_chorus_set_depth_ms(chorus, FLUID_CHORUS_DEFAULT_DEPTH);
fluid_chorus_set_type(chorus, FLUID_CHORUS_MOD_SINE);
return fluid_chorus_update(chorus);
}
/* Purpose:
* Sets the number of stages.
* Requires call to fluid_chorus_update afterwards.
* Range checking is performed there.*/
void fluid_chorus_set_nr(fluid_chorus_t* chorus, int nr)
{
chorus->new_number_blocks = nr;
}
/* Purpose:
* API function, read the current state of the chorus
*/
int fluid_chorus_get_nr(fluid_chorus_t* chorus)
{
return chorus->number_blocks;
};
/* Purpose:
* Sets the mixing level of the signal from each delay line (linear).
* Requires calling fluid_chorus_update afterwards.*/
void fluid_chorus_set_level(fluid_chorus_t* chorus, fluid_real_t level)
{
chorus->new_level = level;
}
/* Purpose:
* API function, read the current state of the chorus
*/
fluid_real_t fluid_chorus_get_level(fluid_chorus_t* chorus)
{
return chorus->level;
};
/* Purpose:
* Sets the modulation frequency.
* Requires call to fluid_chorus_update afterwards.
* Range checking is performed there.*/
void fluid_chorus_set_speed_Hz(fluid_chorus_t* chorus, fluid_real_t speed_Hz)
{
chorus->new_speed_Hz = speed_Hz;
}
/* Purpose:
* API function, read the current state of the chorus
*/
fluid_real_t fluid_chorus_get_speed_Hz(fluid_chorus_t* chorus)
{
return chorus->speed_Hz;
};
/* Purpose:
* Sets the modulation depth in ms.
* Requires call to fluid_chorus_update afterwards.
* Range checking is performed there.*/
void fluid_chorus_set_depth_ms(fluid_chorus_t* chorus, fluid_real_t depth_ms)
{
chorus->new_depth_ms=depth_ms;
}
/* Purpose:
* API function, read the current state of the chorus
*/
fluid_real_t fluid_chorus_get_depth_ms(fluid_chorus_t* chorus)
{
return chorus->depth_ms;
};
/* Purpose:
* Sets the type of the modulation waveform.
* Requires call to fluid_chorus_update afterwards.
* Check for meaningful values is performed there.*/
void fluid_chorus_set_type(fluid_chorus_t* chorus, int type)
{
chorus->new_type=type;
}
/* Purpose:
* API function, read the current state of the chorus
*/
int fluid_chorus_get_type(fluid_chorus_t* chorus)
{
return chorus->type;
};
void
delete_fluid_chorus(fluid_chorus_t* chorus)
{
if (chorus == NULL) {
return;
}
if (chorus->chorusbuf != NULL) {
FLUID_FREE(chorus->chorusbuf);
}
if (chorus->lookup_tab != NULL) {
FLUID_FREE(chorus->lookup_tab);
}
FLUID_FREE(chorus);
}
/* Purpose:
* Calculates the internal chorus parameters using the settings from
* fluid_chorus_set_xxx. */
int
fluid_chorus_update(fluid_chorus_t* chorus)
{
int i;
int modulation_depth_samples;
if (chorus->new_number_blocks < 0) {
fluid_log(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0.");
chorus->new_number_blocks = 0;
} else if (chorus->new_number_blocks > MAX_CHORUS) {
fluid_log(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.",
MAX_CHORUS);
chorus->new_number_blocks = MAX_CHORUS;
};
if (chorus->new_speed_Hz < MIN_SPEED_HZ) {
fluid_log(FLUID_WARN, "chorus: speed is too low (min %f)! Setting value to min.",
(double) MIN_SPEED_HZ);
chorus->new_speed_Hz = MIN_SPEED_HZ;
} else if (chorus->new_speed_Hz > MAX_SPEED_HZ) {
fluid_log(FLUID_WARN, "chorus: speed must be below %f Hz! Setting value to max.",
(double) MAX_SPEED_HZ);
chorus->new_speed_Hz = MAX_SPEED_HZ;
}
if (chorus->new_depth_ms < 0.0) {
fluid_log(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
chorus->new_depth_ms = 0.0;
}
/* Depth: Check for too high value through modulation_depth_samples. */
if (chorus->new_level < 0.0) {
fluid_log(FLUID_WARN, "chorus: level must be positive! Setting value to 0.");
chorus->new_level = 0.0;
} else if (chorus->new_level > 10) {
fluid_log(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! "
"Setting it to 0.1.");
chorus->new_level = 0.1;
}
/* The modulating LFO goes through a full period every x samples: */
chorus->modulation_period_samples = chorus->sample_rate / chorus->new_speed_Hz;
/* The variation in delay time is x: */
modulation_depth_samples = (int)
(chorus->new_depth_ms / 1000.0 /* convert modulation depth in ms to s*/
* chorus->sample_rate);
if (modulation_depth_samples > MAX_SAMPLES) {
fluid_log(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
modulation_depth_samples = MAX_SAMPLES;
}
/* initialize LFO table */
if (chorus->type == FLUID_CHORUS_MOD_SINE) {
fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
modulation_depth_samples);
} else if (chorus->type == FLUID_CHORUS_MOD_TRIANGLE) {
fluid_chorus_triangle(chorus->lookup_tab, chorus->modulation_period_samples,
modulation_depth_samples);
} else {
fluid_log(FLUID_WARN, "chorus: Unknown modulation type. Using sinewave.");
chorus->type = FLUID_CHORUS_MOD_SINE;
fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
modulation_depth_samples);
};
for (i = 0; i < chorus->number_blocks; i++) {
/* Set the phase of the chorus blocks equally spaced */
chorus->phase[i] = (int) ((double) chorus->modulation_period_samples
* (double) i / (double) chorus->number_blocks);
}
/* Start of the circular buffer */
chorus->counter = 0;
chorus->type = chorus->new_type;
chorus->depth_ms = chorus->new_depth_ms;
chorus->level = chorus->new_level;
chorus->speed_Hz = chorus->new_speed_Hz;
chorus->number_blocks = chorus->new_number_blocks;
return FLUID_OK;
/* failure: */
/* Note: This lives on the assumption, that the last chorus values were correct.
* If not, this will loop forever and a day. */
/* fluid_log(FLUID_WARN, "chorus: Restoring last good settings"); */
/* chorus->new_type = chorus->type; */
/* chorus->new_depth_ms = chorus->depth_ms; */
/* chorus->new_level = chorus->level; */
/* chorus->new_speed_Hz = chorus->speed_Hz; */
/* chorus->new_number_blocks = chorus->number_blocks; */
/* return FLUID_FAILED; */
}
void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
int sample_index;
int i;
fluid_real_t d_in, d_out;
for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
d_in = in[sample_index];
d_out = 0.0f;
# if 0
/* Debug: Listen to the chorus signal only */
left_out[sample_index]=0;
right_out[sample_index]=0;
#endif
/* Write the current sample into the circular buffer */
chorus->chorusbuf[chorus->counter] = d_in;
for (i = 0; i < chorus->number_blocks; i++) {
int ii;
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
/* The value in the lookup table is so, that this expression
* will always be positive. It will always include a number of
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
* remain positive at all times. */
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
- chorus->lookup_tab[chorus->phase[i]]);
int pos_samples = pos_subsamples/INTERPOLATION_SUBSAMPLES;
/* modulo divide by INTERPOLATION_SUBSAMPLES */
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
/* Add the delayed signal to the chorus sum d_out Note: The
* delay in the delay line moves backwards for increasing
* delay!*/
/* 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]);
pos_samples--;
};
/* Cycle the phase of the modulating LFO */
chorus->phase[i]++;
chorus->phase[i] %= (chorus->modulation_period_samples);
} /* foreach chorus block */
d_out *= chorus->level;
/* Add the chorus sum d_out to output */
left_out[sample_index] += d_out;
right_out[sample_index] += d_out;
/* Move forward in circular buffer */
chorus->counter++;
chorus->counter %= MAX_SAMPLES;
} /* foreach sample */
}
/* Duplication of code ... */
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
int sample_index;
int i;
fluid_real_t d_in, d_out;
for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
d_in = in[sample_index];
d_out = 0.0f;
# if 0
/* Debug: Listen to the chorus signal only */
left_out[sample_index]=0;
right_out[sample_index]=0;
#endif
/* Write the current sample into the circular buffer */
chorus->chorusbuf[chorus->counter] = d_in;
for (i = 0; i < chorus->number_blocks; i++) {
int ii;
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
/* The value in the lookup table is so, that this expression
* will always be positive. It will always include a number of
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
* remain positive at all times. */
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
- chorus->lookup_tab[chorus->phase[i]]);
int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
/* modulo divide by INTERPOLATION_SUBSAMPLES */
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
/* Add the delayed signal to the chorus sum d_out Note: The
* delay in the delay line moves backwards for increasing
* delay!*/
/* 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];
pos_samples--;
};
/* Cycle the phase of the modulating LFO */
chorus->phase[i]++;
chorus->phase[i] %= (chorus->modulation_period_samples);
} /* foreach chorus block */
d_out *= chorus->level;
/* Add the chorus sum d_out to output */
left_out[sample_index] = d_out;
right_out[sample_index] = d_out;
/* Move forward in circular buffer */
chorus->counter++;
chorus->counter %= MAX_SAMPLES;
} /* foreach sample */
}
/* Purpose:
*
* Calculates a modulation waveform (sine) Its value ( modulo
* MAXSAMPLES) varies between 0 and depth*INTERPOLATION_SUBSAMPLES.
* Its period length is len. The waveform data will be used modulo
* MAXSAMPLES only. Since MAXSAMPLES is substracted from the waveform
* a couple of times here, the resulting (current position in
* buffer)-(waveform sample) will always be positive.
*/
void fluid_chorus_sine(int *buf, int len, int depth)
{
int i;
double val;
for (i = 0; i < len; i++) {
val = sin((double) i / (double)len * 2.0 * M_PI);
buf[i] = (int) ((1.0 + val) * (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES);
buf[i] -= 3* MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
// printf("%i %i\n",i,buf[i]);
}
}
/* Purpose:
* Calculates a modulation waveform (triangle)
* See fluid_chorus_sine for comments.
*/
void fluid_chorus_triangle(int *buf, int len, int depth)
{
int i=0;
int ii=len-1;
double val;
double val2;
while (i <= ii){
val = i * 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
val2= (int) (val + 0.5) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
buf[i++] = (int) val2;
buf[ii--] = (int) val2;
}
}
void
fluid_chorus_reset(fluid_chorus_t* chorus)
{
fluid_chorus_init(chorus);
}
+56
View File
@@ -0,0 +1,56 @@
/* 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_CHORUS_H
#define _FLUID_CHORUS_H
#include "fluidsynth_priv.h"
typedef struct _fluid_chorus_t fluid_chorus_t;
/*
* chorus
*/
fluid_chorus_t* new_fluid_chorus(fluid_real_t sample_rate);
void delete_fluid_chorus(fluid_chorus_t* chorus);
void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out);
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out);
int fluid_chorus_init(fluid_chorus_t* chorus);
void fluid_chorus_reset(fluid_chorus_t* chorus);
void fluid_chorus_set_nr(fluid_chorus_t* chorus, int nr);
void fluid_chorus_set_level(fluid_chorus_t* chorus, fluid_real_t level);
void fluid_chorus_set_speed_Hz(fluid_chorus_t* chorus, fluid_real_t speed_Hz);
void fluid_chorus_set_depth_ms(fluid_chorus_t* chorus, fluid_real_t depth_ms);
void fluid_chorus_set_type(fluid_chorus_t* chorus, int type);
int fluid_chorus_update(fluid_chorus_t* chorus);
int fluid_chorus_get_nr(fluid_chorus_t* chorus);
fluid_real_t fluid_chorus_get_level(fluid_chorus_t* chorus);
fluid_real_t fluid_chorus_get_speed_Hz(fluid_chorus_t* chorus);
fluid_real_t fluid_chorus_get_depth_ms(fluid_chorus_t* chorus);
int fluid_chorus_get_type(fluid_chorus_t* chorus);
#endif /* _FLUID_CHORUS_H */
File diff suppressed because it is too large Load Diff
+102
View File
@@ -0,0 +1,102 @@
/* 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_CMD_H
#define _FLUID_CMD_H
#include "fluidsynth_priv.h"
#include "fluid_io.h"
void fluid_shell_settings(fluid_settings_t* settings);
/** some help functions */
int fluid_is_number(char* a);
int fluid_is_empty(char* a);
char* fluid_expand_path(char* path, char* new_path, int len);
/** the handlers for the command lines */
int fluid_handle_help(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_quit(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_noteon(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_noteoff(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_cc(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_prog(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_select(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_inst(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_channels(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_load(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_unload(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reload(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_fonts(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_mstat(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reverbpreset(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reverbsetroomsize(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reverbsetdamp(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reverbsetwidth(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reverbsetlevel(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_chorusnr(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_choruslevel(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_chorusspeed(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_chorusdepth(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_chorus(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reverb(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_gain(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_interp(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_interpc(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_tuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_tune(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_settuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_resettuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_tunings(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_dumptuning(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_reset(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_source(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out);
int fluid_handle_echo(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out);
int fluid_handle_set(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_get(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_info(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_handle_settings(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd);
void delete_fluid_cmd(fluid_cmd_t* cmd);
int fluid_cmd_handler_handle(fluid_cmd_handler_t* handler,
int ac, char** av,
fluid_ostream_t out);
void fluid_server_remove_client(fluid_server_t* server, fluid_client_t* client);
void fluid_server_add_client(fluid_server_t* server, fluid_client_t* client);
fluid_client_t* new_fluid_client(fluid_server_t* server,
fluid_settings_t* settings,
fluid_cmd_handler_t* handler,
fluid_socket_t sock);
void delete_fluid_client(fluid_client_t* client);
void fluid_client_quit(fluid_client_t* client);
#endif /* _FLUID_CMD_H */
+320
View File
@@ -0,0 +1,320 @@
/* 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_conv.h"
/* conversion tables */
fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE];
fluid_real_t fluid_posbp_tab[128];
fluid_real_t fluid_concave_tab[128];
fluid_real_t fluid_convex_tab[128];
fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
/*
* void fluid_synth_init
*
* Does all the initialization for this module.
*/
void
fluid_conversion_config(void)
{
int i;
double x;
for (i = 0; i < FLUID_CENTS_HZ_SIZE; i++) {
fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0);
}
/* centibels to amplitude conversion
* Note: SF2.01 section 8.1.3: Initial attenuation range is
* between 0 and 144 dB. Therefore a negative attenuation is
* not allowed.
*/
for (i = 0; i < FLUID_CB_AMP_SIZE; i++) {
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
}
/* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont
* specification in regards to volume attenuation. The below calculation
* is an approx. equation for generating a table equivelant to the
* cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told
* was generated from device testing. By the spec this should be centibels.
*/
for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) {
fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR);
}
/* initialize the conversion tables (see fluid_mod.c
fluid_mod_get_value cases 4 and 8) */
/* concave unipolar positive transform curve */
fluid_concave_tab[0] = 0.0;
fluid_concave_tab[127] = 1.0;
/* convex unipolar positive transform curve */
fluid_convex_tab[0] = 0;
fluid_convex_tab[127] = 1.0;
x = log10(128.0 / 127.0);
/* There seems to be an error in the specs. The equations are
implemented according to the pictures on SF2.01 page 73. */
for (i = 1; i < 127; i++) {
x = -20.0 / 96.0 * log((i * i) / (127.0 * 127.0)) / log(10.0);
fluid_convex_tab[i] = (fluid_real_t) (1.0 - x);
fluid_concave_tab[127 - i] = (fluid_real_t) x;
}
/* initialize the pan conversion table */
x = PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
for (i = 0; i < FLUID_PAN_SIZE; i++) {
fluid_pan_tab[i] = (fluid_real_t) sin(i * x);
}
}
/*
* fluid_ct2hz
*/
fluid_real_t
fluid_ct2hz_real(fluid_real_t cents)
{
if (cents < 0)
return (fluid_real_t) 1.0;
else if (cents < 900) {
return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int) (cents + 300)];
} else if (cents < 2100) {
return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int) (cents - 900)];
} else if (cents < 3300) {
return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int) (cents - 2100)];
} else if (cents < 4500) {
return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int) (cents - 3300)];
} else if (cents < 5700) {
return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int) (cents - 4500)];
} else if (cents < 6900) {
return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int) (cents - 5700)];
} else if (cents < 8100) {
return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int) (cents - 6900)];
} else if (cents < 9300) {
return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int) (cents - 8100)];
} else if (cents < 10500) {
return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int) (cents - 9300)];
} else if (cents < 11700) {
return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int) (cents - 10500)];
} else if (cents < 12900) {
return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int) (cents - 11700)];
} else if (cents < 14100) {
return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int) (cents - 12900)];
} else {
return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
}
}
/*
* fluid_ct2hz
*/
fluid_real_t
fluid_ct2hz(fluid_real_t cents)
{
/* Filter fc limit: SF2.01 page 48 # 8 */
if (cents >= 13500){
cents = 13500; /* 20 kHz */
} else if (cents < 1500){
cents = 1500; /* 20 Hz */
}
return fluid_ct2hz_real(cents);
}
/*
* fluid_cb2amp
*
* in: a value between 0 and 960, 0 is no attenuation
* out: a value between 1 and 0
*/
fluid_real_t
fluid_cb2amp(fluid_real_t cb)
{
/*
* cb: an attenuation in 'centibels' (1/10 dB)
* SF2.01 page 49 # 48 limits it to 144 dB.
* 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
*/
/* minimum attenuation: 0 dB */
if (cb < 0) {
return 1.0;
}
if (cb >= FLUID_CB_AMP_SIZE) {
return 0.0;
}
return fluid_cb2amp_tab[(int) cb];
}
/*
* fluid_atten2amp
*
* in: a value between 0 and 1440, 0 is no attenuation
* out: a value between 1 and 0
*
* Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't
* follow this. Thats the reason for separate fluid_cb2amp and fluid_atten2amp.
*/
fluid_real_t
fluid_atten2amp(fluid_real_t atten)
{
if (atten < 0) return 1.0;
else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0;
else return fluid_atten2amp_tab[(int) atten];
}
/*
* fluid_tc2sec_delay
*/
fluid_real_t
fluid_tc2sec_delay(fluid_real_t tc)
{
/* SF2.01 section 8.1.2 items 21, 23, 25, 33
* SF2.01 section 8.1.3 items 21, 23, 25, 33
*
* The most negative number indicates a delay of 0. Range is limited
* from -12000 to 5000 */
if (tc <= -32768.0f) {
return (fluid_real_t) 0.0f;
};
if (tc < -12000.) {
tc = (fluid_real_t) -12000.0f;
}
if (tc > 5000.0f) {
tc = (fluid_real_t) 5000.0f;
}
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
* fluid_tc2sec_attack
*/
fluid_real_t
fluid_tc2sec_attack(fluid_real_t tc)
{
/* SF2.01 section 8.1.2 items 26, 34
* SF2.01 section 8.1.3 items 26, 34
* The most negative number indicates a delay of 0
* Range is limited from -12000 to 8000 */
if (tc<=-32768.){return (fluid_real_t) 0.0;};
if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
if (tc>8000.){tc=(fluid_real_t) 8000.0;};
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
* fluid_tc2sec
*/
fluid_real_t
fluid_tc2sec(fluid_real_t tc)
{
/* No range checking here! */
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
* fluid_tc2sec_release
*/
fluid_real_t
fluid_tc2sec_release(fluid_real_t tc)
{
/* SF2.01 section 8.1.2 items 30, 38
* SF2.01 section 8.1.3 items 30, 38
* No 'most negative number' rule here!
* Range is limited from -12000 to 8000 */
if (tc<=-32768.){return (fluid_real_t) 0.0;};
if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
if (tc>8000.){tc=(fluid_real_t) 8000.0;};
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
}
/*
* fluid_act2hz
*
* Convert from absolute cents to Hertz
*/
fluid_real_t
fluid_act2hz(fluid_real_t c)
{
return (fluid_real_t) (8.176 * pow(2.0, (double) c / 1200.0));
}
/*
* fluid_hz2ct
*
* Convert from Hertz to cents
*/
fluid_real_t
fluid_hz2ct(fluid_real_t f)
{
return (fluid_real_t) (6900 + 1200 * log(f / 440.0) / log(2.0));
}
/*
* fluid_pan
*/
fluid_real_t
fluid_pan(fluid_real_t c, int left)
{
if (left) {
c = -c;
}
if (c < -500) {
return (fluid_real_t) 0.0;
} else if (c > 500) {
return (fluid_real_t) 1.0;
} else {
return fluid_pan_tab[(int) (c + 500)];
}
}
/*
* fluid_concave
*/
fluid_real_t
fluid_concave(fluid_real_t val)
{
if (val < 0) {
return 0;
} else if (val > 127) {
return 1;
}
return fluid_concave_tab[(int) val];
}
/*
* fluid_convex
*/
fluid_real_t
fluid_convex(fluid_real_t val)
{
if (val < 0) {
return 0;
} else if (val > 127) {
return 1;
}
return fluid_convex_tab[(int) val];
}
+62
View File
@@ -0,0 +1,62 @@
/* 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_CONV_H
#define _FLUID_CONV_H
#include "fluidsynth_priv.h"
#define FLUID_CENTS_HZ_SIZE 1200
#define FLUID_VEL_CB_SIZE 128
#define FLUID_CB_AMP_SIZE 961
#define FLUID_ATTEN_AMP_SIZE 1441
#define FLUID_PAN_SIZE 1002
/* EMU 8k/10k don't follow spec in regards to volume attenuation.
* This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR).
* By the standard this should be -200.0. */
#define FLUID_ATTEN_POWER_FACTOR (-531.509)
void fluid_conversion_config(void);
fluid_real_t fluid_ct2hz_real(fluid_real_t cents);
fluid_real_t fluid_ct2hz(fluid_real_t cents);
fluid_real_t fluid_cb2amp(fluid_real_t cb);
fluid_real_t fluid_atten2amp(fluid_real_t atten);
fluid_real_t fluid_tc2sec(fluid_real_t tc);
fluid_real_t fluid_tc2sec_delay(fluid_real_t tc);
fluid_real_t fluid_tc2sec_attack(fluid_real_t tc);
fluid_real_t fluid_tc2sec_release(fluid_real_t tc);
fluid_real_t fluid_act2hz(fluid_real_t c);
fluid_real_t fluid_hz2ct(fluid_real_t c);
fluid_real_t fluid_pan(fluid_real_t c, int left);
fluid_real_t fluid_concave(fluid_real_t val);
fluid_real_t fluid_convex(fluid_real_t val);
extern fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
extern fluid_real_t fluid_vel2cb_tab[FLUID_VEL_CB_SIZE];
extern fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
extern fluid_real_t fluid_posbp_tab[128];
extern fluid_real_t fluid_concave_tab[128];
extern fluid_real_t fluid_convex_tab[128];
extern fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
#endif /* _FLUID_CONV_H */
File diff suppressed because it is too large Load Diff
+608
View File
@@ -0,0 +1,608 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
*
* 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_DEFSFONT_H
#define _FLUID_DEFSFONT_H
#include "fluidsynth.h"
#include "fluidsynth_priv.h"
#include "fluid_list.h"
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/*-----------------------------------sfont.h----------------------------*/
#define SF_SAMPMODES_LOOP 1
#define SF_SAMPMODES_UNROLL 2
#define SF_MIN_SAMPLERATE 400
#define SF_MAX_SAMPLERATE 50000
#define SF_MIN_SAMPLE_LENGTH 32
/* Sound Font structure defines */
typedef struct _SFVersion
{ /* version structure */
unsigned short major;
unsigned short minor;
}
SFVersion;
typedef struct _SFMod
{ /* Modulator structure */
unsigned short src; /* source modulator */
unsigned short dest; /* destination generator */
signed short amount; /* signed, degree of modulation */
unsigned short amtsrc; /* second source controls amnt of first */
unsigned short trans; /* transform applied to source */
}
SFMod;
typedef union _SFGenAmount
{ /* Generator amount structure */
signed short sword; /* signed 16 bit value */
unsigned short uword; /* unsigned 16 bit value */
struct
{
unsigned char lo; /* low value for ranges */
unsigned char hi; /* high value for ranges */
}
range;
}
SFGenAmount;
typedef struct _SFGen
{ /* Generator structure */
unsigned short id; /* generator ID */
SFGenAmount amount; /* generator value */
}
SFGen;
typedef struct _SFZone
{ /* Sample/instrument zone structure */
fluid_list_t *instsamp; /* instrument/sample pointer for zone */
fluid_list_t *gen; /* list of generators */
fluid_list_t *mod; /* list of modulators */
}
SFZone;
typedef struct _SFSample
{ /* Sample structure */
char name[21]; /* Name of sample */
unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
unsigned int start; /* Offset in sample area to start of sample */
unsigned int end; /* Offset from start to end of sample,
this is the last point of the
sample, the SF spec has this as the
1st point after, corrected on
load/save */
unsigned int loopstart; /* Offset from start to start of loop */
unsigned int loopend; /* Offset from start to end of loop,
marks the first point after loop,
whose sample value is ideally
equivalent to loopstart */
unsigned int samplerate; /* Sample rate recorded at */
unsigned char origpitch; /* root midi key number */
signed char pitchadj; /* pitch correction in cents */
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
}
SFSample;
typedef struct _SFInst
{ /* Instrument structure */
char name[21]; /* Name of instrument */
fluid_list_t *zone; /* list of instrument zones */
}
SFInst;
typedef struct _SFPreset
{ /* Preset structure */
char name[21]; /* preset name */
unsigned short prenum; /* preset number */
unsigned short bank; /* bank number */
unsigned int libr; /* Not used (preserved) */
unsigned int genre; /* Not used (preserved) */
unsigned int morph; /* Not used (preserved) */
fluid_list_t *zone; /* list of preset zones */
}
SFPreset;
/* NOTE: sffd is also used to determine if sound font is new (NULL) */
typedef struct _SFData
{ /* Sound font data structure */
SFVersion version; /* sound font version */
SFVersion romver; /* ROM version */
unsigned int samplepos; /* position within sffd of the sample chunk */
unsigned int samplesize; /* length within sffd of the sample chunk */
char *fname; /* file name */
FILE *sffd; /* loaded sfont file descriptor */
fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
fluid_list_t *preset; /* linked list of preset info */
fluid_list_t *inst; /* linked list of instrument info */
fluid_list_t *sample; /* linked list of sample info */
}
SFData;
/* sf file chunk IDs */
enum
{ UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID,
INFO_ID, SDTA_ID, PDTA_ID, /* info/sample/preset */
IFIL_ID, ISNG_ID, INAM_ID, IROM_ID, /* info ids (1st byte of info strings) */
IVER_ID, ICRD_ID, IENG_ID, IPRD_ID, /* more info ids */
ICOP_ID, ICMT_ID, ISFT_ID, /* and yet more info ids */
SNAM_ID, SMPL_ID, /* sample ids */
PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID, /* preset ids */
IHDR_ID, IBAG_ID, IMOD_ID, IGEN_ID, /* instrument ids */
SHDR_ID /* sample info */
};
/* generator types */
typedef enum
{ Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_ModLFO2Pitch,
Gen_VibLFO2Pitch, Gen_ModEnv2Pitch, Gen_FilterFc, Gen_FilterQ,
Gen_ModLFO2FilterFc, Gen_ModEnv2FilterFc, Gen_EndAddrCoarseOfs,
Gen_ModLFO2Vol, 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_Key2ModEnvHold,
Gen_Key2ModEnvDecay, Gen_VolEnvDelay, Gen_VolEnvAttack,
Gen_VolEnvHold, Gen_VolEnvDecay, Gen_VolEnvSustain, Gen_VolEnvRelease,
Gen_Key2VolEnvHold, Gen_Key2VolEnvDecay, 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_SampleModes,
Gen_Reserved3, Gen_ScaleTune, Gen_ExclusiveClass, Gen_OverrideRootKey,
Gen_Dummy
}
Gen_Type;
#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
#define Gen_Count Gen_Dummy /* count of generators */
#define GenArrSize sizeof(SFGenAmount)*Gen_Count /* gen array size */
/* generator unit type */
typedef enum
{
None, /* No unit type */
Unit_Smpls, /* in samples */
Unit_32kSmpls, /* in 32k samples */
Unit_Cent, /* in cents (1/100th of a semitone) */
Unit_HzCent, /* in Hz Cents */
Unit_TCent, /* in Time Cents */
Unit_cB, /* in centibels (1/100th of a decibel) */
Unit_Percent, /* in percentage */
Unit_Semitone, /* in semitones */
Unit_Range /* a range of values */
}
Gen_Unit;
/* global data */
extern unsigned short badgen[]; /* list of bad generators */
extern unsigned short badpgen[]; /* list of bad preset generators */
/* functions */
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);
void sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone);
fluid_list_t *gen_inlist (int gen, fluid_list_t * genlist);
int gen_valid (int gen);
int gen_validp (int gen);
/*-----------------------------------sffile.h----------------------------*/
/*
File structures and routines (used to be in sffile.h)
*/
#define CHNKIDSTR(id) &idlist[(id - 1) * 4]
/* sfont file chunk sizes */
#define SFPHDRSIZE 38
#define SFBAGSIZE 4
#define SFMODSIZE 10
#define SFGENSIZE 4
#define SFIHDRSIZE 22
#define SFSHDRSIZE 46
/* sfont file data structures */
typedef struct _SFChunk
{ /* RIFF file chunk structure */
unsigned int id; /* chunk id */
unsigned int size; /* size of the following chunk */
}
SFChunk;
typedef struct _SFPhdr
{
unsigned char name[20]; /* preset name */
unsigned short preset; /* preset number */
unsigned short bank; /* bank number */
unsigned short pbagndx; /* index into preset bag */
unsigned int library; /* just for preserving them */
unsigned int genre; /* Not used */
unsigned int morphology; /* Not used */
}
SFPhdr;
typedef struct _SFBag
{
unsigned short genndx; /* index into generator list */
unsigned short modndx; /* index into modulator list */
}
SFBag;
typedef struct _SFIhdr
{
char name[20]; /* Name of instrument */
unsigned short ibagndx; /* Instrument bag index */
}
SFIhdr;
typedef struct _SFShdr
{ /* Sample header loading struct */
char name[20]; /* Sample name */
unsigned int start; /* Offset to start of sample */
unsigned int end; /* Offset to end of sample */
unsigned int loopstart; /* Offset to start of loop */
unsigned int loopend; /* Offset to end of loop */
unsigned int samplerate; /* Sample rate recorded at */
unsigned char origpitch; /* root midi key number */
signed char pitchadj; /* pitch correction in cents */
unsigned short samplelink; /* Not used */
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
}
SFShdr;
/* data */
extern char idlist[];
/* functions */
SFData *sfload_file (const char * fname);
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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 Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Provide definitions for some commonly used macros.
* Some of them are only provided if they haven't already
* been defined. It is assumed that if they are already
* defined then the current definition is correct.
*/
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#define GPOINTER_TO_INT(p) ((int) (p))
#define GINT_TO_POINTER(i) ((void *) (i))
char* g_strdup (const char *str);
/* Provide simple macro statement wrappers (adapted from Perl):
* G_STMT_START { statements; } G_STMT_END;
* can be used as a single statement, as in
* if (x) G_STMT_START { ... } G_STMT_END; else ...
*
* For gcc we will wrap the statements within `({' and `})' braces.
* For SunOS they will be wrapped within `if (1)' and `else (void) 0',
* and otherwise within `do' and `while (0)'.
*/
#if !(defined (G_STMT_START) && defined (G_STMT_END))
# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
# define G_STMT_START (void)(
# define G_STMT_END )
# else
# if (defined (sun) || defined (__sun__))
# define G_STMT_START if (1)
# define G_STMT_END else (void)0
# else
# define G_STMT_START do
# define G_STMT_END while (0)
# endif
# endif
#endif
/* Basic bit swapping functions
*/
#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((unsigned short) ( \
(((unsigned short) (val) & (unsigned short) 0x00ffU) << 8) | \
(((unsigned short) (val) & (unsigned short) 0xff00U) >> 8)))
#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((unsigned int) ( \
(((unsigned int) (val) & (unsigned int) 0x000000ffU) << 24) | \
(((unsigned int) (val) & (unsigned int) 0x0000ff00U) << 8) | \
(((unsigned int) (val) & (unsigned int) 0x00ff0000U) >> 8) | \
(((unsigned int) (val) & (unsigned int) 0xff000000U) >> 24)))
#define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
#define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
#define GINT16_TO_LE(val) ((signed short) (val))
#define GUINT16_TO_LE(val) ((unsigned short) (val))
#define GINT16_TO_BE(val) ((signed short) GUINT16_SWAP_LE_BE (val))
#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val))
#define GINT32_TO_LE(val) ((signed int) (val))
#define GUINT32_TO_LE(val) ((unsigned int) (val))
#define GINT32_TO_BE(val) ((signed int) GUINT32_SWAP_LE_BE (val))
#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val))
/* The G*_TO_?E() macros are defined in glibconfig.h.
* The transformation is symmetric, so the FROM just maps to the TO.
*/
#define GINT16_FROM_LE(val) (GINT16_TO_LE (val))
#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val))
#define GINT16_FROM_BE(val) (GINT16_TO_BE (val))
#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val))
#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val))
#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val))
/*-----------------------------------util.h----------------------------*/
/*
Utility functions (formerly in util.h)
*/
#define FAIL 0
#define OK 1
enum
{ ErrWarn, ErrFatal, ErrStatus, ErrCorr, ErrEof, ErrMem, Errno,
ErrRead, ErrWrite
};
#define ErrMax ErrWrite
#define ErrnoStart Errno
#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);
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/********************************************************************************/
/***************************************************************
*
* FORWARD DECLARATIONS
*/
typedef struct _fluid_defsfont_t fluid_defsfont_t;
typedef struct _fluid_defpreset_t fluid_defpreset_t;
typedef struct _fluid_preset_zone_t fluid_preset_zone_t;
typedef struct _fluid_inst_t fluid_inst_t;
typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
/*
Public interface
*/
fluid_sfloader_t* new_fluid_defsfloader(void);
int delete_fluid_defsfloader(fluid_sfloader_t* loader);
fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename);
int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont);
char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont);
fluid_preset_t* fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont);
int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset);
int fluid_defpreset_preset_delete(fluid_preset_t* preset);
char* fluid_defpreset_preset_get_name(fluid_preset_t* preset);
int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset);
int fluid_defpreset_preset_get_num(fluid_preset_t* preset);
int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
/*
* fluid_defsfont_t
*/
struct _fluid_defsfont_t
{
char* filename; /* the filename of this soundfont */
unsigned int samplepos; /* the position in the file at which the sample data starts */
unsigned int samplesize; /* the size of the sample data */
short* sampledata; /* the sample data, loaded in ram */
fluid_list_t* sample; /* the samples in this soundfont */
fluid_defpreset_t* preset; /* the presets of this soundfont */
fluid_preset_t iter_preset; /* preset interface used in the iteration */
fluid_defpreset_t* iter_cur; /* the current preset in the iteration */
};
fluid_defsfont_t* new_fluid_defsfont(void);
int delete_fluid_defsfont(fluid_defsfont_t* sfont);
int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file);
char* fluid_defsfont_get_name(fluid_defsfont_t* sfont);
fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int prenum);
void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont);
int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset);
int fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont);
int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample);
int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset);
fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s);
/*
* fluid_preset_t
*/
struct _fluid_defpreset_t
{
fluid_defpreset_t* next;
fluid_defsfont_t* sfont; /* the soundfont this preset belongs to */
char name[21]; /* the name of the preset */
unsigned int bank; /* the bank number */
unsigned int num; /* the preset number */
fluid_preset_zone_t* global_zone; /* the global zone of the preset */
fluid_preset_zone_t* zone; /* the chained list of preset zones */
};
fluid_defpreset_t* new_fluid_defpreset(fluid_defsfont_t* sfont);
int delete_fluid_defpreset(fluid_defpreset_t* preset);
fluid_defpreset_t* fluid_defpreset_next(fluid_defpreset_t* preset);
int fluid_defpreset_import_sfont(fluid_defpreset_t* preset, SFPreset* sfpreset, fluid_defsfont_t* sfont);
int fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
int fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
fluid_preset_zone_t* fluid_defpreset_get_zone(fluid_defpreset_t* preset);
fluid_preset_zone_t* fluid_defpreset_get_global_zone(fluid_defpreset_t* preset);
int fluid_defpreset_get_banknum(fluid_defpreset_t* preset);
int fluid_defpreset_get_num(fluid_defpreset_t* preset);
char* fluid_defpreset_get_name(fluid_defpreset_t* preset);
int fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
/*
* fluid_preset_zone
*/
struct _fluid_preset_zone_t
{
fluid_preset_zone_t* next;
char* name;
fluid_inst_t* inst;
int keylo;
int keyhi;
int vello;
int velhi;
fluid_gen_t gen[GEN_LAST];
fluid_mod_t * mod; /* List of modulators */
};
fluid_preset_zone_t* new_fluid_preset_zone(char* name);
int delete_fluid_preset_zone(fluid_preset_zone_t* zone);
fluid_preset_zone_t* fluid_preset_zone_next(fluid_preset_zone_t* preset);
int fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone* sfzone, fluid_defsfont_t* sfont);
int fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel);
fluid_inst_t* fluid_preset_zone_get_inst(fluid_preset_zone_t* zone);
/*
* fluid_inst_t
*/
struct _fluid_inst_t
{
char name[21];
fluid_inst_zone_t* global_zone;
fluid_inst_zone_t* zone;
};
fluid_inst_t* new_fluid_inst(void);
int delete_fluid_inst(fluid_inst_t* inst);
int fluid_inst_import_sfont(fluid_inst_t* inst, SFInst *sfinst, fluid_defsfont_t* sfont);
int fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
int fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
fluid_inst_zone_t* fluid_inst_get_zone(fluid_inst_t* inst);
fluid_inst_zone_t* fluid_inst_get_global_zone(fluid_inst_t* inst);
/*
* fluid_inst_zone_t
*/
struct _fluid_inst_zone_t
{
fluid_inst_zone_t* next;
char* name;
fluid_sample_t* sample;
int keylo;
int keyhi;
int vello;
int velhi;
fluid_gen_t gen[GEN_LAST];
fluid_mod_t * mod; /* List of modulators */
};
fluid_inst_zone_t* new_fluid_inst_zone(char* name);
int delete_fluid_inst_zone(fluid_inst_zone_t* zone);
fluid_inst_zone_t* fluid_inst_zone_next(fluid_inst_zone_t* zone);
int fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont);
int fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel);
fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone);
fluid_sample_t* new_fluid_sample(void);
int delete_fluid_sample(fluid_sample_t* sample);
int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont);
int fluid_sample_in_rom(fluid_sample_t* sample);
#endif /* _FLUID_SFONT_H */
+26
View File
@@ -0,0 +1,26 @@
/* 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
+281
View File
@@ -0,0 +1,281 @@
/* 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 */
switch(dsp_interp_method){
case FLUID_INTERP_NONE:
/* No interpolation. Just take the sample, which is closest to
* the playback pointer. Questionable quality, but very
* efficient. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_phase_index = fluid_phase_index(dsp_phase);
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);
dsp_amp += dsp_amp_incr;
}
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;
}
break;
} /* switch interpolation method */
} /* 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 */
/* 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 = 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;
}
} else {
/* 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];
}
}
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];
}
}
}
/* 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];
}
}
/* 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];
}
}
+120
View File
@@ -0,0 +1,120 @@
/* 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
*
*/
/* Nonoptimized DSP loop */
#warning "This code is meant for experiments only.";
/* wave table interpolation */
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_sample = (dsp_amp *
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]
+ dsp_coeff->a2 * dsp_data[dsp_phase_index+2]
+ dsp_coeff->a3 * dsp_data[dsp_phase_index+3]));
/* increment phase and amplitude */
fluid_phase_incr(dsp_phase, dsp_phase_incr);
dsp_amp += dsp_amp_incr;
/* filter */
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_sample - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_sample = dsp_b0 * dsp_centernode + dsp_b1 * dsp_hist1 + dsp_b2 * dsp_hist2;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
/* pan */
dsp_left_buf[dsp_i] += voice->amp_left * dsp_sample;
dsp_right_buf[dsp_i] += voice->amp_right * dsp_sample;
/* reverb */
if (dsp_reverb_buf){
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_sample;
}
/* chorus */
if (dsp_chorus_buf){
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_sample;
}
}
+387
View File
@@ -0,0 +1,387 @@
/* 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++;
}
}
+495
View File
@@ -0,0 +1,495 @@
/* 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
*/
/*
2002 : API design by Peter Hanappe and Antoine Schmitt
August 2002 : Implementation by Antoine Schmitt [email protected]
as part of the infiniteCD author project
http://www.infiniteCD.org/
Oct4.2002 : AS : corrected bug in heap allocation, that caused a crash during sequencer free.
*/
#include "fluid_event_priv.h"
#include "fluidsynth_priv.h"
/***************************************************************
*
* SEQUENCER EVENTS
*/
/* Event alloc/free */
fluid_event_t*
new_fluid_event()
{
fluid_event_t* evt;
evt = FLUID_NEW(fluid_event_t);
if (evt == NULL) {
fluid_log(FLUID_PANIC, "event: Out of memory\n");
return NULL;
}
FLUID_MEMSET(evt, 0, sizeof(fluid_event_t));
// by default, no type
evt->dest = -1;
evt->src = -1;
evt->type = -1;
return(evt);
}
void
delete_fluid_event(fluid_event_t* evt)
{
if (evt == NULL) {
return;
}
FLUID_FREE(evt);
}
/* Initializing events */
void
fluid_event_set_time(fluid_event_t* evt, unsigned int time)
{
evt->time = time;
}
void
fluid_event_set_source(fluid_event_t* evt, short src)
{
evt->src = src;
}
void
fluid_event_set_dest(fluid_event_t* evt, short dest)
{
evt->dest = dest;
}
/* Timer events */
void
fluid_event_timer(fluid_event_t* evt, void* data)
{
evt->type = FLUID_SEQ_TIMER;
evt->data = data;
}
/* Note events */
void
fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
{
evt->type = FLUID_SEQ_NOTEON;
evt->channel = channel;
evt->key = key;
evt->vel = vel;
}
void
fluid_event_noteoff(fluid_event_t* evt, int channel, short key)
{
evt->type = FLUID_SEQ_NOTEOFF;
evt->channel = channel;
evt->key = key;
}
void
fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration)
{
evt->type = FLUID_SEQ_NOTE;
evt->channel = channel;
evt->key = key;
evt->vel = vel;
evt->duration = duration;
}
void
fluid_event_all_sounds_off(fluid_event_t* evt, int channel)
{
evt->type = FLUID_SEQ_ALLSOUNDSOFF;
evt->channel = channel;
}
void
fluid_event_all_notes_off(fluid_event_t* evt, int channel)
{
evt->type = FLUID_SEQ_ALLNOTESOFF;
evt->channel = channel;
}
void
fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
{
evt->type = FLUID_SEQ_BANKSELECT;
evt->channel = channel;
evt->control = bank_num;
}
void
fluid_event_program_change(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_PROGRAMCHANGE;
evt->channel = channel;
evt->value = val;
}
void
fluid_event_program_select(fluid_event_t* evt, int channel,
unsigned int sfont_id, short bank_num, short preset_num)
{
evt->type = FLUID_SEQ_PROGRAMSELECT;
evt->channel = channel;
evt->duration = sfont_id;
evt->value = preset_num;
evt->control = bank_num;
}
void
fluid_event_any_control_change(fluid_event_t* evt, int channel)
{
evt->type = FLUID_SEQ_ANYCONTROLCHANGE;
evt->channel = channel;
}
void
fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch)
{
evt->type = FLUID_SEQ_PITCHBEND;
evt->channel = channel;
if (pitch < 0) pitch = 0;
if (pitch > 16383) pitch = 16383;
evt->pitch = pitch;
}
void
fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
{
evt->type = FLUID_SEQ_PITCHWHHELSENS;
evt->channel = channel;
evt->value = value;
}
void
fluid_event_modulation(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_MODULATION;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
void
fluid_event_sustain(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_SUSTAIN;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
void
fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val)
{
evt->type = FLUID_SEQ_CONTROLCHANGE;
evt->channel = channel;
evt->control = control;
evt->value = val;
}
void
fluid_event_pan(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_PAN;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
void
fluid_event_volume(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_VOLUME;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
void
fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_REVERBSEND;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
void
fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_CHORUSSEND;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/* Accessing event data */
int fluid_event_get_type(fluid_event_t* evt)
{
return evt->type;
}
unsigned int fluid_event_get_time(fluid_event_t* evt)
{
return evt->time;
}
short fluid_event_get_source(fluid_event_t* evt)
{
return evt->src;
}
short fluid_event_get_dest(fluid_event_t* evt)
{
return evt->dest;
}
int fluid_event_get_channel(fluid_event_t* evt)
{
return evt->channel;
}
short fluid_event_get_key(fluid_event_t* evt)
{
return evt->key;
}
short fluid_event_get_velocity(fluid_event_t* evt)
{
return evt->vel;
}
short fluid_event_get_control(fluid_event_t* evt)
{
return evt->control;
}
short fluid_event_get_value(fluid_event_t* evt)
{
return evt->value;
}
void* fluid_event_get_data(fluid_event_t* evt)
{
return evt->data;
}
unsigned int fluid_event_get_duration(fluid_event_t* evt)
{
return evt->duration;
}
short fluid_event_get_bank(fluid_event_t* evt)
{
return evt->control;
}
int fluid_event_get_pitch(fluid_event_t* evt)
{
return evt->pitch;
}
short
fluid_event_get_program(fluid_event_t* evt)
{
return evt->value;
}
unsigned int
fluid_event_get_sfont_id(fluid_event_t* evt)
{
return evt->duration;
}
/********************/
/* heap management */
/********************/
fluid_evt_heap_t*
_fluid_evt_heap_init(int nbEvents)
{
#ifdef HEAP_WITH_DYNALLOC
int i;
fluid_evt_heap_t* heap;
fluid_evt_entry *tmp;
heap = FLUID_NEW(fluid_evt_heap_t);
if (heap == NULL) {
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return NULL;
}
heap->freelist = NULL;
fluid_mutex_init(heap->mutex);
/* LOCK */
fluid_mutex_lock(heap->mutex);
/* Allocate the event entries */
for (i = 0; i < nbEvents; i++) {
tmp = FLUID_NEW(fluid_evt_entry);
tmp->next = heap->freelist;
heap->freelist = tmp;
}
/* UNLOCK */
fluid_mutex_unlock(heap->mutex);
#else
int i;
fluid_evt_heap_t* heap;
int siz = 2*sizeof(fluid_evt_entry *) + sizeof(fluid_evt_entry)*nbEvents;
heap = (fluid_evt_heap_t *)FLUID_MALLOC(siz);
if (heap == NULL) {
fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
return NULL;
}
FLUID_MEMSET(heap, 0, siz);
/* link all heap events */
{
fluid_evt_entry *tmp = &(heap->pool);
for (i = 0 ; i < nbEvents - 1 ; i++)
tmp[i].next = &(tmp[i+1]);
tmp[nbEvents-1].next = NULL;
/* set head & tail */
heap->tail = &(tmp[nbEvents-1]);
heap->head = &(heap->pool);
}
#endif
return (heap);
}
void
_fluid_evt_heap_free(fluid_evt_heap_t* heap)
{
#ifdef HEAP_WITH_DYNALLOC
fluid_evt_entry *tmp, *next;
/* LOCK */
fluid_mutex_lock(heap->mutex);
tmp = heap->freelist;
while (tmp) {
next = tmp->next;
FLUID_FREE(tmp);
tmp = next;
}
/* UNLOCK */
fluid_mutex_unlock(heap->mutex);
fluid_mutex_destroy(heap->mutex);
FLUID_FREE(heap);
#else
FLUID_FREE(heap);
#endif
}
fluid_evt_entry*
_fluid_seq_heap_get_free(fluid_evt_heap_t* heap)
{
#ifdef HEAP_WITH_DYNALLOC
fluid_evt_entry* evt = NULL;
/* LOCK */
fluid_mutex_lock(heap->mutex);
#if !defined(MACOS9)
if (heap->freelist == NULL) {
heap->freelist = FLUID_NEW(fluid_evt_entry);
if (heap->freelist != NULL) {
heap->freelist->next = NULL;
}
}
#endif
evt = heap->freelist;
if (evt != NULL) {
heap->freelist = heap->freelist->next;
evt->next = NULL;
}
/* UNLOCK */
fluid_mutex_unlock(heap->mutex);
return evt;
#else
fluid_evt_entry* evt;
if (heap->head == NULL) return NULL;
/* take from head of the heap */
/* critical - should threadlock ? */
evt = heap->head;
heap->head = heap->head->next;
return evt;
#endif
}
void
_fluid_seq_heap_set_free(fluid_evt_heap_t* heap, fluid_evt_entry* evt)
{
#ifdef HEAP_WITH_DYNALLOC
/* LOCK */
fluid_mutex_lock(heap->mutex);
evt->next = heap->freelist;
heap->freelist = evt;
/* UNLOCK */
fluid_mutex_unlock(heap->mutex);
#else
/* append to the end of the heap */
/* critical - should threadlock ? */
heap->tail->next = evt;
heap->tail = evt;
evt->next = NULL;
#endif
}
@@ -0,0 +1,81 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
#ifndef _FLUID_EVENT_PRIV_H
#define _FLUID_EVENT_PRIV_H
#include "fluidsynth.h"
#include "fluid_sys.h"
/* Private data for event */
/* ?? should be optimized in size, using unions */
struct _fluid_event_t {
unsigned int time;
int type;
short src;
short dest;
int channel;
short key;
short vel;
short control;
short value;
short id; //?? unused ?
int pitch;
unsigned int duration;
void* data;
};
unsigned int fluid_event_get_time(fluid_event_t* evt);
void fluid_event_set_time(fluid_event_t* evt, unsigned int time);
/* private data for sorter + heap */
enum fluid_evt_entry_type {
FLUID_EVT_ENTRY_INSERT = 0,
FLUID_EVT_ENTRY_REMOVE
};
typedef struct _fluid_evt_entry fluid_evt_entry;
struct _fluid_evt_entry {
fluid_evt_entry *next;
short entryType;
fluid_event_t evt;
};
#define HEAP_WITH_DYNALLOC 1
/* #undef HEAP_WITH_DYNALLOC */
typedef struct _fluid_evt_heap_t {
#ifdef HEAP_WITH_DYNALLOC
fluid_evt_entry* freelist;
fluid_mutex_t mutex;
#else
fluid_evt_entry* head;
fluid_evt_entry* tail;
fluid_evt_entry pool;
#endif
} fluid_evt_heap_t;
fluid_evt_heap_t* _fluid_evt_heap_init(int nbEvents);
void _fluid_evt_heap_free(fluid_evt_heap_t* heap);
fluid_evt_entry* _fluid_seq_heap_get_free(fluid_evt_heap_t* heap);
void _fluid_seq_heap_set_free(fluid_evt_heap_t* heap, fluid_evt_entry* evt);
#endif /* _FLUID_EVENT_PRIV_H */
+148
View File
@@ -0,0 +1,148 @@
/* 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_gen.h"
#include "fluid_chan.h"
/* See SFSpec21 $8.1.3 */
fluid_gen_info_t fluid_gen_info[] = {
/* number/name init scale min max def */
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
{ GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
{ GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
{ GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
{ GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
{ GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
{ GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
{ GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
{ GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
{ GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
{ GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
{ GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
{ GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
{ GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
{ GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
{ GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
{ GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
{ GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
{ GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
{ GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
{ GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
{ GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
{ GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
{ GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
{ GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
{ GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
{ GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
{ GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f }
};
/* fluid_gen_set_default_values
*
* Set an array of generators to their initial value
*/
int
fluid_gen_set_default_values(fluid_gen_t* gen)
{
int i;
for (i = 0; i < GEN_LAST; i++) {
gen[i].flags = GEN_UNUSED;
gen[i].mod = 0.0;
gen[i].nrpn = 0.0;
gen[i].val = fluid_gen_info[i].def;
}
return FLUID_OK;
}
/* fluid_gen_init
*
* Set an array of generators to their initial value
*/
int
fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel)
{
int i;
fluid_gen_set_default_values(gen);
for (i = 0; i < GEN_LAST; i++) {
gen[i].nrpn = fluid_channel_get_gen(channel, i);
/* This is an extension to the SoundFont standard. More
* documentation is available at the fluid_synth_set_gen2()
* function. */
if (fluid_channel_get_gen_abs(channel, i)) {
gen[i].flags = GEN_ABS_NRPN;
}
}
return FLUID_OK;
}
fluid_real_t fluid_gen_scale(int gen, float value)
{
return (fluid_gen_info[gen].min
+ value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min));
}
fluid_real_t fluid_gen_scale_nrpn(int gen, int data)
{
fluid_real_t value = (float) data - 8192.0f;
fluid_clip(value, -8192, 8192);
return value * (float) fluid_gen_info[gen].nrpn_scale;
}
+44
View File
@@ -0,0 +1,44 @@
/* 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_GEN_H
#define _FLUID_GEN_H
#include "fluidsynth_priv.h"
typedef struct _fluid_gen_info_t {
char num; /* Generator number */
char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
float min; /* The minimum value */
float max; /* The maximum value */
float def; /* The default value (cfr. fluid_gen_set_default_values()) */
} fluid_gen_info_t;
#define fluid_gen_set_mod(_gen, _val) { (_gen)->mod = (double) (_val); }
#define fluid_gen_set_nrpn(_gen, _val) { (_gen)->nrpn = (double) (_val); }
fluid_real_t fluid_gen_scale(int gen, float value);
fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn);
int fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel);
#endif /* _FLUID_GEN_H */
+388
View File
@@ -0,0 +1,388 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
/*
* MT safe
*/
#include "fluidsynth_priv.h"
#include "fluid_hash.h"
#define HASH_TABLE_MIN_SIZE 7
#define HASH_TABLE_MAX_SIZE 13845163
typedef struct _fluid_hashnode_t fluid_hashnode_t;
struct _fluid_hashnode_t {
char* key;
void* value;
int type;
fluid_hashnode_t *next;
};
static fluid_hashnode_t* new_fluid_hashnode(char* key, void* value, int type);
static void delete_fluid_hashnode(fluid_hashnode_t *hash_node, fluid_hash_delete_t del);
static void delete_fluid_hashnodes(fluid_hashnode_t *hash_node, fluid_hash_delete_t del);
struct _fluid_hashtable_t {
unsigned int size;
unsigned int nnodes;
fluid_hashnode_t **nodes;
fluid_hash_delete_t del;
};
#define FLUID_HASHTABLE_RESIZE(hash_table) \
if ((3 * hash_table->size <= hash_table->nnodes) \
&& (hash_table->size < HASH_TABLE_MAX_SIZE)) { \
fluid_hashtable_resize(hash_table); \
}
static void fluid_hashtable_resize(fluid_hashtable_t *hash_table);
static fluid_hashnode_t** fluid_hashtable_lookup_node(fluid_hashtable_t *hash_table, char* key);
/**
* new_fluid_hashtable:
*
* Creates a new #fluid_hashtable_t.
*
* Return value: a new #fluid_hashtable_t.
**/
fluid_hashtable_t*
new_fluid_hashtable(fluid_hash_delete_t del)
{
fluid_hashtable_t *hash_table;
unsigned int i;
hash_table = FLUID_NEW(fluid_hashtable_t);
hash_table->size = HASH_TABLE_MIN_SIZE;
hash_table->nnodes = 0;
hash_table->nodes = FLUID_ARRAY(fluid_hashnode_t*, hash_table->size);
hash_table->del = del;
for (i = 0; i < hash_table->size; i++) {
hash_table->nodes[i] = NULL;
}
return hash_table;
}
/**
* delete_fluid_hashtable:
* @hash_table: a #fluid_hashtable_t.
*
* Destroys the #fluid_hashtable_t. If keys and/or values are dynamically
* allocated, you should either free them first or create the #fluid_hashtable_t
* using fluid_hashtable_new_full(). In the latter case the destroy functions
* you supplied will be called on all keys and values before destroying
* the #fluid_hashtable_t.
**/
void
delete_fluid_hashtable(fluid_hashtable_t *hash_table)
{
unsigned int i;
if (hash_table == NULL) {
return;
}
for (i = 0; i < hash_table->size; i++) {
delete_fluid_hashnodes(hash_table->nodes[i], hash_table->del);
}
FLUID_FREE(hash_table->nodes);
FLUID_FREE(hash_table);
}
static /*inline*/ fluid_hashnode_t**
fluid_hashtable_lookup_node (fluid_hashtable_t* hash_table, char* key)
{
fluid_hashnode_t **node;
node = &hash_table->nodes[fluid_str_hash(key) % hash_table->size];
while (*node && (FLUID_STRCMP((*node)->key, key) != 0)) {
node = &(*node)->next;
}
return node;
}
/**
* fluid_hashtable_lookup:
* @hash_table: a #fluid_hashtable_t.
* @key: the key to look up.
*
* Looks up a key in a #fluid_hashtable_t.
*
* Return value: the associated value, or %NULL if the key is not found.
**/
int
fluid_hashtable_lookup(fluid_hashtable_t *hash_table, char* key, void** value, int* type)
{
fluid_hashnode_t *node;
node = *fluid_hashtable_lookup_node(hash_table, key);
if (node) {
if (value) {
*value = node->value;
}
if (type) {
*type = node->type;
}
return 1;
} else {
return 0;
}
}
/**
* fluid_hashtable_insert:
* @hash_table: a #fluid_hashtable_t.
* @key: a key to insert.
* @value: the value to associate with the key.
*
* Inserts a new key and value into a #fluid_hashtable_t.
*
* If the key already exists in the #fluid_hashtable_t its current value is replaced
* with the new value. If you supplied a @value_destroy_func when creating the
* #fluid_hashtable_t, the old value is freed using that function. If you supplied
* a @key_destroy_func when creating the #fluid_hashtable_t, the passed key is freed
* using that function.
**/
void
fluid_hashtable_insert(fluid_hashtable_t *hash_table, char* key, void* value, int type)
{
fluid_hashnode_t **node;
node = fluid_hashtable_lookup_node(hash_table, key);
if (*node) {
(*node)->value = value;
(*node)->type = type;
} else {
*node = new_fluid_hashnode(key, value, type);
hash_table->nnodes++;
FLUID_HASHTABLE_RESIZE(hash_table);
}
}
/**
* fluid_hashtable_replace:
* @hash_table: a #GHashTable.
* @key: a key to insert.
* @value: the value to associate with the key.
*
* Inserts a new key and value into a #GHashTable similar to
* fluid_hashtable_insert(). The difference is that if the key already exists
* in the #GHashTable, it gets replaced by the new key. If you supplied a
* @value_destroy_func when creating the #GHashTable, the old value is freed
* using that function. If you supplied a @key_destroy_func when creating the
* #GHashTable, the old key is freed using that function.
**/
void
fluid_hashtable_replace(fluid_hashtable_t *hash_table, char* key, void* value, int type)
{
fluid_hashnode_t **node;
node = fluid_hashtable_lookup_node(hash_table, key);
if (*node) {
if (hash_table->del) {
hash_table->del((*node)->value, (*node)->type);
}
(*node)->value = value;
} else {
*node = new_fluid_hashnode(key, value, type);
hash_table->nnodes++;
FLUID_HASHTABLE_RESIZE(hash_table);
}
}
/**
* fluid_hashtable_remove:
* @hash_table: a #fluid_hashtable_t.
* @key: the key to remove.
*
* Removes a key and its associated value from a #fluid_hashtable_t.
*
* If the #fluid_hashtable_t was created using fluid_hashtable_new_full(), the
* key and value are freed using the supplied destroy functions, otherwise
* you have to make sure that any dynamically allocated values are freed
* yourself.
*
* Return value: %TRUE if the key was found and removed from the #fluid_hashtable_t.
**/
int
fluid_hashtable_remove (fluid_hashtable_t *hash_table, char* key)
{
fluid_hashnode_t **node, *dest;
node = fluid_hashtable_lookup_node(hash_table, key);
if (*node) {
dest = *node;
(*node) = dest->next;
delete_fluid_hashnode(dest, hash_table->del);
hash_table->nnodes--;
FLUID_HASHTABLE_RESIZE (hash_table);
return 1;
}
return 0;
}
/**
* fluid_hashtable_foreach:
* @hash_table: a #fluid_hashtable_t.
* @func: the function to call for each key/value pair.
* @user_data: user data to pass to the function.
*
* Calls the given function for each of the key/value pairs in the
* #fluid_hashtable_t. The function is passed the key and value of each
* pair, and the given @user_data parameter. The hash table may not
* be modified while iterating over it (you can't add/remove
* items). To remove all items matching a predicate, use
* fluid_hashtable_remove().
**/
void
fluid_hashtable_foreach(fluid_hashtable_t *hash_table, fluid_hash_iter_t func, void* data)
{
fluid_hashnode_t *node = NULL;
unsigned int i;
for (i = 0; i < hash_table->size; i++) {
for (node = hash_table->nodes[i]; node != NULL; node = node->next) {
(*func)(node->key, node->value, node->type, data);
}
}
}
/**
* fluid_hashtable_size:
* @hash_table: a #fluid_hashtable_t.
*
* Returns the number of elements contained in the #fluid_hashtable_t.
*
* Return value: the number of key/value pairs in the #fluid_hashtable_t.
**/
unsigned int
fluid_hashtable_size(fluid_hashtable_t *hash_table)
{
return hash_table->nnodes;
}
static void
fluid_hashtable_resize(fluid_hashtable_t *hash_table)
{
fluid_hashnode_t **new_nodes;
fluid_hashnode_t *node;
fluid_hashnode_t *next;
unsigned int hash_val;
int new_size;
unsigned int i;
new_size = 3 * hash_table->size + 1;
new_size = (new_size > HASH_TABLE_MAX_SIZE)? HASH_TABLE_MAX_SIZE : new_size;
/* printf("%s: %d: resizing, new size = %d\n", __FILE__, __LINE__, new_size); */
new_nodes = FLUID_ARRAY(fluid_hashnode_t*, new_size);
FLUID_MEMSET(new_nodes, 0, new_size * sizeof(fluid_hashnode_t*));
for (i = 0; i < hash_table->size; i++) {
for (node = hash_table->nodes[i]; node; node = next) {
next = node->next;
hash_val = fluid_str_hash(node->key) % new_size;
node->next = new_nodes[hash_val];
new_nodes[hash_val] = node;
}
}
FLUID_FREE(hash_table->nodes);
hash_table->nodes = new_nodes;
hash_table->size = new_size;
}
static fluid_hashnode_t*
new_fluid_hashnode(char* key, void* value, int type)
{
fluid_hashnode_t *hash_node;
hash_node = FLUID_NEW(fluid_hashnode_t);
hash_node->key = FLUID_STRDUP(key);
hash_node->value = value;
hash_node->type = type;
hash_node->next = NULL;
return hash_node;
}
static void
delete_fluid_hashnode(fluid_hashnode_t *hash_node, fluid_hash_delete_t del)
{
if (del) {
(*del)(hash_node->value, hash_node->type);
}
if (hash_node->key) {
FLUID_FREE(hash_node->key);
}
FLUID_FREE(hash_node);
}
static void
delete_fluid_hashnodes(fluid_hashnode_t *hash_node, fluid_hash_delete_t del)
{
while (hash_node) {
fluid_hashnode_t *next = hash_node->next;
delete_fluid_hashnode(hash_node, del);
hash_node = next;
}
}
/* 31 bit hash function */
unsigned int
fluid_str_hash(char* key)
{
char *p = key;
unsigned int h = *p;
if (h) {
for (p += 1; *p != '\0'; p++) {
h = (h << 5) - h + *p;
}
}
return h;
}
+64
View File
@@ -0,0 +1,64 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
/*
* Demolished by Peter Hanappe [December 2002]
*
* - only string as key
* - stores additional type info
* - removed use of GLib types (gpointer, gint, ...)
* - reduced the number of API functions
* - changed names to fluid_hashtable_...
*/
#ifndef _FLUID_HASH_H
#define _FLUID_HASH_H
typedef int (*fluid_hash_iter_t)(char* key, void* value, int type, void* data);
typedef void (*fluid_hash_delete_t)(void* value, int type);
fluid_hashtable_t* new_fluid_hashtable(fluid_hash_delete_t delete);
void delete_fluid_hashtable(fluid_hashtable_t *hash_table);
void fluid_hashtable_insert(fluid_hashtable_t *hash_table, char* key, void* value, int type);
void fluid_hashtable_replace(fluid_hashtable_t *hash_table, char* key, void* value, int type);
/* Returns non-zero if found, 0 if not found */
int fluid_hashtable_lookup(fluid_hashtable_t *hash_table, char* key, void** value, int* type);
/* Returns non-zero if removed, 0 if not removed */
int fluid_hashtable_remove(fluid_hashtable_t *hash_table, char* key);
void fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hash_iter_t fun, void* data);
unsigned int fluid_hashtable_size(fluid_hashtable_t *hash_table);
unsigned int fluid_str_hash(char* v);
#endif /* _FLUID_HASH_H */
+121
View File
@@ -0,0 +1,121 @@
/* 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 "fluidsynth_priv.h"
#include "fluid_io.h"
#if WITH_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
int fluid_istream_gets(fluid_istream_t in, char* buf, int len);
fluid_istream_t fluid_get_stdin()
{
#ifdef MACOS9
return 0; /* to be tested - Antoine 8/3/3 */
#else
return STDIN_FILENO;
#endif
}
fluid_ostream_t fluid_get_stdout()
{
#ifdef MACOS9
return 1; /* to be tested - Antoine 8/3/3 */
#else
return STDOUT_FILENO;
#endif
}
int fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len)
{
#if WITH_READLINE
if (in == fluid_get_stdin()) {
char* line;
line = readline(prompt);
if (line == NULL) {
return -1;
}
snprintf(buf, len, "%s", line);
buf[len - 1] = 0;
free(line);
return 1;
} else {
return fluid_istream_gets(in, buf, len);
}
#else
return fluid_istream_gets(in, buf, len);
#endif
}
/* FIXME */
int fluid_istream_gets(fluid_istream_t in, char* buf, int len)
{
char c;
int n;
buf[len - 1] = 0;
while (--len > 0) {
n = read(in, &c, 1);
if (n == 0) {
*buf++ = 0;
return 0;
}
if (n < 0) {
return n;
}
if ((c == '\n') || (c == '\r')) {
*buf++ = 0;
return 1;
}
*buf++ = c;
}
return -1;
}
int fluid_ostream_printf(fluid_ostream_t out, char* format, ...)
{
char buf[4096];
va_list args;
int len;
va_start(args, format);
len = vsnprintf(buf, 4095, format, args);
va_end(args);
if (len <= 0) {
printf("fluid_ostream_printf: buffer overflow");
return -1;
}
buf[4095] = 0;
/* return write(out, buf, len); */
return write(out, buf, strlen(buf));
}
+42
View File
@@ -0,0 +1,42 @@
/* 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_IO_H
#define _FLUID_IO_H
/** Read a line from the input stream.
\returns 0 if end-of-stream, -1 if error, non zero otherwise
*/
int fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len);
/** Read a line from the input stream.
\returns The number of bytes written. If an error occured, -1 is
returned.
*/
int fluid_ostream_printf(fluid_ostream_t out, char* format, ...);
#endif /* _FLUID_IO_H */
File diff suppressed because it is too large Load Diff
+240
View File
@@ -0,0 +1,240 @@
/* 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
*/
/* Author: Markus Nentwig, [email protected]
*/
#ifndef _FLUID_LADSPA_H
#define _FLUID_LADSPA_H
/***************************************************************
*
* INCLUDES
*/
#include "fluidsynth_priv.h"
#ifdef LADSPA
#include "fluid_list.h"
#include <pthread.h>
#include <ladspa.h>
/***************************************************************
*
* DEFINES
*/
/* How many different plugin libraries may be used at the same time? */
#define FLUID_LADSPA_MaxLibs 100
/* How many plugin instances may be used at the same time? */
#define FLUID_LADSPA_MaxPlugins 100
/* How many nodes are allowed? */
#define FLUID_LADSPA_MaxNodes 100
/* How many tokens are allowed in one command line? (for example 152 => max. 50 port plugin allowed) */
#define FLUID_LADSPA_MaxTokens 152
/* What is the maximum path length? */
#define FLUID_LADSPA_MaxPathLength 512
/***************************************************************
*
* ENUM
*/
typedef enum {
fluid_LADSPA_NoMatch,
fluid_LADSPA_PartialMatch,
fluid_LADSPA_FullMatch
} fluid_LADSPA_Stringmatch_t;
/* Bypass state of the Fx unit */
typedef enum {
fluid_LADSPA_Active,
fluid_LADSPA_Bypassed,
fluid_LADSPA_BypassRequest
} fluid_LADSPA_BypassState;
typedef enum {
fluid_LADSPA_node_is_source=1,
fluid_LADSPA_node_is_sink=2,
fluid_LADSPA_node_is_audio=4,
fluid_LADSPA_node_is_control=8,
fluid_LADSPA_node_is_dummy=16,
fluid_LADSPA_node_is_user_ctrl=32
} fluid_LADSPA_nodeflags;
/* fluid_LADSPA_Node_t
* An internal node of the Fx unit.
* A 'node' is the 'glue' that connects several LADSPA plugins.
* Basically it's a real-valued variable (control node) or a real-valued buffer (audio node).
*/
typedef struct {
LADSPA_Data * buf; /*Either the buffer (Audio node) or a single control value (Control node)*/
char * Name; /* Unique identifier*/
int InCount; /* How many sources feed into this node? (0 or 1) */
int OutCount; /* How many other elements take data out of this node? */
int flags;
} fluid_LADSPA_Node_t;
/*
* fluid_LADSPA_Fx_t
* Fx unit using LADSPA.
* This includes a number of LADSPA plugins, their libraries, nodes etc.
* The Fx unit connects its input to Fluidsynth and its output to the soundcard.
*/
typedef struct {
/* LADSPA-plugins are in shared libraries (for example aw.so).
* Pointers to them are stored here. A library is uniquely identified through
* its filename (full path).*/
fluid_synth_t* synth;
int NumberLibs;
void * ppvPluginLibs[FLUID_LADSPA_MaxLibs];
char * ppvPluginLibNames[FLUID_LADSPA_MaxLibs];
/*List of plugins (descriptor and instance)
* A LADSPA plugin descriptor points to the code, which is executed, when a plugin is run.
* The plugin instance is given as a parameter, when calling.
*/
int NumberPlugins;
const LADSPA_Descriptor * PluginDescriptorTable[FLUID_LADSPA_MaxPlugins];
LADSPA_Handle * PluginInstanceTable[FLUID_LADSPA_MaxPlugins];
/* List of nodes */
int NumberNodes;
fluid_LADSPA_Node_t * Nodelist[FLUID_LADSPA_MaxNodes];
/* List of Command lines
* During the setup phase, each ladspa_add command creates one command sequence. For example:
* ./aw.so alienwah_stereo Input <- Master_L_Synth Output -> Master_R_Synth Parameter <- #42.0
* Those lists are stored in LADSPA_Command_Sequence.
* One command line results in one plugin => size MaxPlugins.
*/
int NumberCommands;
char ** LADSPA_Command_Sequence[FLUID_LADSPA_MaxPlugins];
/* User control nodes
* A user control node is declared at any time before the ladspa_start command.
* It acts as a constant node, but it has a name and can be changed with the ladspa_nodeset command. */
int NumberUserControlNodes;
char * UserControlNodeNames[FLUID_LADSPA_MaxNodes];
fluid_real_t UserControlNodeValues[FLUID_LADSPA_MaxNodes];
/* Bypass switch
* If set, the LADSPA Fx unit does not touch the signal.*/
fluid_LADSPA_BypassState Bypass;
/* Communication between the 'command line' process and the synthesis process.
* A possible conflict situation arises, when fluid_clear is called, and starts to destroy
* the plugins. But the synthesis thread still processes plugins at the same time. The consequences are ugly.
* Therefore ladspa_clear waits for acknowledgement from the synthesis thread, that the Fx unit is bypassed.
* 'cond' is used for the communication, the mutex is required for changing the condition.
*/
pthread_cond_t cond;
pthread_mutex_t mutex;
} fluid_LADSPA_FxUnit_t;
/*
* misc
*/
/* Purpose:
* Creates a new Fx unit in bypass mode with default settings.
* It is ready for further calls (add, clear, start).
*/
fluid_LADSPA_FxUnit_t* new_fluid_LADSPA_FxUnit(fluid_synth_t* synth);
/* Purpose:
* Applies the master gain (from command line option --gain or gain command).
* Processes one block of sound data (generated from the synthesizer) through
* the LADSPA Fx unit.
* Acknowledges a bypass request.
*/
void fluid_LADSPA_run(fluid_LADSPA_FxUnit_t* Fx_unit, fluid_real_t* left_buf[], fluid_real_t* right_buf[], fluid_real_t* fx_left_buf[], fluid_real_t* fx_right_buf[]);
/* Purpose:
* Returns the node belonging to Name or NULL, if not found
*/
fluid_LADSPA_Node_t* fluid_LADSPA_RetrieveNode(fluid_LADSPA_FxUnit_t* FxUnit, char * Name);
/* Purpose:
* Creates a new node with the given characteristics.
*/
fluid_LADSPA_Node_t* fluid_LADSPA_CreateNode(fluid_LADSPA_FxUnit_t* FxUnit, char * Name, int flags);
/* Purpose:
* - Resets LADSPA Fx unit to bypass.
* - Removes all plugins from the reverb unit.
* - Releases all libraries.
* Note: It would be more efficient to keep the libraries. But then the user would have to restart fluidsynth each time
* a plugin is recompiled.
*/
void fluid_LADSPA_clear(fluid_LADSPA_FxUnit_t* FxUnit);
/* Purpose:
* Frees all memory and shuts down the Fx block.
* The synthesis thread must be stopped, when calling.
*/
void fluid_LADSPA_shutdown(fluid_LADSPA_FxUnit_t* FxUnit);
/*
* fluid_handle_LADSPA_XXX
* Those functions are called from fluid_cmd, when a command is entered on the command line.
*/
/* Purpose:
* - Resets LADSPA Fx unit to bypass.
* - Removes all plugins from the reverb unit.
* - Releases all libraries.
* Note: It would be more efficient to keep the libraries. But then the user would have to restart fluidsynth each time
* a plugin is recompiled.
*/
int fluid_LADSPA_handle_clear(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
/* Purpose:
* Loads the plugins added with 'ladspa_add' and then start the Fx unit.
* Internal processes:
* - load the LADSPA plugin libraries
* - instantiate the plugins
* - connect the plugins
* - set the bypass switch to 'not bypassed'
*/
int fluid_LADSPA_handle_start(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
/* Purpose:
* Adds one plugin into the list of the LADSPA Fx unit.
* This is only allowed, while the Fx block is in 'bypass' state (after clear).
*/
int fluid_LADSPA_handle_add(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
/* Purpose:
* Declares a user control node and a value; for further processing in ladspa_start.
*/
int fluid_LADSPA_handle_declnode(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
/* Purpose:
* Assigns a value to the a user control node
*/
int fluid_LADSPA_handle_setnode(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
#endif /* LADSPA */
#endif /* _FLUID_LADSPA_H */
+300
View File
@@ -0,0 +1,300 @@
/* 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_lash.h"
#include "fluid_synth.h"
#include <unistd.h> /* for usleep() */
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
static void fluid_lash_save (fluid_synth_t * synth);
static void fluid_lash_load (fluid_synth_t * synth, const char * filename);
static void *fluid_lash_run (void * data);
/*
* lash client - this symbol needs to be in the library else
* all clients would need a fluid_lash_client symbol.
*/
#ifdef HAVE_LASH
lash_client_t * fluid_lash_client;
#else
cca_client_t * fluid_lash_client;
#endif
static pthread_t fluid_lash_thread;
#ifdef HAVE_LASH
fluid_lash_args_t *
fluid_lash_extract_args (int * pargc, char *** pargv)
{
return lash_extract_args (pargc, pargv);
}
int
fluid_lash_connect (fluid_lash_args_t * args)
{
fluid_lash_client = lash_init (args, PACKAGE, LASH_Config_Data_Set | LASH_Terminal, LASH_PROTOCOL (2,0));
return fluid_lash_client && lash_enabled (fluid_lash_client);
}
void
fluid_lash_create_thread (fluid_synth_t * synth)
{
pthread_create (&fluid_lash_thread, NULL, fluid_lash_run, synth);
}
static void
fluid_lash_save (fluid_synth_t * synth)
{
int i;
int sfcount;
fluid_sfont_t * sfont;
lash_config_t * config;
char num[32];
sfcount = fluid_synth_sfcount (synth);
config = lash_config_new ();
lash_config_set_key (config, "soundfont count");
lash_config_set_value_int (config, sfcount);
lash_send_config (fluid_lash_client, config);
for (i = sfcount - 1; i >= 0; i--)
{
sfont = fluid_synth_get_sfont (synth, i);
config = lash_config_new ();
sprintf (num, "%d", i);
lash_config_set_key (config, num);
lash_config_set_value_string (config, sfont->get_name (sfont));
lash_send_config (fluid_lash_client, config);
}
}
static void
fluid_lash_load (fluid_synth_t * synth, const char * filename)
{
fluid_synth_sfload (synth, filename, 1);
}
static void *
fluid_lash_run (void * data)
{
lash_event_t * event;
lash_config_t * config;
fluid_synth_t * synth;
int done = 0;
int err;
int pending_restores = 0;
synth = (fluid_synth_t *) data;
while (!done)
{
while ( (event = lash_get_event (fluid_lash_client)) )
{
switch (lash_event_get_type (event))
{
case LASH_Save_Data_Set:
fluid_lash_save (synth);
lash_send_event (fluid_lash_client, event);
break;
case LASH_Restore_Data_Set:
lash_event_destroy (event);
break;
case LASH_Quit:
err = kill (getpid(), SIGQUIT);
if (err)
fprintf (stderr, "%s: error sending signal: %s",
__FUNCTION__, strerror (errno));
lash_event_destroy (event);
done = 1;
break;
case LASH_Server_Lost:
lash_event_destroy (event);
done = 1;
break;
default:
fprintf (stderr, "Recieved unknown LASH event of type %d\n", lash_event_get_type (event));
lash_event_destroy (event);
break;
}
}
while ( (config = lash_get_config (fluid_lash_client)) )
{
if (strcmp (lash_config_get_key (config), "soundfont count") == 0)
pending_restores = lash_config_get_value_int (config);
else
{
fluid_lash_load (synth, lash_config_get_value_string (config));
pending_restores--;
}
lash_config_destroy (config);
if (!pending_restores)
{
event = lash_event_new_with_type (LASH_Restore_Data_Set);
lash_send_event (fluid_lash_client, event);
}
}
usleep (10000);
}
return NULL;
}
#else /* depricated LADCCA support, will remove someday */
fluid_lash_args_t *
fluid_lash_extract_args (int * pargc, char *** pargv)
{
return cca_extract_args (pargc, pargv);
}
int
fluid_lash_connect (fluid_lash_args_t * args)
{
fluid_lash_client = cca_init (args, PACKAGE, CCA_Config_Data_Set | CCA_Terminal, CCA_PROTOCOL (2,0));
return fluid_lash_client && cca_enabled (fluid_lash_client);
}
void
fluid_lash_create_thread (fluid_synth_t * synth)
{
pthread_create (&fluid_lash_thread, NULL, fluid_lash_run, synth);
}
static void
fluid_lash_save (fluid_synth_t * synth)
{
int i;
int sfcount;
fluid_sfont_t * sfont;
cca_config_t * config;
char num[32];
sfcount = fluid_synth_sfcount (synth);
config = cca_config_new ();
cca_config_set_key (config, "soundfont count");
cca_config_set_value_int (config, sfcount);
cca_send_config (fluid_lash_client, config);
for (i = sfcount - 1; i >= 0; i--)
{
sfont = fluid_synth_get_sfont (synth, i);
config = cca_config_new ();
sprintf (num, "%d", i);
cca_config_set_key (config, num);
cca_config_set_value_string (config, sfont->get_name (sfont));
cca_send_config (fluid_lash_client, config);
}
}
static void
fluid_lash_load (fluid_synth_t * synth, const char * filename)
{
fluid_synth_sfload (synth, filename, 1);
}
/* LADCCA thread */
static void *
fluid_lash_run (void * data)
{
cca_event_t * event;
cca_config_t * config;
fluid_synth_t * synth;
int done = 0;
int err;
int pending_restores = 0;
synth = (fluid_synth_t *) data;
while (!done)
{
while ( (event = cca_get_event (fluid_lash_client)) )
{
switch (cca_event_get_type (event))
{
case CCA_Save_Data_Set:
fluid_lash_save (synth);
cca_send_event (fluid_lash_client, event);
break;
case CCA_Restore_Data_Set:
cca_event_destroy (event);
break;
case CCA_Quit:
err = kill (getpid(), SIGQUIT);
if (err)
fprintf (stderr, "%s: error sending signal: %s",
__FUNCTION__, strerror (errno));
cca_event_destroy (event);
done = 1;
break;
case CCA_Server_Lost:
cca_event_destroy (event);
done = 1;
break;
default:
fprintf (stderr, "Recieved unknown LADCCA event of type %d\n", cca_event_get_type (event));
cca_event_destroy (event);
break;
}
}
while ( (config = cca_get_config (fluid_lash_client)) )
{
if (strcmp (cca_config_get_key (config), "soundfont count") == 0)
pending_restores = cca_config_get_value_int (config);
else
{
fluid_lash_load (synth, cca_config_get_value_string (config));
pending_restores--;
}
cca_config_destroy (config);
if (!pending_restores)
{
event = cca_event_new_with_type (CCA_Restore_Data_Set);
cca_send_event (fluid_lash_client, event);
}
}
usleep (10000);
}
return NULL;
}
#endif /* #if HAVE_LASH #else */
+51
View File
@@ -0,0 +1,51 @@
/* 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 "config.h"
#if defined(HAVE_LASH) || defined(HAVE_LADCCA)
#include "fluid_synth.h"
#define LASH_ENABLED 1
#ifdef HAVE_LASH
#include <lash/lash.h>
extern lash_client_t * fluid_lash_client;
#define fluid_lash_args_t lash_args_t
#define fluid_lash_alsa_client_id lash_alsa_client_id
#define fluid_lash_jack_client_name lash_jack_client_name
#else /* old depricated LADCCA support which will be removed someday */
#include <ladcca/ladcca.h>
extern cca_client_t * fluid_lash_client;
#define fluid_lash_args_t cca_args_t
#define fluid_lash_alsa_client_id cca_alsa_client_id
#define fluid_lash_jack_client_name cca_jack_client_name
#endif
fluid_lash_args_t *fluid_lash_extract_args (int * pargc, char *** pargv);
int fluid_lash_connect (fluid_lash_args_t * args);
void fluid_lash_create_thread (fluid_synth_t * synth);
#endif /* defined(HAVE_LASH) || defined(HAVE_LADCCA) */
+257
View File
@@ -0,0 +1,257 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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 Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GLib Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "fluid_list.h"
fluid_list_t*
new_fluid_list(void)
{
fluid_list_t* list;
list = (fluid_list_t*) FLUID_MALLOC(sizeof(fluid_list_t));
list->data = NULL;
list->next = NULL;
return list;
}
void
delete_fluid_list(fluid_list_t *list)
{
fluid_list_t *next;
while (list) {
next = list->next;
FLUID_FREE(list);
list = next;
}
}
void
delete1_fluid_list(fluid_list_t *list)
{
if (list) {
FLUID_FREE(list);
}
}
fluid_list_t*
fluid_list_append(fluid_list_t *list, void* data)
{
fluid_list_t *new_list;
fluid_list_t *last;
new_list = new_fluid_list();
new_list->data = data;
if (list)
{
last = fluid_list_last(list);
/* g_assert (last != NULL); */
last->next = new_list;
return list;
}
else
return new_list;
}
fluid_list_t*
fluid_list_prepend(fluid_list_t *list, void* data)
{
fluid_list_t *new_list;
new_list = new_fluid_list();
new_list->data = data;
new_list->next = list;
return new_list;
}
fluid_list_t*
fluid_list_nth(fluid_list_t *list, int n)
{
while ((n-- > 0) && list) {
list = list->next;
}
return list;
}
fluid_list_t*
fluid_list_remove(fluid_list_t *list, void* data)
{
fluid_list_t *tmp;
fluid_list_t *prev;
prev = NULL;
tmp = list;
while (tmp) {
if (tmp->data == data) {
if (prev) {
prev->next = tmp->next;
}
if (list == tmp) {
list = list->next;
}
tmp->next = NULL;
delete_fluid_list(tmp);
break;
}
prev = tmp;
tmp = tmp->next;
}
return list;
}
fluid_list_t*
fluid_list_remove_link(fluid_list_t *list, fluid_list_t *link)
{
fluid_list_t *tmp;
fluid_list_t *prev;
prev = NULL;
tmp = list;
while (tmp) {
if (tmp == link) {
if (prev) {
prev->next = tmp->next;
}
if (list == tmp) {
list = list->next;
}
tmp->next = NULL;
break;
}
prev = tmp;
tmp = tmp->next;
}
return list;
}
static fluid_list_t*
fluid_list_sort_merge(fluid_list_t *l1, fluid_list_t *l2, fluid_compare_func_t compare_func)
{
fluid_list_t list, *l;
l = &list;
while (l1 && l2) {
if (compare_func(l1->data,l2->data) < 0) {
l = l->next = l1;
l1 = l1->next;
} else {
l = l->next = l2;
l2 = l2->next;
}
}
l->next= l1 ? l1 : l2;
return list.next;
}
fluid_list_t*
fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func)
{
fluid_list_t *l1, *l2;
if (!list) {
return NULL;
}
if (!list->next) {
return list;
}
l1 = list;
l2 = list->next;
while ((l2 = l2->next) != NULL) {
if ((l2 = l2->next) == NULL)
break;
l1=l1->next;
}
l2 = l1->next;
l1->next = NULL;
return fluid_list_sort_merge(fluid_list_sort(list, compare_func),
fluid_list_sort(l2, compare_func),
compare_func);
}
fluid_list_t*
fluid_list_last(fluid_list_t *list)
{
if (list) {
while (list->next)
list = list->next;
}
return list;
}
int
fluid_list_size(fluid_list_t *list)
{
int n = 0;
while (list) {
n++;
list = list->next;
}
return n;
}
fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data)
{
fluid_list_t *new_list;
fluid_list_t *cur;
fluid_list_t *prev = NULL;
new_list = new_fluid_list();
new_list->data = data;
cur = list;
while ((n-- > 0) && cur) {
prev = cur;
cur = cur->next;
}
new_list->next = cur;
if (prev) {
prev->next = new_list;
return list;
} else {
return new_list;
}
}
+61
View File
@@ -0,0 +1,61 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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 Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef _FLUID_LIST_H
#define _FLUID_LIST_H
#include "fluidsynth_priv.h"
/*
*
* Lists
*
* A sound font loader has to pack the data from the .SF2 file into
* list structures of this type.
*
*/
typedef struct _fluid_list_t fluid_list_t;
typedef int (*fluid_compare_func_t)(void* a, void* b);
struct _fluid_list_t
{
void* data;
fluid_list_t *next;
};
fluid_list_t* new_fluid_list(void);
void delete_fluid_list(fluid_list_t *list);
void delete1_fluid_list(fluid_list_t *list);
fluid_list_t* fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func);
fluid_list_t* fluid_list_append(fluid_list_t *list, void* data);
fluid_list_t* fluid_list_prepend(fluid_list_t *list, void* data);
fluid_list_t* fluid_list_remove(fluid_list_t *list, void* data);
fluid_list_t* fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink);
fluid_list_t* fluid_list_nth(fluid_list_t *list, int n);
fluid_list_t* fluid_list_last(fluid_list_t *list);
fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data);
int fluid_list_size(fluid_list_t *list);
#define fluid_list_next(slist) ((slist) ? (((fluid_list_t *)(slist))->next) : NULL)
#define fluid_list_get(slist) ((slist) ? ((slist)->data) : NULL)
#endif /* _FLUID_LIST_H */
+184
View File
@@ -0,0 +1,184 @@
/* 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_mdriver.h"
#include "fluid_settings.h"
/* ALSA */
#if ALSA_SUPPORT
fluid_midi_driver_t* new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler,
void* event_handler_data);
int delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p);
void fluid_alsa_rawmidi_driver_settings(fluid_settings_t* settings);
fluid_midi_driver_t* new_fluid_alsa_seq_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler,
void* event_handler_data);
int delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p);
void fluid_alsa_seq_driver_settings(fluid_settings_t* settings);
#endif
/* OSS */
#if OSS_SUPPORT
fluid_midi_driver_t* new_fluid_oss_midi_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler,
void* event_handler_data);
int delete_fluid_oss_midi_driver(fluid_midi_driver_t* p);
void fluid_oss_midi_driver_settings(fluid_settings_t* settings);
#endif
/* Windows MIDI service */
#if WINMIDI_SUPPORT
fluid_midi_driver_t* new_fluid_winmidi_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler,
void* event_handler_data);
int delete_fluid_winmidi_driver(fluid_midi_driver_t* p);
#endif
/* definitions for the MidiShare driver */
#if MIDISHARE_SUPPORT
fluid_midi_driver_t* new_fluid_midishare_midi_driver(fluid_settings_t* settings,
void* event_handler_data,
handle_midi_event_func_t handler);
int delete_fluid_midishare_midi_driver(fluid_midi_driver_t* p);
#endif
/*
* fluid_mdriver_definition
*/
struct fluid_mdriver_definition_t {
char* name;
fluid_midi_driver_t* (*new)(fluid_settings_t* settings,
handle_midi_event_func_t event_handler,
void* event_handler_data);
int (*free)(fluid_midi_driver_t* p);
void (*settings)(fluid_settings_t* settings);
};
struct fluid_mdriver_definition_t fluid_midi_drivers[] = {
#if OSS_SUPPORT
{ "oss",
new_fluid_oss_midi_driver,
delete_fluid_oss_midi_driver,
fluid_oss_midi_driver_settings },
#endif
#if ALSA_SUPPORT
{ "alsa_raw",
new_fluid_alsa_rawmidi_driver,
delete_fluid_alsa_rawmidi_driver,
fluid_alsa_rawmidi_driver_settings },
{ "alsa_seq",
new_fluid_alsa_seq_driver,
delete_fluid_alsa_seq_driver,
fluid_alsa_seq_driver_settings },
#endif
#if WINMIDI_SUPPORT
{ "winmidi",
new_fluid_winmidi_driver,
delete_fluid_winmidi_driver,
NULL },
#endif
#if MIDISHARE_SUPPORT
{ "midishare",
new_fluid_midishare_midi_driver,
delete_fluid_midishare_midi_driver,
NULL },
#endif
{ NULL, NULL, NULL, NULL }
};
void fluid_midi_driver_settings(fluid_settings_t* settings)
{
int i;
/* Set the default driver */
#if ALSA_SUPPORT
fluid_settings_register_str(settings, "midi.driver", "alsa_seq", 0, NULL, NULL);
#elif OSS_SUPPORT
fluid_settings_register_str(settings, "midi.driver", "oss", 0, NULL, NULL);
#elif WINMIDI_SUPPORT
fluid_settings_register_str(settings, "midi.driver", "winmidi", 0, NULL, NULL);
#elif MIDISHARE_SUPPORT
fluid_settings_register_str(settings, "midi.driver", "midishare", 0, NULL, NULL);
#else
fluid_settings_register_str(settings, "midi.driver", "", 0, NULL, NULL);
#endif
/* Add all drivers to the list of options */
#if ALSA_SUPPORT
fluid_settings_add_option(settings, "midi.driver", "alsa_seq");
fluid_settings_add_option(settings, "midi.driver", "alsa_raw");
#endif
#if OSS_SUPPORT
fluid_settings_add_option(settings, "midi.driver", "oss");
#endif
#if WINMIDI_SUPPORT
fluid_settings_add_option(settings, "midi.driver", "winmidi");
#endif
#if MIDISHARE_SUPPORT
fluid_settings_add_option(settings, "midi.driver", "midishare");
#endif
for (i = 0; fluid_midi_drivers[i].name != NULL; i++) {
if (fluid_midi_drivers[i].settings != NULL) {
fluid_midi_drivers[i].settings(settings);
}
}
}
fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings, handle_midi_event_func_t handler, void* event_handler_data)
{
int i;
fluid_midi_driver_t* driver = NULL;
for (i = 0; fluid_midi_drivers[i].name != NULL; i++) {
if (fluid_settings_str_equal(settings, "midi.driver", fluid_midi_drivers[i].name)) {
FLUID_LOG(FLUID_DBG, "Using '%s' midi driver", fluid_midi_drivers[i].name);
driver = fluid_midi_drivers[i].new(settings, handler, event_handler_data);
if (driver) {
driver->name = fluid_midi_drivers[i].name;
}
return driver;
}
}
FLUID_LOG(FLUID_ERR, "Couldn't find the requested midi driver");
return NULL;
}
void delete_fluid_midi_driver(fluid_midi_driver_t* driver)
{
int i;
for (i = 0; fluid_midi_drivers[i].name != NULL; i++) {
if (fluid_midi_drivers[i].name == driver->name) {
fluid_midi_drivers[i].free(driver);
return;
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/* 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_MDRIVER_H
#define _FLUID_MDRIVER_H
#include "fluidsynth_priv.h"
void fluid_midi_driver_settings(fluid_settings_t* settings);
/*
* fluid_midi_driver_t
*/
struct _fluid_midi_driver_t
{
char* name;
handle_midi_event_func_t handler;
void* data;
};
#endif /* _FLUID_AUDRIVER_H */
File diff suppressed because it is too large Load Diff
+324
View File
@@ -0,0 +1,324 @@
/* 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_MIDI_H
#define _FLUID_MIDI_H
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
#include "fluid_list.h"
typedef struct _fluid_midi_parser_t fluid_midi_parser_t;
fluid_midi_parser_t* new_fluid_midi_parser(void);
int delete_fluid_midi_parser(fluid_midi_parser_t* parser);
fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c);
int fluid_midi_send_event(fluid_synth_t* synth, fluid_player_t* player, fluid_midi_event_t* evt);
/***************************************************************
*
* CONSTANTS & ENUM
*/
#define MAX_NUMBER_OF_TRACKS 128
enum fluid_midi_event_type {
/* channel messages */
NOTE_OFF = 0x80,
NOTE_ON = 0x90,
KEY_PRESSURE = 0xa0,
CONTROL_CHANGE = 0xb0,
PROGRAM_CHANGE = 0xc0,
CHANNEL_PRESSURE = 0xd0,
PITCH_BEND = 0xe0,
/* system exclusive */
MIDI_SYSEX = 0xf0,
/* system common - never in midi files */
MIDI_TIME_CODE = 0xf1,
MIDI_SONG_POSITION = 0xf2,
MIDI_SONG_SELECT = 0xf3,
MIDI_TUNE_REQUEST = 0xf6,
MIDI_EOX = 0xf7,
/* system real-time - never in midi files */
MIDI_SYNC = 0xf8,
MIDI_TICK = 0xf9,
MIDI_START = 0xfa,
MIDI_CONTINUE = 0xfb,
MIDI_STOP = 0xfc,
MIDI_ACTIVE_SENSING = 0xfe,
MIDI_SYSTEM_RESET = 0xff,
/* meta event - for midi files only */
MIDI_META_EVENT = 0xff
};
enum fluid_midi_control_change {
BANK_SELECT_MSB = 0x00,
MODULATION_MSB = 0x01,
BREATH_MSB = 0x02,
FOOT_MSB = 0x04,
PORTAMENTO_TIME_MSB = 0x05,
DATA_ENTRY_MSB = 0x06,
VOLUME_MSB = 0x07,
BALANCE_MSB = 0x08,
PAN_MSB = 0x0A,
EXPRESSION_MSB = 0x0B,
EFFECTS1_MSB = 0x0C,
EFFECTS2_MSB = 0x0D,
GPC1_MSB = 0x10, /* general purpose controller */
GPC2_MSB = 0x11,
GPC3_MSB = 0x12,
GPC4_MSB = 0x13,
BANK_SELECT_LSB = 0x20,
MODULATION_WHEEL_LSB = 0x21,
BREATH_LSB = 0x22,
FOOT_LSB = 0x24,
PORTAMENTO_TIME_LSB = 0x25,
DATA_ENTRY_LSB = 0x26,
VOLUME_LSB = 0x27,
BALANCE_LSB = 0x28,
PAN_LSB = 0x2A,
EXPRESSION_LSB = 0x2B,
EFFECTS1_LSB = 0x2C,
EFFECTS2_LSB = 0x2D,
GPC1_LSB = 0x30,
GPC2_LSB = 0x31,
GPC3_LSB = 0x32,
GPC4_LSB = 0x33,
SUSTAIN_SWITCH = 0x40,
PORTAMENTO_SWITCH = 0x41,
SOSTENUTO_SWITCH = 0x42,
SOFT_PEDAL_SWITCH = 0x43,
LEGATO_SWITCH = 0x45,
HOLD2_SWITCH = 0x45,
SOUND_CTRL1 = 0x46,
SOUND_CTRL2 = 0x47,
SOUND_CTRL3 = 0x48,
SOUND_CTRL4 = 0x49,
SOUND_CTRL5 = 0x4A,
SOUND_CTRL6 = 0x4B,
SOUND_CTRL7 = 0x4C,
SOUND_CTRL8 = 0x4D,
SOUND_CTRL9 = 0x4E,
SOUND_CTRL10 = 0x4F,
GPC5 = 0x50,
GPC6 = 0x51,
GPC7 = 0x52,
GPC8 = 0x53,
PORTAMENTO_CTRL = 0x54,
EFFECTS_DEPTH1 = 0x5B,
EFFECTS_DEPTH2 = 0x5C,
EFFECTS_DEPTH3 = 0x5D,
EFFECTS_DEPTH4 = 0x5E,
EFFECTS_DEPTH5 = 0x5F,
DATA_ENTRY_INCR = 0x60,
DATA_ENTRY_DECR = 0x61,
NRPN_LSB = 0x62,
NRPN_MSB = 0x63,
RPN_LSB = 0x64,
RPN_MSB = 0x65,
ALL_SOUND_OFF = 0x78,
ALL_CTRL_OFF = 0x79,
LOCAL_CONTROL = 0x7A,
ALL_NOTES_OFF = 0x7B,
OMNI_OFF = 0x7C,
OMNI_ON = 0x7D,
POLY_OFF = 0x7E,
POLY_ON = 0x7F
};
enum midi_meta_event {
MIDI_COPYRIGHT = 0x02,
MIDI_TRACK_NAME = 0x03,
MIDI_INST_NAME = 0x04,
MIDI_LYRIC = 0x05,
MIDI_MARKER = 0x06,
MIDI_CUE_POINT = 0x07,
MIDI_EOT = 0x2f,
MIDI_SET_TEMPO = 0x51,
MIDI_SMPTE_OFFSET = 0x54,
MIDI_TIME_SIGNATURE = 0x58,
MIDI_KEY_SIGNATURE = 0x59,
MIDI_SEQUENCER_EVENT = 0x7f
};
enum fluid_player_status
{
FLUID_PLAYER_READY,
FLUID_PLAYER_PLAYING,
FLUID_PLAYER_DONE
};
enum fluid_driver_status
{
FLUID_MIDI_READY,
FLUID_MIDI_LISTENING,
FLUID_MIDI_DONE
};
/***************************************************************
*
* TYPE DEFINITIONS & FUNCTION DECLARATIONS
*/
/* From ctype.h */
#define fluid_isascii(c) (((c) & ~0x7f) == 0)
/*
* fluid_midi_event_t
*/
struct _fluid_midi_event_t {
fluid_midi_event_t* next; /* Don't use it, it will dissappear. Used in midi tracks. */
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
unsigned char type; /* MIDI event type */
unsigned char channel; /* MIDI channel */
unsigned int param1; /* First parameter */
unsigned int param2; /* Second parameter */
};
/*
* fluid_track_t
*/
struct _fluid_track_t {
char* name;
int num;
fluid_midi_event_t *first;
fluid_midi_event_t *cur;
fluid_midi_event_t *last;
unsigned int ticks;
};
typedef struct _fluid_track_t fluid_track_t;
fluid_track_t* new_fluid_track(int num);
int delete_fluid_track(fluid_track_t* track);
int fluid_track_set_name(fluid_track_t* track, char* name);
char* fluid_track_get_name(fluid_track_t* track);
int fluid_track_add_event(fluid_track_t* track, fluid_midi_event_t* evt);
fluid_midi_event_t* fluid_track_first_event(fluid_track_t* track);
fluid_midi_event_t* fluid_track_next_event(fluid_track_t* track);
int fluid_track_get_duration(fluid_track_t* track);
int fluid_track_reset(fluid_track_t* track);
int fluid_track_send_events(fluid_track_t* track,
fluid_synth_t* synth,
fluid_player_t* player,
unsigned int ticks);
#define fluid_track_eot(track) ((track)->cur == NULL)
/*
* fluid_player
*/
struct _fluid_player_t {
int status;
int loop;
int ntracks;
fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
fluid_synth_t* synth;
fluid_timer_t* timer;
fluid_list_t* playlist;
char* current_file;
char send_program_change; /* should we ignore the program changes? */
int start_ticks; /* the number of tempo ticks passed at the last tempo change */
int cur_ticks; /* the number of tempo ticks passed */
int begin_msec; /* the time (msec) of the beginning of the file */
int start_msec; /* the start time of the last tempo change */
int cur_msec; /* the current time */
int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */
double deltatime; /* milliseconds per midi tick. depends on set-tempo */
unsigned int division;
};
int fluid_player_add_track(fluid_player_t* player, fluid_track_t* track);
int fluid_player_callback(void* data, unsigned int msec);
int fluid_player_count_tracks(fluid_player_t* player);
fluid_track_t* fluid_player_get_track(fluid_player_t* player, int i);
int fluid_player_reset(fluid_player_t* player);
int fluid_player_load(fluid_player_t* player, char *filename);
/*
* fluid_midi_file
*/
typedef struct {
fluid_file fp;
int running_status;
int c;
int type;
int ntracks;
int uses_smpte;
unsigned int smpte_fps;
unsigned int smpte_res;
unsigned int division; /* If uses_SMPTE == 0 then division is
ticks per beat (quarter-note) */
double tempo; /* Beats per second (SI rules =) */
int tracklen;
int trackpos;
int eot;
int varlen;
} fluid_midi_file;
fluid_midi_file* new_fluid_midi_file(char* filename);
void delete_fluid_midi_file(fluid_midi_file* mf);
int fluid_midi_file_read_mthd(fluid_midi_file* midifile);
int fluid_midi_file_load_tracks(fluid_midi_file* midifile, fluid_player_t* player);
int fluid_midi_file_read_track(fluid_midi_file* mf, fluid_player_t* player, int num);
int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track);
int fluid_midi_file_read_varlen(fluid_midi_file* mf);
int fluid_midi_file_getc(fluid_midi_file* mf);
int fluid_midi_file_push(fluid_midi_file* mf, int c);
int fluid_midi_file_read(fluid_midi_file* mf, void* buf, int len);
int fluid_midi_file_skip(fluid_midi_file* mf, int len);
int fluid_midi_file_read_tracklen(fluid_midi_file* mf);
int fluid_midi_file_eot(fluid_midi_file* mf);
int fluid_midi_file_get_division(fluid_midi_file* midifile);
int fluid_midi_event_length(unsigned char status);
/* How many parameters may a MIDI event have? */
#define FLUID_MIDI_PARSER_MAX_PAR 3
/*
* fluid_midi_parser_t
*/
struct _fluid_midi_parser_t {
unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */
unsigned char channel; /* The channel of the event that is received (in case of a channel event) */
unsigned int nr_bytes; /* How many bytes have been read for the current event? */
unsigned int nr_bytes_total; /* How many bytes does the current event type include? */
unsigned short p[FLUID_MIDI_PARSER_MAX_PAR]; /* The parameters */
fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */
};
int fluid_isasciistring(char* s);
long fluid_getlength(unsigned char *s);
int fluid_midi_router_send_event(fluid_midi_router_t* router, fluid_midi_event_t* event);
#endif /* _FLUID_MIDI_H */
+879
View File
@@ -0,0 +1,879 @@
/* 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
*/
/* Author: Markus Nentwig, [email protected]
*/
#include "fluid_midi_router.h"
#include "fluid_midi.h"
#include "fluid_synth.h"
#include "fluid_io.h"
/*
* new_fluid_midi_router
*/
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;;
/* create the router */
router = FLUID_NEW(fluid_midi_router_t); if (router == NULL){
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
};
/* Clear the router, so that error_recovery can safely free all the rules.
* Dump functions are also NULLed.
*/
FLUID_MEMSET(router, 0, sizeof(fluid_midi_router_t));
/* Retrieve the number of MIDI channels for range limiting */
fluid_settings_getint(settings, "synth.midi-channels", &router->nr_midi_channels);
fluid_mutex_init(router->ruletables_mutex);
router->synth = (fluid_synth_t*) event_handler_data;
router->event_handler=handler;
router->event_handler_data=event_handler_data;
/* Create the default routing rules
* They accept events on any channel for any range of parameters,
* and route them unchanged ("result=par*1.0+0") */
if (fluid_midi_router_create_default_rules(router) != FLUID_OK) goto error_recovery;
return router;
error_recovery:
FLUID_LOG(FLUID_ERR, "new_fluid_midi_router failed");
fluid_midi_router_destroy_all_rules(router);
FLUID_FREE(router);
return NULL;
}
/*
* delete_fluid_midi_router
*/
int
delete_fluid_midi_router(fluid_midi_router_t* router)
{
if (router == NULL) {
return FLUID_OK;
}
fluid_midi_router_destroy_all_rules(router);
FLUID_FREE(router);
return FLUID_OK;
}
/*
* fluid_midi_router_destroy_all_rules(fluid_midi_router_t* router)
* Purpose:
* Frees the used memory. This is used only for shutdown!
*/
void fluid_midi_router_destroy_all_rules(fluid_midi_router_t* router){
fluid_midi_router_rule_t* rules[6];
fluid_midi_router_rule_t* current_rule;
fluid_midi_router_rule_t* next_rule;
int i;
rules[0]=router->note_rules;
rules[1]=router->cc_rules;
rules[2]=router->progchange_rules;
rules[3]=router->pitchbend_rules;
rules[4]=router->channel_pressure_rules;
rules[5]=router->key_pressure_rules;
for (i=0; i < 6; i++){
current_rule=rules[i];
while (current_rule){
next_rule=current_rule->next;
FLUID_FREE(current_rule);
current_rule=next_rule;
};
};
}
/*
* new_fluid_midi_router_rule
*/
fluid_midi_router_rule_t* new_fluid_midi_router_rule(void)
{
fluid_midi_router_rule_t* rule=FLUID_NEW(fluid_midi_router_rule_t);
if (rule == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(rule, 0, sizeof(fluid_midi_router_rule_t));
return rule;
};
/*
* delete_fluid_midi_router_rule
*/
int
delete_fluid_midi_router_rule(fluid_midi_router_rule_t* rule)
{
FLUID_FREE(rule);
return FLUID_OK;
}
int fluid_midi_router_create_default_rules(fluid_midi_router_t* router)
{
fluid_midi_router_rule_t** rules[6];
int i;
rules[0]=&router->note_rules;
rules[1]=&router->cc_rules;
rules[2]=&router->progchange_rules;
rules[3]=&router->pitchbend_rules;
rules[4]=&router->channel_pressure_rules;
rules[5]=&router->key_pressure_rules;
for (i=0; i < 6; i++){
/* Start a new rule. rules[i] is the destination. _end will insert
* a new rule there into the linked list.
*/
if (fluid_midi_router_begin(router, rules[i]) != FLUID_OK) goto error_recovery;
if (fluid_midi_router_end(router) != FLUID_OK) goto error_recovery;
};
return FLUID_OK;
error_recovery:
FLUID_LOG(FLUID_ERR, "fluid_midi_router_create_default_rules failed");
return FLUID_FAILED;
};
/* Purpose:
* Resets the new-rule registers in 'router' to their default values.
* Stores the destination (the linked list into which the new rule is inserted by _end)
*/
int fluid_midi_router_begin(fluid_midi_router_t* router, fluid_midi_router_rule_t** dest)
{
if (!dest) goto error_recovery;
router->dest=dest;
/* In the days before the router, MIDI data went straight to the synth.
* So there is no need to check for reasonable values here.
*/
router->new_rule_chan_min=0;
router->new_rule_chan_max=999999;
router->new_rule_chan_mul=1.;
router->new_rule_chan_add=0;
router->new_rule_par1_min=0;
router->new_rule_par1_max=999999;
router->new_rule_par1_mul=1.;
router->new_rule_par1_add=0;
router->new_rule_par2_min=0;
router->new_rule_par2_max=999999;
router->new_rule_par2_mul=1.;
router->new_rule_par2_add=0;
return FLUID_OK;
error_recovery:
FLUID_LOG(FLUID_ERR, "fluid_midi_router_begin failed");
return FLUID_FAILED;
};
/* Purpose:
* Concludes a sequence of commands:
* - router_start type
* - router_chan
* - router_par1
* - router_par2
* - router_end (this call).
* Creates a new event from the given parameters and stores it in
* the correct list.
*/
int fluid_midi_router_end(fluid_midi_router_t* router){
fluid_midi_router_rule_t* rule=new_fluid_midi_router_rule(); if (rule == NULL) goto error_recovery;
rule->chan_min=router->new_rule_chan_min;
rule->chan_max=router->new_rule_chan_max;
rule->chan_mul=router->new_rule_chan_mul;
rule->chan_add=router->new_rule_chan_add;
rule->par1_min=router->new_rule_par1_min;
rule->par1_max=router->new_rule_par1_max;
rule->par1_mul=router->new_rule_par1_mul;
rule->par1_add=router->new_rule_par1_add;
rule->par2_min=router->new_rule_par2_min;
rule->par2_max=router->new_rule_par2_max;
rule->par2_mul=router->new_rule_par2_mul;
rule->par2_add=router->new_rule_par2_add;
/* Now we modify the rules table. Lock it to make sure, that the RT
* thread is not in the middle of an event. Also prevent, that some
* other thread modifies the table at the same time.
*/
fluid_mutex_lock(router->ruletables_mutex);
rule->next= *(router->dest);
*router->dest=rule;
fluid_mutex_unlock(router->ruletables_mutex);
return FLUID_OK;
error_recovery:
FLUID_LOG(FLUID_ERR, "fluid_midi_router_end failed");
delete_fluid_midi_router_rule(rule);
return FLUID_FAILED;
};
/*
* fluid_midi_router_send_event
* 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.
*
* In default mode, a noteon event is just forwarded to the synth's 'noteon' function,
* a 'CC' event to the synth's 'CC' function and so on.
*
* The router can be used to
* - filter messages (for example: Pass sustain pedal CCs only to selected channels),
* - split the keyboard (noteon with notenr < x: to ch 1, >x to ch 2),
* - layer sounds (for each noteon received on ch 1, create a noteon on ch1, ch2, ch3,...)
* - velocity scaling (for each noteon event, scale the velocity by 1.27 to give DX7 users
* a chance)
* - velocity switching ("v <=100: Angel Choir; V > 100: Hell's Bells")
* - get rid of aftertouch
* - ...
*/
int
fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event)
{
fluid_midi_router_t* router=(fluid_midi_router_t*)data;
fluid_synth_t* synth = router->synth;
fluid_midi_router_rule_t* rule=NULL;
fluid_midi_router_rule_t* next_rule=NULL;
int event_has_par2=0; /* Flag, indicates that current event needs two parameters */
int negative_event=0; /* Flag, indicates that current event releases a key / pedal */
int par1_max=127; /* Range limit for par1 */
int par2_max=127; /* Range limit for par2 */
int ret_val=FLUID_OK;
/* Some keyboards report noteoff through a noteon event with vel=0.
* Convert those to noteoff to ease processing.*/
if (event->type == NOTE_ON && event->param2 == 0) {
/* Channel: Remains the same
* Param 1: Note number, remains the same
* Param 2: release velocity), set to max
*/
event->type = NOTE_OFF;
event->param2=127;
};
/* Lock the rules table, so that for example the shell thread doesn't
* clear the rules we are just working with */
fluid_mutex_lock(router->ruletables_mutex);
/* Depending on the event type, choose the correct table of rules.
* Also invoke the appropriate callback function for the event type
* to notify external applications.
* Note: An event type not listed here simply won't find any rules and
* will be ignored.
*/
switch (event->type) {
case NOTE_ON:
rule=router->note_rules;
event_has_par2=1;
break;
case NOTE_OFF:
rule=router->note_rules;
event_has_par2=1;
break;
case CONTROL_CHANGE:
rule=router->cc_rules;
event_has_par2=1;
break;
case PROGRAM_CHANGE:
rule=router->progchange_rules;
break;
case PITCH_BEND:
rule=router->pitchbend_rules;
par1_max=16383;
break;
case CHANNEL_PRESSURE:
rule=router->channel_pressure_rules;
break;
case KEY_PRESSURE:
rule=router->key_pressure_rules;
event_has_par2=1;
break;
case MIDI_SYSTEM_RESET:
return router->event_handler(router->event_handler_data,event);
default:
break;
}
/* At this point 'rule' contains the first rule in a linked list.
* Check for all rules, whether channel and parameter ranges match.
*/
while (rule){
int chan; /* Channel of the generated event */
int par1; /* par1 of the generated event */
int par2=0;
int event_par1=(int)event->param1;
int event_par2=(int)event->param2;
fluid_midi_event_t new_event;
/* Store the pointer to the next rule right now. If the rule is later flagged for destruction,
* it may not be accessed anymore.
*/
next_rule=rule->next;
/* Check, whether the rule is still active. Expired rules cannot be removed immediately,
* because freeing memory in a realtime thread is no good idea. And the MIDI thread,
* which calls us here, has raised priority.*/
if (rule->state == MIDIRULE_DONE){
goto do_next_rule;
};
/* Channel window */
if (rule->chan_min > rule->chan_max){
/* Inverted rule: Exclude everything between max and min (but not min/max) */
if (event->channel > rule->chan_max && event->channel < rule->chan_min){
goto do_next_rule;
}
} else {
/* Normal rule: Exclude everything < max or > min (but not min/max) */
if (event->channel > rule->chan_max || event->channel < rule->chan_min){
goto do_next_rule;
}
};
/* Par 1 window */
if (rule->par1_min > rule->par1_max){
/* Inverted rule: Exclude everything between max and min (but not min/max) */
if (event_par1 > rule->par1_max && event_par1 < rule->par1_min){
goto do_next_rule;
}
} else {
/* Normal rule: Exclude everything < max or > min (but not min/max)*/
if (event_par1 > rule->par1_max || event_par1 < rule->par1_min){
goto do_next_rule;
}
};
/* Par 2 window (only applies to event types, which have 2 pars)
* For noteoff events, velocity switching doesn't make any sense.
* Velocity scaling might be useful, though.
*/
if (event_has_par2 && event->type != NOTE_OFF){
if (rule->par2_min > rule->par2_max){
/* Inverted rule: Exclude everything between max and min (but not min/max) */
if (event_par2 > rule->par2_max && event_par2 < rule->par2_min){
goto do_next_rule;
}
} else {
/* Normal rule: Exclude everything < max or > min (but not min/max)*/
if (event_par2 > rule->par2_max || event_par2 < rule->par2_min){
goto do_next_rule;
};
};
};
/* Channel scaling / offset
* Note: rule->chan_mul will probably be 0 or 1. If it's 0, input from all
* input channels is mapped to the same synth channel.
*/
chan=(int)((fluid_real_t)event->channel * (fluid_real_t)rule->chan_mul + (fluid_real_t)rule->chan_add + 0.5);
/* Par 1 scaling / offset */
par1=(int)((fluid_real_t)event_par1 * (fluid_real_t)rule->par1_mul + (fluid_real_t)rule->par1_add + 0.5);
/* Par 2 scaling / offset, if applicable */
if (event_has_par2){
par2=(int)((fluid_real_t)event_par2 * (fluid_real_t)rule->par2_mul + (fluid_real_t)rule->par2_add + 0.5);
};
/* Channel range limiting */
if (chan < 0){
chan=0;
/* Upper limit is hard to implement, because the number of MIDI channels can be changed via settings any time. */
};
/* Par1 range limiting */
if (par1 < 0){
par1=0;
} else if (par1 > par1_max){
par1=par1_max;
};
/* Par2 range limiting */
if (event_has_par2){
if (par2 < 0){
par2=0;
} else if (par2 > par2_max){
par2=par2_max;
};
};
/* At this point we have to create an event of event->type on 'chan' with par1 (maybe par2).
* We keep track on the state of noteon and sustain pedal events. If the application tries
* to delete a rule, it will only be fully removed, if pending noteoff / pedal off events have
* arrived. In the meantime (MIDIRULE_WAITING) state, it will only let through 'negative' events
* (noteoff or pedal up).
*/
if (
event->type == NOTE_ON
|| (event->type == CONTROL_CHANGE && par1 == SUSTAIN_SWITCH && par2 >= 64)
){
/* Noteon or sustain pedal down event generated */
if (rule->keys_cc[par1] == 0){
rule->keys_cc[par1]=1;
rule->pending_events++;
};
} else if (
event->type == NOTE_OFF
|| (event->type == CONTROL_CHANGE && par1 == SUSTAIN_SWITCH && par2 < 64)
){
/* Noteoff or sustain pedal up event generated */
if (rule->keys_cc[par1] > 0){
rule->keys_cc[par1]=0;
rule->pending_events--;
negative_event=1;
};
};
if (rule->state == MIDIRULE_WAITING){
if (negative_event){
if (rule->pending_events == 0){
/* There are no more pending events in the rule - all keys are up.
* Change its state to 'unused', it will be cleared up at the next
* opportunity to run 'free' safely.
* Note: After this, the rule may disappear at any time
*/
rule->state=MIDIRULE_DONE;
};
} else {
/* This rule only exists because of some unfinished business:
* There is still a note or sustain pedal waiting to be
* released. But the event that came in does not release any.
* So we just ignore the event and go on with the next rule.
*/
goto do_next_rule;
};
};
/* At this point it is decided, what is sent to the synth.
* Create a new event and make the appropriate call
*/
fluid_midi_event_set_type(&new_event, event->type);
fluid_midi_event_set_channel(&new_event, chan);
/* fluid_midi_event_set_param1(&new_event, par1); */
/* fluid_midi_event_set_param2(&new_event, par2); */
new_event.param1 = par1;
new_event.param2 = par2;
/* Don't know what to do with return values: What is, if
* generating one event fails? Current solution: Make all calls,
* regardless of failures, but report failure to the caller, as
* soon as only one call fails. Strategy should be thought
* through.
*/
if (router->event_handler(router->event_handler_data, &new_event) != FLUID_OK) {
ret_val=FLUID_FAILED;
}
do_next_rule:
rule=next_rule;
};
/* We are finished with the rule tables. Allow the other threads to do their job. */
fluid_mutex_unlock(router->ruletables_mutex);
return ret_val;
}
int fluid_midi_router_handle_clear(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
fluid_midi_router_t* router=synth->midi_router;
if (ac != 0) {
fluid_ostream_printf(out, "router_clear needs no arguments.\n");
goto error_recovery;
}
/* Disable rules and mark for destruction */
fluid_midi_router_disable_all_rules(router);
/* Free unused rules */
fluid_midi_router_free_unused_rules(router);
return 0;
error_recovery:
return -1;
};
int fluid_midi_router_handle_default(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
fluid_midi_router_t* router=synth->midi_router;
if (ac != 0) {
fluid_ostream_printf(out, "router_default needs no arguments.\n");
return -1;
}
/* Disable rules and mark for destruction */
fluid_midi_router_disable_all_rules(router);
/* Create default rules */
if (fluid_midi_router_create_default_rules(router) != FLUID_OK){
FLUID_LOG(FLUID_ERR, "create_default_rules failed");
goto error_recovery;
};
/* Free unused rules */
fluid_midi_router_free_unused_rules(router);
return 0;
error_recovery:
return -1;
};
int fluid_midi_router_handle_begin(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
fluid_midi_router_t* router=synth->midi_router;
fluid_midi_router_rule_t** dest=NULL;
if (ac != 1) {
fluid_ostream_printf(out, "router_begin needs no arguments.\n");
goto error_recovery;
}
if (FLUID_STRCMP(av[0],"note") == 0){
dest=& router->note_rules;
} else if (FLUID_STRCMP(av[0],"cc") == 0){
dest=& router->cc_rules;
} else if (FLUID_STRCMP(av[0],"prog") == 0){
dest=& router->progchange_rules;
} else if (FLUID_STRCMP(av[0],"pbend") == 0){
dest=& router->pitchbend_rules;
} else if (FLUID_STRCMP(av[0],"cpress") == 0){
dest=& router->channel_pressure_rules;
} else if (FLUID_STRCMP(av[0],"kpress") == 0){
dest=& router->key_pressure_rules;
};
if (dest == NULL){
fluid_ostream_printf(out, "router_begin args: note, cc, prog, pbend, cpress, kpress\n");
goto error_recovery;
};
if (fluid_midi_router_begin(router, dest) != FLUID_OK){
goto error_recovery;
};
/* Free unused rules (give it a try) */
fluid_midi_router_free_unused_rules(router);
return 0;
error_recovery:
return -1;
};
int fluid_midi_router_handle_end(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
fluid_midi_router_t* router=synth->midi_router;
if (ac != 0) {
fluid_ostream_printf(out, "router_end needs no arguments.");
goto error_recovery;
}
if (fluid_midi_router_end(router) != FLUID_OK){
FLUID_LOG(FLUID_ERR, "midi_router_end failed");
goto error_recovery;
};
/* Free unused rules (give it a try) */
fluid_midi_router_free_unused_rules(router);
return 0;
error_recovery:
return -1;
};
int fluid_midi_router_handle_chan(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
fluid_midi_router_t* router=synth->midi_router;
if (ac != 4) {
fluid_ostream_printf(out, "router_chan needs four args: min, max, mul, add.");
goto error_recovery;
}
router->new_rule_chan_min=atoi(av[0]);
router->new_rule_chan_max=atoi(av[1]);
router->new_rule_chan_mul=atoi(av[2]);
router->new_rule_chan_add=atoi(av[3]);
/* Free unused rules (give it a try) */
fluid_midi_router_free_unused_rules(router);
return 0;
error_recovery:
return -1;
};
int fluid_midi_router_handle_par1(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
fluid_midi_router_t* router=synth->midi_router;
if (ac != 4) {
fluid_ostream_printf(out, "router_par1 needs four args: min, max, mul, add.");
goto error_recovery;
}
router->new_rule_par1_min=atoi(av[0]);
router->new_rule_par1_max=atoi(av[1]);
router->new_rule_par1_mul=atoi(av[2]);
router->new_rule_par1_add=atoi(av[3]);
/* Free unused rules (give it a try) */
fluid_midi_router_free_unused_rules(router);
return 0;
error_recovery:
return -1;
};
int fluid_midi_router_handle_par2(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out)
{
fluid_midi_router_t* router=synth->midi_router;
if (ac != 4) {
fluid_ostream_printf(out, "router_par2 needs four args: min, max, mul, add.");
goto error_recovery;
}
router->new_rule_par2_min=atoi(av[0]);
router->new_rule_par2_max=atoi(av[1]);
router->new_rule_par2_mul=atoi(av[2]);
router->new_rule_par2_add=atoi(av[3]);
/* Free unused rules (give it a try) */
fluid_midi_router_free_unused_rules(router);
return 0;
error_recovery:
return -1;
};
void fluid_midi_router_disable_all_rules(fluid_midi_router_t* router)
{
/* Go through all rules. If the rule has no outstanding events, then
* flag it for destruction. Otherwise change it to wait mode. Then
* it will handle the pending events, and flag itself for destruction
* as soon as all events have arrived.
*/
fluid_midi_router_rule_t* rules[6];
fluid_midi_router_rule_t* current_rule;
int i;
rules[0]=router->note_rules;
rules[1]=router->cc_rules;
rules[2]=router->progchange_rules;
rules[3]=router->pitchbend_rules;
rules[4]=router->channel_pressure_rules;
rules[5]=router->key_pressure_rules;
/* Lock the rules table. We live on the assumption, that the rules
* table does not change while we are chewing at it.
* Changes between the processing of note / cc etc are permitted.
*/
for (i=0; i < 6; i++){
fluid_mutex_lock(router->ruletables_mutex);
current_rule=rules[i];
while (current_rule){
if (current_rule->pending_events == 0){
/* Flag for destruction */
current_rule->state=MIDIRULE_DONE;
} else {
/* Wait mode */
current_rule->state=MIDIRULE_WAITING;
};
current_rule=current_rule->next;
};
fluid_mutex_unlock(router->ruletables_mutex);
};
};
void fluid_midi_router_free_unused_rules(fluid_midi_router_t* router)
{
int i;
for (i=0; i < 6; i++){
fluid_midi_router_rule_t** p=NULL;
/* We assume, that the table does not change while we are at it.
* Between different types (note, cc etc) we can allow changes.
*/
fluid_mutex_lock(router->ruletables_mutex);
switch(i){
case 0:
p=&router->note_rules;
break;
case 1:
p=&router->cc_rules;
break;
case 2:
p=&router->progchange_rules;
break;
case 3:
p=&router->pitchbend_rules;
break;
case 4:
p=&router->channel_pressure_rules;
break;
case 5:
p=&router->key_pressure_rules;
break;
default:
break;
};
while (*p){
fluid_midi_router_rule_t* current_rule=*p;
fluid_midi_router_rule_t* next_rule=current_rule->next;
if (current_rule->state == MIDIRULE_DONE){
/* p points to current_rule.
* current_rule->next points to next_rule.
* Unlink current_rule from the chain by setting the content
* of p to next_rule.
*/
*p=next_rule;
/* Now the rule is not in the chain anymore. Destroy it. */
delete_fluid_midi_router_rule(current_rule);
} else {
/* We have to keep the rule, there is still unfinished business. */
p = &current_rule->next;
};
};
fluid_mutex_unlock(router->ruletables_mutex);
};
};
/* 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.
*/
int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event)
{
switch (event->type) {
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;
};
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.
*/
int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event)
{
switch (event->type) {
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);
break;
case PITCH_BEND:
fprintf(stdout, "event_post_pitch %i %i\n", event->channel, event->param1);
break;
case CHANNEL_PRESSURE:
fprintf(stdout, "event_post_cpress %i %i\n", event->channel, event->param1);
break;
case KEY_PRESSURE:
fprintf(stdout, "event_post_kpress %i %i %i\n",
event->channel, event->param1, event->param2);
break;
default:
break;
};
return fluid_synth_handle_midi_event((fluid_synth_t*) data, event);
};
+112
View File
@@ -0,0 +1,112 @@
/* 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
*/
/* Author: Markus Nentwig, [email protected]
*/
#ifndef _FLUID_MIDIROUTER_H
#define _FLUID_MIDIROUTER_H
#include "fluidsynth_priv.h"
#include "fluid_midi.h"
#include "fluid_sys.h"
void fluid_midi_router_destroy_all_rules(fluid_midi_router_t* router);
fluid_midi_router_rule_t* new_fluid_midi_router_rule(void);
int fluid_midi_router_handle_clear(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_midi_router_handle_default(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_midi_router_handle_begin(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_midi_router_handle_chan(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_midi_router_handle_par1(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_midi_router_handle_par2(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_midi_router_handle_end(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_midi_router_begin(fluid_midi_router_t* router, fluid_midi_router_rule_t** dest);
int fluid_midi_router_end(fluid_midi_router_t* router);
int fluid_midi_router_create_default_rules(fluid_midi_router_t* router);
void fluid_midi_router_disable_all_rules(fluid_midi_router_t* router);
void fluid_midi_router_free_unused_rules(fluid_midi_router_t* router);
/*
* fluid_midi_router
*/
struct _fluid_midi_router_t {
fluid_synth_t* synth;
fluid_midi_router_rule_t* note_rules;
fluid_midi_router_rule_t* cc_rules;
fluid_midi_router_rule_t* progchange_rules;
fluid_midi_router_rule_t* pitchbend_rules;
fluid_midi_router_rule_t* channel_pressure_rules;
fluid_midi_router_rule_t* key_pressure_rules;
int new_rule_chan_min;
int new_rule_chan_max;
double new_rule_chan_mul;
int new_rule_chan_add;
int new_rule_par1_min;
int new_rule_par1_max;
double new_rule_par1_mul;
int new_rule_par1_add;
int new_rule_par2_min;
int new_rule_par2_max;
double new_rule_par2_mul;
int new_rule_par2_add;
fluid_midi_router_rule_t** dest;
handle_midi_event_func_t event_handler; /* Callback function for generated events */
void* event_handler_data; /* One arg for the callback */
int nr_midi_channels; /* For clipping the midi channel */
fluid_mutex_t ruletables_mutex;
};
struct _fluid_midi_router_rule_t {
int chan_min; /* Channel window, for which this rule is valid */
int chan_max;
fluid_real_t chan_mul; /* Channel multiplier (usually 0 or 1) */
int chan_add; /* Channel offset */
int par1_min; /* Parameter 1 window, for which this rule is valid */
int par1_max;
fluid_real_t par1_mul;
int par1_add;
int par2_min; /* Parameter 2 window, for which this rule is valid */
int par2_max;
fluid_real_t par2_mul;
int par2_add;
int pending_events; /* In case of noteon: How many keys are still down? */
char keys_cc[128]; /* Flags, whether a key is down / controller is set (sustain) */
fluid_midi_router_rule_t* next; /* next entry */
int state; /* Does this rule expire, as soon as (for example) all keys are up? */
};
enum fluid_midirule_state {
MIDIRULE_ACTIVE = 0x00,
MIDIRULE_WAITING,
MIDIRULE_DONE
};
#endif
+429
View File
@@ -0,0 +1,429 @@
/* 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_mod.h"
#include "fluid_chan.h"
#include "fluid_voice.h"
/*
* fluid_mod_clone
*/
void
fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src)
{
mod->dest = src->dest;
mod->src1 = src->src1;
mod->flags1 = src->flags1;
mod->src2 = src->src2;
mod->flags2 = src->flags2;
mod->amount = src->amount;
}
/*
* fluid_mod_set_source1
*/
void
fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags)
{
mod->src1 = src;
mod->flags1 = flags;
}
/*
* fluid_mod_set_source2
*/
void
fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags)
{
mod->src2 = src;
mod->flags2 = flags;
}
/*
* fluid_mod_set_dest
*/
void
fluid_mod_set_dest(fluid_mod_t* mod, int dest)
{
mod->dest = dest;
}
/*
* fluid_mod_set_amount
*/
void
fluid_mod_set_amount(fluid_mod_t* mod, double amount)
{
mod->amount = (double) amount;
}
int fluid_mod_get_source1(fluid_mod_t* mod)
{
return mod->src1;
}
int fluid_mod_get_flags1(fluid_mod_t* mod)
{
return mod->flags1;
}
int fluid_mod_get_source2(fluid_mod_t* mod)
{
return mod->src2;
}
int fluid_mod_get_flags2(fluid_mod_t* mod)
{
return mod->flags2;
}
int fluid_mod_get_dest(fluid_mod_t* mod)
{
return mod->dest;
}
double fluid_mod_get_amount(fluid_mod_t* mod)
{
return (fluid_real_t) mod->amount;
}
/*
* fluid_mod_get_value
*/
fluid_real_t
fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice)
{
fluid_real_t v1 = 0.0, v2 = 1.0;
fluid_real_t range1 = 127.0, range2 = 127.0;
if (chan == NULL) {
return 0.0f;
}
/* 'special treatment' for default controller
*
* Reference: SF2.01 section 8.4.2
*
* The GM default controller 'vel-to-filter cut off' is not clearly
* defined: If implemented according to the specs, the filter
* frequency jumps between vel=63 and vel=64. To maintain
* compatibility with existing sound fonts, the implementation is
* 'hardcoded', it is impossible to implement using only one
* modulator otherwise.
*
* I assume here, that the 'intention' of the paragraph is one
* octave (1200 cents) filter frequency shift between vel=127 and
* vel=64. 'amount' is (-2400), at least as long as the controller
* is set to default.
*
* Further, the 'appearance' of the modulator (source enumerator,
* destination enumerator, flags etc) is different from that
* described in section 8.4.2, but it matches the definition used in
* several SF2.1 sound fonts (where it is used only to turn it off).
* */
if ((mod->src2 == FLUID_MOD_VELOCITY) &&
(mod->src1 == FLUID_MOD_VELOCITY) &&
(mod->flags1 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
| FLUID_MOD_NEGATIVE | FLUID_MOD_LINEAR)) &&
(mod->flags2 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
| FLUID_MOD_POSITIVE | FLUID_MOD_SWITCH)) &&
(mod->dest == GEN_FILTERFC)) {
if (voice->vel < 64){
return (fluid_real_t) mod->amount / 2.0;
} else {
return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
}
}
/* get the initial value of the first source */
if (mod->src1 > 0) {
if (mod->flags1 & FLUID_MOD_CC) {
v1 = fluid_channel_get_cc(chan, mod->src1);
} else { /* source 1 is one of the direct controllers */
switch (mod->src1) {
case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
v1 = range1;
break;
case FLUID_MOD_VELOCITY:
v1 = voice->vel;
break;
case FLUID_MOD_KEY:
v1 = voice->key;
break;
case FLUID_MOD_KEYPRESSURE:
v1 = chan->key_pressure;
break;
case FLUID_MOD_CHANNELPRESSURE:
v1 = chan->channel_pressure;
break;
case FLUID_MOD_PITCHWHEEL:
v1 = chan->pitch_bend;
range1 = 0x4000;
break;
case FLUID_MOD_PITCHWHEELSENS:
v1 = chan->pitch_wheel_sensitivity;
break;
default:
v1 = 0.0;
}
}
/* transform the input value */
switch (mod->flags1 & 0x0f) {
case 0: /* linear, unipolar, positive */
v1 /= range1;
break;
case 1: /* linear, unipolar, negative */
v1 = 1.0f - v1 / range1;
break;
case 2: /* linear, bipolar, positive */
v1 = -1.0f + 2.0f * v1 / range1;
break;
case 3: /* linear, bipolar, negative */
v1 = -1.0f + 2.0f * v1 / range1;
break;
case 4: /* concave, unipolar, positive */
v1 = fluid_concave(v1);
break;
case 5: /* concave, unipolar, negative */
v1 = fluid_concave(127 - v1);
break;
case 6: /* concave, bipolar, positive */
v1 = (v1 > 64)? fluid_concave(2 * (v1 - 64)) : -fluid_concave(2 * (64 - v1));
break;
case 7: /* concave, bipolar, negative */
v1 = (v1 > 64)? -fluid_concave(2 * (v1 - 64)) : fluid_concave(2 * (64 - v1));
break;
case 8: /* convex, unipolar, positive */
v1 = fluid_convex(v1);
break;
case 9: /* convex, unipolar, negative */
v1 = fluid_convex(127 - v1);
break;
case 10: /* convex, bipolar, positive */
v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1));
break;
case 11: /* convex, bipolar, negative */
v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1));
break;
case 12: /* switch, unipolar, positive */
v1 = (v1 >= 64)? 1.0f : 0.0f;
break;
case 13: /* switch, unipolar, negative */
v1 = (v1 >= 64)? 0.0f : 1.0f;
break;
case 14: /* switch, bipolar, positive */
v1 = (v1 >= 64)? 1.0f : -1.0f;
break;
case 15: /* switch, bipolar, negative */
v1 = (v1 >= 64)? -1.0f : 1.0f;
break;
}
} else {
return 0.0;
}
/* no need to go further */
if (v1 == 0.0f) {
return 0.0f;
}
/* get the second input source */
if (mod->src2 > 0) {
if (mod->flags2 & FLUID_MOD_CC) {
v2 = fluid_channel_get_cc(chan, mod->src2);
} else {
switch (mod->src2) {
case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
v2 = range2;
break;
case FLUID_MOD_VELOCITY:
v2 = voice->vel;
break;
case FLUID_MOD_KEY:
v2 = voice->key;
break;
case FLUID_MOD_KEYPRESSURE:
v2 = chan->key_pressure;
break;
case FLUID_MOD_CHANNELPRESSURE:
v2 = chan->channel_pressure;
break;
case FLUID_MOD_PITCHWHEEL:
v2 = chan->pitch_bend;
break;
case FLUID_MOD_PITCHWHEELSENS:
v2 = chan->pitch_wheel_sensitivity;
break;
default:
v1 = 0.0f;
}
}
/* transform the second input value */
switch (mod->flags2 & 0x0f) {
case 0: /* linear, unipolar, positive */
v2 /= range2;
break;
case 1: /* linear, unipolar, negative */
v2 = 1.0f - v2 / range2;
break;
case 2: /* linear, bipolar, positive */
v2 = -1.0f + 2.0f * v2 / range2;
break;
case 3: /* linear, bipolar, negative */
v2 = -1.0f + 2.0f * v2 / range2;
break;
case 4: /* concave, unipolar, positive */
v2 = fluid_concave(v2);
break;
case 5: /* concave, unipolar, negative */
v2 = fluid_concave(127 - v2);
break;
case 6: /* concave, bipolar, positive */
v2 = (v2 > 64)? fluid_concave(2 * (v2 - 64)) : -fluid_concave(2 * (64 - v2));
break;
case 7: /* concave, bipolar, negative */
v2 = (v2 > 64)? -fluid_concave(2 * (v2 - 64)) : fluid_concave(2 * (64 - v2));
break;
case 8: /* convex, unipolar, positive */
v2 = fluid_convex(v2);
break;
case 9: /* convex, unipolar, negative */
v2 = 1.0f - fluid_convex(v2);
break;
case 10: /* convex, bipolar, positive */
v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
break;
case 11: /* convex, bipolar, negative */
v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
break;
case 12: /* switch, unipolar, positive */
v2 = (v2 >= 64)? 1.0f : 0.0f;
break;
case 13: /* switch, unipolar, negative */
v2 = (v2 >= 64)? 0.0f : 1.0f;
break;
case 14: /* switch, bipolar, positive */
v2 = (v2 >= 64)? 1.0f : -1.0f;
break;
case 15: /* switch, bipolar, negative */
v2 = (v2 >= 64)? -1.0f : 1.0f;
break;
}
} else {
v2 = 1.0f;
}
/* it's as simple as that: */
return (fluid_real_t) mod->amount * v1 * v2;
}
/*
* fluid_mod_new
*/
fluid_mod_t*
fluid_mod_new()
{
fluid_mod_t* mod = FLUID_NEW(fluid_mod_t);
if (mod == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
return mod;
};
/*
* fluid_mod_delete
*/
void
fluid_mod_delete(fluid_mod_t * mod)
{
FLUID_FREE(mod);
};
/*
* fluid_mod_test_identity
*/
/* Purpose:
* Checks, if two modulators are identical.
* SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'.
*/
int fluid_mod_test_identity(fluid_mod_t * mod1, fluid_mod_t * mod2){
if (mod1->dest != mod2->dest){return 0;};
if (mod1->src1 != mod2->src1){return 0;};
if (mod1->src2 != mod2->src2){return 0;};
if (mod1->flags1 != mod2->flags1){return 0;}
if (mod1->flags2 != mod2->flags2){return 0;}
return 1;
};
/* debug function: Prints the contents of a modulator */
void fluid_dump_modulator(fluid_mod_t * mod){
int src1=mod->src1;
int dest=mod->dest;
int src2=mod->src2;
int flags1=mod->flags1;
int flags2=mod->flags2;
fluid_real_t amount=(fluid_real_t)mod->amount;
printf("Src: ");
if (flags1 & FLUID_MOD_CC){
printf("MIDI CC=%i",src1);
} else {
switch(src1){
case FLUID_MOD_NONE:
printf("None"); break;
case FLUID_MOD_VELOCITY:
printf("note-on velocity"); break;
case FLUID_MOD_KEY:
printf("Key nr"); break;
case FLUID_MOD_KEYPRESSURE:
printf("Poly pressure"); break;
case FLUID_MOD_CHANNELPRESSURE:
printf("Chan pressure"); break;
case FLUID_MOD_PITCHWHEEL:
printf("Pitch Wheel"); break;
case FLUID_MOD_PITCHWHEELSENS:
printf("Pitch Wheel sens"); break;
default:
printf("(unknown: %i)", src1);
}; /* switch src1 */
}; /* if not CC */
if (flags1 & FLUID_MOD_NEGATIVE){printf("- ");} else {printf("+ ");};
if (flags1 & FLUID_MOD_BIPOLAR){printf("bip ");} else {printf("unip ");};
printf("-> ");
switch(dest){
case GEN_FILTERQ: printf("Q"); break;
case GEN_FILTERFC: printf("fc"); break;
case GEN_VIBLFOTOPITCH: printf("VibLFO-to-pitch"); break;
case GEN_MODENVTOPITCH: printf("ModEnv-to-pitch"); break;
case GEN_MODLFOTOPITCH: printf("ModLFO-to-pitch"); break;
case GEN_CHORUSSEND: printf("Chorus send"); break;
case GEN_REVERBSEND: printf("Reverb send"); break;
case GEN_PAN: printf("pan"); break;
case GEN_ATTENUATION: printf("att"); break;
default: printf("dest %i",dest);
}; /* switch dest */
printf(", amount %f flags %i src2 %i flags2 %i\n",amount, flags1, src2, flags2);
};
+40
View File
@@ -0,0 +1,40 @@
/* 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_MOD_H
#define _FLUID_MOD_H
#include "fluidsynth_priv.h"
#include "fluid_conv.h"
void fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src);
fluid_real_t fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice);
void fluid_dump_modulator(fluid_mod_t * mod);
#define fluid_mod_has_source(mod,cc,ctrl) \
( ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) != 0) && (cc != 0)) \
|| ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) == 0) && (cc == 0)))) \
|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) != 0) && (cc != 0)) \
|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) == 0) && (cc == 0)))))
#define fluid_mod_has_dest(mod,gen) ((mod)->dest == gen)
#endif /* _FLUID_MOD_H */
+177
View File
@@ -0,0 +1,177 @@
/* 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_PHASE_H
#define _FLUID_PHASE_H
#if HAVE_CONFIG_H
#include "config.h"
#endif
/*
* phase
*/
#define FLUID_INTERP_BITS 8
#define FLUID_INTERP_BITS_MASK 0xff000000
#define FLUID_INTERP_BITS_SHIFT 24
#define FLUID_INTERP_MAX 256
#define FLUID_FRACT_MAX ((double)4294967296.0)
/* fluid_phase_t
* Purpose:
* Playing pointer for voice playback
*
* When a sample is played back at a different pitch, the playing pointer in the
* source sample will not advance exactly one sample per output sample.
* 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;
/* 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; \
}
/* 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); \
}
/* Purpose:
* Return the index and the fractional part, respectively. */
#define fluid_phase_index(_x) \
((int)(_x).b32.index)
#define fluid_phase_fract(_x) \
((_x).b32.fract)
/* Purpose:
* Takes the fractional part of the argument phase and
* calculates the corresponding position in the interpolation table.
* The fractional position of the playing pointer is calculated with a quite high
* resolution (32 bits). It would be unpractical to keep a set of interpolation
* 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))
#define fluid_phase_double(_x) \
((double)((_x).b32.index) + ((double)((_x).b32.fract) / 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
/* 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
/* 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
/* 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)++)
#endif /* _FLUID_PHASE_H */
File diff suppressed because it is too large Load Diff
+114
View File
@@ -0,0 +1,114 @@
/* 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_RAMSFONT_H
#define _FLUID_RAMSFONT_H
#include "fluidsynth.h"
#include "fluidsynth_priv.h"
#include "fluid_defsfont.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
Public interface
*/
int fluid_ramsfont_sfont_delete(fluid_sfont_t* sfont);
char* fluid_ramsfont_sfont_get_name(fluid_sfont_t* sfont);
fluid_preset_t* fluid_ramsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
void fluid_ramsfont_sfont_iteration_start(fluid_sfont_t* sfont);
int fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset);
int fluid_rampreset_preset_delete(fluid_preset_t* preset);
char* fluid_rampreset_preset_get_name(fluid_preset_t* preset);
int fluid_rampreset_preset_get_banknum(fluid_preset_t* preset);
int fluid_rampreset_preset_get_num(fluid_preset_t* preset);
int fluid_rampreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
/*
* fluid_ramsfont_t
*/
struct _fluid_ramsfont_t
{
char name[21]; /* the name of the soundfont */
fluid_list_t* sample; /* the samples in this soundfont */
fluid_rampreset_t* preset; /* the presets of this soundfont */
fluid_preset_t iter_preset; /* preset interface used in the iteration */
fluid_rampreset_t* iter_cur; /* the current preset in the iteration */
};
/* interface */
fluid_ramsfont_t* new_fluid_ramsfont(void);
int delete_fluid_ramsfont(fluid_ramsfont_t* sfont);
char* fluid_ramsfont_get_name(fluid_ramsfont_t* sfont);
fluid_rampreset_t* fluid_ramsfont_get_preset(fluid_ramsfont_t* sfont, unsigned int bank, unsigned int prenum);
void fluid_ramsfont_iteration_start(fluid_ramsfont_t* sfont);
int fluid_ramsfont_iteration_next(fluid_ramsfont_t* sfont, fluid_preset_t* preset);
/* specific */
/*
* fluid_preset_t
*/
struct _fluid_rampreset_t
{
fluid_rampreset_t* next;
fluid_ramsfont_t* sfont; /* the soundfont this preset belongs to */
char name[21]; /* the name of the preset */
unsigned int bank; /* the bank number */
unsigned int num; /* the preset number */
fluid_preset_zone_t* global_zone; /* the global zone of the preset */
fluid_preset_zone_t* zone; /* the chained list of preset zones */
fluid_list_t *presetvoices; /* chained list of used voices */
};
/* interface */
fluid_rampreset_t* new_fluid_rampreset(fluid_ramsfont_t* sfont);
int delete_fluid_rampreset(fluid_rampreset_t* preset);
fluid_rampreset_t* fluid_rampreset_next(fluid_rampreset_t* preset);
char* fluid_rampreset_get_name(fluid_rampreset_t* preset);
int fluid_rampreset_get_banknum(fluid_rampreset_t* preset);
int fluid_rampreset_get_num(fluid_rampreset_t* preset);
int fluid_rampreset_noteon(fluid_rampreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
#ifdef __cplusplus
}
#endif
#endif /* _FLUID_SFONT_H */
+560
View File
@@ -0,0 +1,560 @@
/*
Freeverb
Written by Jezar at Dreampoint, June 2000
http://www.dreampoint.co.uk
This code is public domain
Translated to C by Peter Hanappe, Mai 2001
*/
#include "fluid_rev.h"
/***************************************************************
*
* REVERB
*/
/* Denormalising:
*
* According to music-dsp thread 'Denormalise', Pentium processors
* have a hardware 'feature', that is of interest here, related to
* numeric underflow. We have a recursive filter. The output decays
* exponentially, if the input stops. So the numbers get smaller and
* smaller... At some point, they reach 'denormal' level. This will
* lead to drastic spikes in the CPU load. The effect was reproduced
* with the reverb - sometimes the average load over 10 s doubles!!.
*
* The 'undenormalise' macro fixes the problem: As soon as the number
* is close enough to denormal level, the macro forces the number to
* 0.0f. The original macro is:
*
* #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
*
* This will zero out a number when it reaches the denormal level.
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
* every sample, expensive. The alternative macro comes from a later
* mail from Jon Watte. It will zap a number before it reaches
* denormal level. Jon suggests to run it once per block instead of
* every sample.
*/
# if defined(WITH_FLOATX)
# 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) fabs(sample)<1e-10 ? 0 : sample;
#endif
/* Denormalising part II:
*
* Another method fixes the problem cheaper: Use a small DC-offset in
* the filter calculations. Now the signals converge not against 0,
* but against the offset. The constant offset is invisible from the
* outside world (i.e. it does not appear at the output. There is a
* very small turn-on transient response, which should not cause
* problems.
*/
//#define DC_OFFSET 0
#define DC_OFFSET 1e-8
//#define DC_OFFSET 0.001f
typedef struct _fluid_allpass fluid_allpass;
typedef struct _fluid_comb fluid_comb;
struct _fluid_allpass {
fluid_real_t feedback;
fluid_real_t *buffer;
int bufsize;
int bufidx;
};
void fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size);
void fluid_allpass_init(fluid_allpass* allpass);
void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
void
fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size)
{
allpass->bufidx = 0;
allpass->buffer = buf;
allpass->bufsize = size;
}
void
fluid_allpass_init(fluid_allpass* allpass)
{
int i;
int len = allpass->bufsize;
fluid_real_t* buf = allpass->buffer;
for (i = 0; i < len; i++) {
buf[i] = DC_OFFSET; /* this is not 100 % correct. */
}
}
void
fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val)
{
allpass->feedback = val;
}
fluid_real_t
fluid_allpass_getfeedback(fluid_allpass* allpass)
{
return allpass->feedback;
}
#define fluid_allpass_process(_allpass, _input) \
{ \
fluid_real_t output; \
fluid_real_t bufout; \
bufout = _allpass.buffer[_allpass.bufidx]; \
output = bufout-_input; \
_allpass.buffer[_allpass.bufidx] = _input + (bufout * _allpass.feedback); \
if (++_allpass.bufidx >= _allpass.bufsize) { \
_allpass.bufidx = 0; \
} \
_input = output; \
}
/* fluid_real_t fluid_allpass_process(fluid_allpass* allpass, fluid_real_t input) */
/* { */
/* fluid_real_t output; */
/* fluid_real_t bufout; */
/* bufout = allpass->buffer[allpass->bufidx]; */
/* undenormalise(bufout); */
/* output = -input + bufout; */
/* allpass->buffer[allpass->bufidx] = input + (bufout * allpass->feedback); */
/* if (++allpass->bufidx >= allpass->bufsize) { */
/* allpass->bufidx = 0; */
/* } */
/* return output; */
/* } */
struct _fluid_comb {
fluid_real_t feedback;
fluid_real_t filterstore;
fluid_real_t damp1;
fluid_real_t damp2;
fluid_real_t *buffer;
int bufsize;
int bufidx;
};
void fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size);
void fluid_comb_init(fluid_comb* comb);
void fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val);
fluid_real_t fluid_comb_getdamp(fluid_comb* comb);
void fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val);
fluid_real_t fluid_comb_getfeedback(fluid_comb* comb);
void
fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size)
{
comb->filterstore = 0;
comb->bufidx = 0;
comb->buffer = buf;
comb->bufsize = size;
}
void
fluid_comb_init(fluid_comb* comb)
{
int i;
fluid_real_t* buf = comb->buffer;
int len = comb->bufsize;
for (i = 0; i < len; i++) {
buf[i] = DC_OFFSET; /* This is not 100 % correct. */
}
}
void
fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val)
{
comb->damp1 = val;
comb->damp2 = 1 - val;
}
fluid_real_t
fluid_comb_getdamp(fluid_comb* comb)
{
return comb->damp1;
}
void
fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val)
{
comb->feedback = val;
}
fluid_real_t
fluid_comb_getfeedback(fluid_comb* comb)
{
return comb->feedback;
}
#define fluid_comb_process(_comb, _input, _output) \
{ \
fluid_real_t _tmp = _comb.buffer[_comb.bufidx]; \
_comb.filterstore = (_tmp * _comb.damp2) + (_comb.filterstore * _comb.damp1); \
_comb.buffer[_comb.bufidx] = _input + (_comb.filterstore * _comb.feedback); \
if (++_comb.bufidx >= _comb.bufsize) { \
_comb.bufidx = 0; \
} \
_output += _tmp; \
}
/* fluid_real_t fluid_comb_process(fluid_comb* comb, fluid_real_t input) */
/* { */
/* fluid_real_t output; */
/* output = comb->buffer[comb->bufidx]; */
/* undenormalise(output); */
/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
/* undenormalise(comb->filterstore); */
/* comb->buffer[comb->bufidx] = input + (comb->filterstore * comb->feedback); */
/* if (++comb->bufidx >= comb->bufsize) { */
/* comb->bufidx = 0; */
/* } */
/* return output; */
/* } */
#define numcombs 8
#define numallpasses 4
#define fixedgain 0.015f
#define scalewet 3.0f
#define scaledamp 0.4f
#define scaleroom 0.28f
#define offsetroom 0.7f
#define initialroom 0.5f
#define initialdamp 0.5f
#define initialwet 1
#define initialdry 0
#define initialwidth 1
#define stereospread 23
/*
These values assume 44.1KHz sample rate
they will probably be OK for 48KHz sample rate
but would need scaling for 96KHz (or other) sample rates.
The values were obtained by listening tests.
*/
#define combtuningL1 1116
#define combtuningR1 1116 + stereospread
#define combtuningL2 1188
#define combtuningR2 1188 + stereospread
#define combtuningL3 1277
#define combtuningR3 1277 + stereospread
#define combtuningL4 1356
#define combtuningR4 1356 + stereospread
#define combtuningL5 1422
#define combtuningR5 1422 + stereospread
#define combtuningL6 1491
#define combtuningR6 1491 + stereospread
#define combtuningL7 1557
#define combtuningR7 1557 + stereospread
#define combtuningL8 1617
#define combtuningR8 1617 + stereospread
#define allpasstuningL1 556
#define allpasstuningR1 556 + stereospread
#define allpasstuningL2 441
#define allpasstuningR2 441 + stereospread
#define allpasstuningL3 341
#define allpasstuningR3 341 + stereospread
#define allpasstuningL4 225
#define allpasstuningR4 225 + stereospread
struct _fluid_revmodel_t {
fluid_real_t roomsize;
fluid_real_t damp;
fluid_real_t wet, wet1, wet2;
fluid_real_t width;
fluid_real_t gain;
/*
The following are all declared inline
to remove the need for dynamic allocation
with its subsequent error-checking messiness
*/
/* Comb filters */
fluid_comb combL[numcombs];
fluid_comb combR[numcombs];
/* Allpass filters */
fluid_allpass allpassL[numallpasses];
fluid_allpass allpassR[numallpasses];
/* Buffers for the combs */
fluid_real_t bufcombL1[combtuningL1];
fluid_real_t bufcombR1[combtuningR1];
fluid_real_t bufcombL2[combtuningL2];
fluid_real_t bufcombR2[combtuningR2];
fluid_real_t bufcombL3[combtuningL3];
fluid_real_t bufcombR3[combtuningR3];
fluid_real_t bufcombL4[combtuningL4];
fluid_real_t bufcombR4[combtuningR4];
fluid_real_t bufcombL5[combtuningL5];
fluid_real_t bufcombR5[combtuningR5];
fluid_real_t bufcombL6[combtuningL6];
fluid_real_t bufcombR6[combtuningR6];
fluid_real_t bufcombL7[combtuningL7];
fluid_real_t bufcombR7[combtuningR7];
fluid_real_t bufcombL8[combtuningL8];
fluid_real_t bufcombR8[combtuningR8];
/* Buffers for the allpasses */
fluid_real_t bufallpassL1[allpasstuningL1];
fluid_real_t bufallpassR1[allpasstuningR1];
fluid_real_t bufallpassL2[allpasstuningL2];
fluid_real_t bufallpassR2[allpasstuningR2];
fluid_real_t bufallpassL3[allpasstuningL3];
fluid_real_t bufallpassR3[allpasstuningR3];
fluid_real_t bufallpassL4[allpasstuningL4];
fluid_real_t bufallpassR4[allpasstuningR4];
};
void fluid_revmodel_update(fluid_revmodel_t* rev);
void fluid_revmodel_init(fluid_revmodel_t* rev);
fluid_revmodel_t*
new_fluid_revmodel()
{
fluid_revmodel_t* rev;
rev = FLUID_NEW(fluid_revmodel_t);
if (rev == NULL) {
return NULL;
}
/* Tie the components to their buffers */
fluid_comb_setbuffer(&rev->combL[0], rev->bufcombL1, combtuningL1);
fluid_comb_setbuffer(&rev->combR[0], rev->bufcombR1, combtuningR1);
fluid_comb_setbuffer(&rev->combL[1], rev->bufcombL2, combtuningL2);
fluid_comb_setbuffer(&rev->combR[1], rev->bufcombR2, combtuningR2);
fluid_comb_setbuffer(&rev->combL[2], rev->bufcombL3, combtuningL3);
fluid_comb_setbuffer(&rev->combR[2], rev->bufcombR3, combtuningR3);
fluid_comb_setbuffer(&rev->combL[3], rev->bufcombL4, combtuningL4);
fluid_comb_setbuffer(&rev->combR[3], rev->bufcombR4, combtuningR4);
fluid_comb_setbuffer(&rev->combL[4], rev->bufcombL5, combtuningL5);
fluid_comb_setbuffer(&rev->combR[4], rev->bufcombR5, combtuningR5);
fluid_comb_setbuffer(&rev->combL[5], rev->bufcombL6, combtuningL6);
fluid_comb_setbuffer(&rev->combR[5], rev->bufcombR6, combtuningR6);
fluid_comb_setbuffer(&rev->combL[6], rev->bufcombL7, combtuningL7);
fluid_comb_setbuffer(&rev->combR[6], rev->bufcombR7, combtuningR7);
fluid_comb_setbuffer(&rev->combL[7], rev->bufcombL8, combtuningL8);
fluid_comb_setbuffer(&rev->combR[7], rev->bufcombR8, combtuningR8);
fluid_allpass_setbuffer(&rev->allpassL[0], rev->bufallpassL1, allpasstuningL1);
fluid_allpass_setbuffer(&rev->allpassR[0], rev->bufallpassR1, allpasstuningR1);
fluid_allpass_setbuffer(&rev->allpassL[1], rev->bufallpassL2, allpasstuningL2);
fluid_allpass_setbuffer(&rev->allpassR[1], rev->bufallpassR2, allpasstuningR2);
fluid_allpass_setbuffer(&rev->allpassL[2], rev->bufallpassL3, allpasstuningL3);
fluid_allpass_setbuffer(&rev->allpassR[2], rev->bufallpassR3, allpasstuningR3);
fluid_allpass_setbuffer(&rev->allpassL[3], rev->bufallpassL4, allpasstuningL4);
fluid_allpass_setbuffer(&rev->allpassR[3], rev->bufallpassR4, allpasstuningR4);
/* Set default values */
fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
fluid_allpass_setfeedback(&rev->allpassL[1], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[1], 0.5f);
fluid_allpass_setfeedback(&rev->allpassL[2], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[2], 0.5f);
fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
/* set values manually, since calling set functions causes update
and all values should be initialized for an update */
rev->roomsize = initialroom * scaleroom + offsetroom;
rev->damp = initialdamp * scaledamp;
rev->wet = initialwet * scalewet;
rev->width = initialwidth;
rev->gain = fixedgain;
/* now its okay to update reverb */
fluid_revmodel_update(rev);
/* Clear all buffers */
fluid_revmodel_init(rev);
return rev;
}
void
delete_fluid_revmodel(fluid_revmodel_t* rev)
{
FLUID_FREE(rev);
}
void
fluid_revmodel_init(fluid_revmodel_t* rev)
{
int i;
for (i = 0; i < numcombs;i++) {
fluid_comb_init(&rev->combL[i]);
fluid_comb_init(&rev->combR[i]);
}
for (i = 0; i < numallpasses; i++) {
fluid_allpass_init(&rev->allpassL[i]);
fluid_allpass_init(&rev->allpassR[i]);
}
}
void
fluid_revmodel_reset(fluid_revmodel_t* rev)
{
fluid_revmodel_init(rev);
}
void
fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
int i, k = 0;
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
outL = outR = 0;
/* The original Freeverb code expects a stereo signal and 'input'
* is set to the sum of the left and right input sample. Since
* this code works on a mono signal, 'input' is set to twice the
* input sample. */
input = (2 * in[k] + DC_OFFSET) * rev->gain;
/* Accumulate comb filters in parallel */
for (i = 0; i < numcombs; i++) {
fluid_comb_process(rev->combL[i], input, outL);
fluid_comb_process(rev->combR[i], input, outR);
}
/* Feed through allpasses in series */
for (i = 0; i < numallpasses; i++) {
fluid_allpass_process(rev->allpassL[i], outL);
fluid_allpass_process(rev->allpassR[i], outR);
}
/* Remove the DC offset */
outL -= DC_OFFSET;
outR -= DC_OFFSET;
/* Calculate output REPLACING anything already there */
left_out[k] = outL * rev->wet1 + outR * rev->wet2;
right_out[k] = outR * rev->wet1 + outL * rev->wet2;
}
}
void
fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
int i, k = 0;
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
outL = outR = 0;
/* The original Freeverb code expects a stereo signal and 'input'
* is set to the sum of the left and right input sample. Since
* this code works on a mono signal, 'input' is set to twice the
* input sample. */
input = (2 * in[k] + DC_OFFSET) * rev->gain;
/* Accumulate comb filters in parallel */
for (i = 0; i < numcombs; i++) {
fluid_comb_process(rev->combL[i], input, outL);
fluid_comb_process(rev->combR[i], input, outR);
}
/* Feed through allpasses in series */
for (i = 0; i < numallpasses; i++) {
fluid_allpass_process(rev->allpassL[i], outL);
fluid_allpass_process(rev->allpassR[i], outR);
}
/* Remove the DC offset */
outL -= DC_OFFSET;
outR -= DC_OFFSET;
/* Calculate output MIXING with anything already there */
left_out[k] += outL * rev->wet1 + outR * rev->wet2;
right_out[k] += outR * rev->wet1 + outL * rev->wet2;
}
}
void
fluid_revmodel_update(fluid_revmodel_t* rev)
{
/* Recalculate internal values after parameter change */
int i;
rev->wet1 = rev->wet * (rev->width / 2 + 0.5f);
rev->wet2 = rev->wet * ((1 - rev->width) / 2);
for (i = 0; i < numcombs; i++) {
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);
}
}
/*
The following get/set functions are not inlined, because
speed is never an issue when calling them, and also
because as you develop the reverb model, you may
wish to take dynamic action when they are called.
*/
void
fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value)
{
/* fluid_clip(value, 0.0f, 1.0f); */
rev->roomsize = (value * scaleroom) + offsetroom;
fluid_revmodel_update(rev);
}
fluid_real_t
fluid_revmodel_getroomsize(fluid_revmodel_t* rev)
{
return (rev->roomsize - offsetroom) / scaleroom;
}
void
fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value)
{
/* fluid_clip(value, 0.0f, 1.0f); */
rev->damp = value * scaledamp;
fluid_revmodel_update(rev);
}
fluid_real_t
fluid_revmodel_getdamp(fluid_revmodel_t* rev)
{
return rev->damp / scaledamp;
}
void
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
{
/* fluid_clip(value, 0.0f, 1.0f); */
/* rev->wet = value * scalewet; */
/* fluid_revmodel_update(rev); */
}
fluid_real_t
fluid_revmodel_getlevel(fluid_revmodel_t* rev)
{
return rev->wet / scalewet;
}
void
fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value)
{
/* fluid_clip(value, 0.0f, 1.0f); */
rev->width = value;
fluid_revmodel_update(rev);
}
fluid_real_t
fluid_revmodel_getwidth(fluid_revmodel_t* rev)
{
return rev->width;
}
+67
View File
@@ -0,0 +1,67 @@
/* 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_REV_H
#define _FLUID_REV_H
#include "fluidsynth_priv.h"
typedef struct _fluid_revmodel_t fluid_revmodel_t;
/*
* reverb
*/
fluid_revmodel_t* new_fluid_revmodel(void);
void delete_fluid_revmodel(fluid_revmodel_t* rev);
void fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out);
void fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out);
void fluid_revmodel_reset(fluid_revmodel_t* rev);
void fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value);
void fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value);
void fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value);
void fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value);
void fluid_revmodel_setmode(fluid_revmodel_t* rev, fluid_real_t value);
fluid_real_t fluid_revmodel_getroomsize(fluid_revmodel_t* rev);
fluid_real_t fluid_revmodel_getdamp(fluid_revmodel_t* rev);
fluid_real_t fluid_revmodel_getlevel(fluid_revmodel_t* rev);
fluid_real_t fluid_revmodel_getwidth(fluid_revmodel_t* rev);
/*
* reverb preset
*/
typedef struct _fluid_revmodel_presets_t {
char* name;
fluid_real_t roomsize;
fluid_real_t damp;
fluid_real_t width;
fluid_real_t level;
} fluid_revmodel_presets_t;
#endif /* _FLUID_REV_H */
File diff suppressed because it is too large Load Diff
+159
View File
@@ -0,0 +1,159 @@
/* 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
*/
/*
2002 : API design by Peter Hanappe and Antoine Schmitt
August 2002 : Implementation by Antoine Schmitt [email protected]
as part of the infiniteCD author project
http://www.infiniteCD.org/
*/
#include "fluidsynth_priv.h"
/***************************************************************
*
* SEQUENCER BINDING
*/
void fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* event, fluid_sequencer_t* seq, void* data);
/* registering the synth */
short fluid_sequencer_register_fluidsynth(fluid_sequencer_t* seq, fluid_synth_t* synth)
{
/* register fluidsynth itself */
return fluid_sequencer_register_client(seq, "fluidsynth", fluid_seq_fluidsynth_callback, (void *)synth);
}
/* the callback itself */
void fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_sequencer_t* seq, void* data)
{
fluid_synth_t* synth = (fluid_synth_t *)data;
switch (fluid_event_get_type(evt)) {
case FLUID_SEQ_NOTEON:
fluid_synth_noteon(synth, fluid_event_get_channel(evt), fluid_event_get_key(evt), fluid_event_get_velocity(evt));
break;
case FLUID_SEQ_NOTEOFF:
fluid_synth_noteoff(synth, fluid_event_get_channel(evt), fluid_event_get_key(evt));
break;
case FLUID_SEQ_NOTE:
{
unsigned int dur;
fluid_synth_noteon(synth, fluid_event_get_channel(evt), fluid_event_get_key(evt), fluid_event_get_velocity(evt));
dur = fluid_event_get_duration(evt);
fluid_event_noteoff(evt, fluid_event_get_channel(evt), fluid_event_get_key(evt));
fluid_sequencer_send_at(seq, evt, dur, 0);
}
break;
case FLUID_SEQ_ALLSOUNDSOFF:
/* NYI */
break;
case FLUID_SEQ_ALLNOTESOFF:
fluid_synth_cc(synth, fluid_event_get_channel(evt), 0x7B, 0);
break;
case FLUID_SEQ_BANKSELECT:
fluid_synth_bank_select(synth, fluid_event_get_channel(evt), fluid_event_get_bank(evt));
break;
case FLUID_SEQ_PROGRAMCHANGE:
fluid_synth_program_change(synth, fluid_event_get_channel(evt), fluid_event_get_program(evt));
break;
case FLUID_SEQ_PROGRAMSELECT:
fluid_synth_program_select(synth, fluid_event_get_channel(evt), fluid_event_get_sfont_id(evt),
fluid_event_get_bank(evt), fluid_event_get_program(evt));
break;
case FLUID_SEQ_ANYCONTROLCHANGE:
/* nothing = only used by remove_events */
break;
case FLUID_SEQ_PITCHBEND:
fluid_synth_pitch_bend(synth, fluid_event_get_channel(evt), fluid_event_get_pitch(evt));
break;
case FLUID_SEQ_PITCHWHHELSENS:
fluid_synth_pitch_wheel_sens(synth, fluid_event_get_channel(evt), fluid_event_get_value(evt));
break;
case FLUID_SEQ_CONTROLCHANGE:
fluid_synth_cc(synth, fluid_event_get_channel(evt), fluid_event_get_control(evt), fluid_event_get_value(evt));
break;
case FLUID_SEQ_MODULATION:
{
short ctrl = 0x01; // MODULATION_MSB
fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
}
break;
case FLUID_SEQ_SUSTAIN:
{
short ctrl = 0x40; // SUSTAIN_SWITCH
fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
}
break;
case FLUID_SEQ_PAN:
{
short ctrl = 0x0A; // PAN_MSB
fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
}
break;
case FLUID_SEQ_VOLUME:
{
short ctrl = 0x07; // VOLUME_MSB
fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
}
break;
case FLUID_SEQ_REVERBSEND:
{
short ctrl = 0x5B; // EFFECTS_DEPTH1
fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
}
break;
case FLUID_SEQ_CHORUSSEND:
{
short ctrl = 0x5D; // EFFECTS_DEPTH3
fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
}
break;
case FLUID_SEQ_TIMER:
/* nothing in fluidsynth */
break;
default:
break;
}
}
+883
View File
@@ -0,0 +1,883 @@
/* 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 "fluidsynth_priv.h"
#include "fluid_settings.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"
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);
typedef struct {
char* value;
char* def;
int hints;
fluid_list_t* options;
fluid_str_update_t update;
void* data;
} fluid_str_setting_t;
static fluid_str_setting_t*
new_fluid_str_setting(char* value, char* def, int hints, fluid_str_update_t fun, void* data)
{
fluid_str_setting_t* str;
str = FLUID_NEW(fluid_str_setting_t);
str->value = value? FLUID_STRDUP(value) : NULL;
str->def = def? FLUID_STRDUP(def) : NULL;
str->hints = hints;
str->options = NULL;
str->update = fun;
str->data = data;
return str;
}
static void delete_fluid_str_setting(fluid_str_setting_t* str)
{
if (str) {
if (str->value) {
FLUID_FREE(str->value);
}
if (str->def) {
FLUID_FREE(str->def);
}
if (str->options) {
delete_fluid_list(str->options);
}
FLUID_FREE(str);
}
}
typedef struct {
double value;
double def;
double min;
double max;
int hints;
fluid_num_update_t update;
void* data;
} fluid_num_setting_t;
static fluid_num_setting_t*
new_fluid_num_setting(double min, double max, double def,
int hints, fluid_num_update_t fun, void* data)
{
fluid_num_setting_t* setting;
setting = FLUID_NEW(fluid_num_setting_t);
setting->value = def;
setting->def = def;
setting->min = min;
setting->max = max;
setting->hints = hints;
setting->update = fun;
setting->data = data;
return setting;
}
static void delete_fluid_num_setting(fluid_num_setting_t* setting)
{
if (setting) {
FLUID_FREE(setting);
}
}
typedef struct {
int value;
int def;
int min;
int max;
int hints;
fluid_int_update_t update;
void* data;
} fluid_int_setting_t;
static fluid_int_setting_t*
new_fluid_int_setting(int min, int max, int def,
int hints, fluid_int_update_t fun, void* data)
{
fluid_int_setting_t* setting;
setting = FLUID_NEW(fluid_int_setting_t);
setting->value = def;
setting->def = def;
setting->min = min;
setting->max = max;
setting->hints = hints;
setting->update = fun;
setting->data = data;
return setting;
}
static void delete_fluid_int_setting(fluid_int_setting_t* setting)
{
if (setting) {
FLUID_FREE(setting);
}
}
fluid_settings_t* new_fluid_settings()
{
fluid_settings_t* settings = new_fluid_hashtable(fluid_settings_hash_delete);
if (settings == NULL) {
return NULL;
}
fluid_settings_init(settings);
return settings;
}
void delete_fluid_settings(fluid_settings_t* settings)
{
delete_fluid_hashtable(settings);
}
void fluid_settings_hash_delete(void* value, int type)
{
switch (type) {
case FLUID_NUM_TYPE:
delete_fluid_num_setting((fluid_num_setting_t*) value);
break;
case FLUID_INT_TYPE:
delete_fluid_int_setting((fluid_int_setting_t*) value);
break;
case FLUID_STR_TYPE:
delete_fluid_str_setting((fluid_str_setting_t*) value);
break;
case FLUID_SET_TYPE:
delete_fluid_hashtable((fluid_hashtable_t*) value);
break;
}
}
void fluid_settings_init(fluid_settings_t* settings)
{
fluid_synth_settings(settings);
fluid_shell_settings(settings);
fluid_audio_driver_settings(settings);
fluid_midi_driver_settings(settings);
}
static fluid_strtok_t* fluid_settings_strtok = NULL;
int fluid_settings_tokenize(char* s, char* buf, char** ptr)
{
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, ".");
}
while (fluid_strtok_has_more(fluid_settings_strtok)) {
ptr[n++] = fluid_strtok_next_token(fluid_settings_strtok);
}
return n;
}
/** returns 1 if the value exists, 0 otherwise */
static int fluid_settings_get(fluid_settings_t* settings,
char** name, int len,
void** value, int* type)
{
fluid_hashtable_t* table = settings;
int t;
void* v;
int n;
for (n = 0; n < len; n++) {
if (table == NULL) {
return 0;
}
if (!fluid_hashtable_lookup(table, name[n], &v, &t)) {
return 0;
}
table = (t == FLUID_SET_TYPE)? (fluid_hashtable_t*) v : NULL;
}
if (value) {
*value = v;
}
if (type) {
*type = t;
}
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,
void* value, int type)
{
fluid_hashtable_t* table = settings;
int t;
void* v;
int n, num = len - 1;
for (n = 0; n < num; n++) {
if (fluid_hashtable_lookup(table, name[n], &v, &t)) {
if (t == FLUID_SET_TYPE) {
table = (fluid_hashtable_t*) v;
} else {
/* path ends prematurely */
FLUID_LOG(FLUID_WARN, "'%s' is not a node", name[n]);
return 0;
}
} else {
/* create a new node */
fluid_hashtable_t* tmp;
tmp = new_fluid_hashtable(fluid_settings_hash_delete);
fluid_hashtable_insert(table, name[n], tmp, FLUID_SET_TYPE);
table = tmp;
}
}
fluid_hashtable_replace(table, name[num], value, type);
return 1;
}
/** returns 1 if the value has been resgister 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];
int ntokens;
fluid_str_setting_t* setting;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (!fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
setting = new_fluid_str_setting(def, def, hints, fun, data);
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_STR_TYPE);
} else {
/* if variable already exists, don't change its value. */
if (type == FLUID_STR_TYPE) {
setting = (fluid_str_setting_t*) value;
setting->update = fun;
setting->data = data;
setting->def = def? FLUID_STRDUP(def) : NULL;
setting->hints = hints;
return 1;
} else {
FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
return 1;
}
}
}
/** returns 1 if the value has been register correctly, zero
otherwise */
int fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
double min, double max, int hints,
fluid_num_update_t fun, void* data)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (!fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
/* insert a new setting */
fluid_num_setting_t* setting;
setting = new_fluid_num_setting(min, max, def, hints, fun, data);
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_NUM_TYPE);
} else {
if (type == FLUID_NUM_TYPE) {
/* update the existing setting but don't change its value */
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
setting->update = fun;
setting->data = data;
setting->min = min;
setting->max = max;
setting->def = def;
setting->hints = hints;
return 1;
} else {
/* type mismatch */
FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
return 0;
}
}
}
/** returns 1 if the value has been register correctly, zero
otherwise */
int fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
int min, int max, int hints,
fluid_int_update_t fun, void* data)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (!fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
/* insert a new setting */
fluid_int_setting_t* setting;
setting = new_fluid_int_setting(min, max, def, hints, fun, data);
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_INT_TYPE);
} else {
if (type == FLUID_INT_TYPE) {
/* update the existing setting but don't change its value */
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
setting->update = fun;
setting->data = data;
setting->min = min;
setting->max = max;
setting->def = def;
setting->hints = hints;
return 1;
} else {
/* type mismatch */
FLUID_LOG(FLUID_WARN, "Type mismatch on setting '%s'", name);
return 0;
}
}
}
int fluid_settings_get_type(fluid_settings_t* settings, char* name)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
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];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
if (type == FLUID_NUM_TYPE) {
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
return setting->hints;
} else if (type == FLUID_STR_TYPE) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
return setting->hints;
} else {
return 0;
}
} else {
return 0;
}
}
int fluid_settings_is_realtime(fluid_settings_t* settings, char* name)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
if (type == FLUID_NUM_TYPE) {
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
return setting->update != NULL;
} else if (type == FLUID_STR_TYPE) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
return setting->update != NULL;
} else {
return 0;
}
} else {
return 0;
}
}
int fluid_settings_setstr(fluid_settings_t* settings, char* name, char* str)
{
char buf[1024];
char* tokens[16];
int ntokens;
int type;
void* value;
fluid_str_setting_t* setting;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
if (type != FLUID_STR_TYPE) {
return 0;
}
setting = (fluid_str_setting_t*) value;
if (setting->value) {
FLUID_FREE(setting->value);
}
setting->value = str? FLUID_STRDUP(str) : NULL;
if (setting->update) {
(*setting->update)(setting->data, name, setting->value);
}
return 1;
} else {
/* insert a new setting */
fluid_str_setting_t* setting;
setting = new_fluid_str_setting(str, NULL, 0, NULL, NULL);
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_STR_TYPE);
}
}
int fluid_settings_getstr(fluid_settings_t* settings, char* name, char** str)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_STR_TYPE)) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
*str = setting->value;
return 1;
}
*str = NULL;
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];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_STR_TYPE)) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
return FLUID_STRCMP(setting->value, s) == 0;
}
return 0;
}
char*
fluid_settings_getstr_default(fluid_settings_t* settings, char* name)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_STR_TYPE)) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
return setting->def;
} else {
return NULL;
}
}
int fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_STR_TYPE)) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
char* copy = FLUID_STRDUP(s);
setting->options = fluid_list_append(setting->options, copy);
return 1;
} else {
return 0;
}
}
int fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_STR_TYPE)) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
fluid_list_t* list = setting->options;
while (list) {
char* option = (char*) fluid_list_get(list);
if (FLUID_STRCMP(s, option) == 0) {
setting->options = fluid_list_remove_link(setting->options, list);
return 1;
}
list = fluid_list_next(list);
}
return 0;
} else {
return 0;
}
}
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];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
if (type != FLUID_NUM_TYPE) {
return 0;
}
setting = (fluid_num_setting_t*) value;
if (val < setting->min) {
val = setting->min;
} else if (val > setting->max) {
val = setting->max;
}
setting->value = val;
if (setting->update) {
(*setting->update)(setting->data, name, val);
}
return 1;
} else {
/* insert a new setting */
fluid_num_setting_t* setting;
setting = new_fluid_num_setting(-1e10, 1e10, 0.0f, 0, NULL, NULL);
setting->value = val;
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_NUM_TYPE);
}
}
int fluid_settings_getnum(fluid_settings_t* settings, char* name, double* val)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_NUM_TYPE)) {
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
*val = setting->value;
return 1;
}
return 0;
}
void fluid_settings_getnum_range(fluid_settings_t* settings, char* name, double* min, double* max)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_NUM_TYPE)) {
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
*min = setting->min;
*max = setting->max;
}
}
double
fluid_settings_getnum_default(fluid_settings_t* settings, char* name)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_NUM_TYPE)) {
fluid_num_setting_t* setting = (fluid_num_setting_t*) value;
return setting->def;
} else {
return 0.0f;
}
}
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];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)) {
if (type != FLUID_INT_TYPE) {
return 0;
}
setting = (fluid_int_setting_t*) value;
if (val < setting->min) {
val = setting->min;
} else if (val > setting->max) {
val = setting->max;
}
setting->value = val;
if (setting->update) {
(*setting->update)(setting->data, name, val);
}
return 1;
} else {
/* insert a new setting */
fluid_int_setting_t* setting;
setting = new_fluid_int_setting(INT_MIN, INT_MAX, 0, 0, NULL, NULL);
setting->value = val;
return fluid_settings_set(settings, tokens, ntokens, setting, FLUID_INT_TYPE);
}
}
int fluid_settings_getint(fluid_settings_t* settings, char* name, int* val)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_INT_TYPE)) {
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
*val = setting->value;
return 1;
}
return 0;
}
void fluid_settings_getint_range(fluid_settings_t* settings, char* name, int* min, int* max)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_INT_TYPE)) {
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
*min = setting->min;
*max = setting->max;
}
}
int
fluid_settings_getint_default(fluid_settings_t* settings, char* name)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_INT_TYPE)) {
fluid_int_setting_t* setting = (fluid_int_setting_t*) value;
return setting->def;
} else {
return 0.0f;
}
}
void fluid_settings_foreach_option(fluid_settings_t* settings, char* name, void* data,
fluid_settings_foreach_option_t func)
{
int type;
void* value;
char buf[1024];
char* tokens[16];
int ntokens;
if (!func) {
return;
}
ntokens = fluid_settings_tokenize(name, buf, tokens);
if (fluid_settings_get(settings, tokens, ntokens, &value, &type)
&& (type == FLUID_STR_TYPE)) {
fluid_str_setting_t* setting = (fluid_str_setting_t*) value;
fluid_list_t* list = setting->options;
while (list) {
char* option = (char*) fluid_list_get(list);
(*func)(data, name, option);
list = fluid_list_next(list);
}
}
}
static fluid_settings_foreach_t fluid_settings_foreach_func;
static void* fluid_settings_foreach_data;
int fluid_settings_foreach_iter(char* key, void* value, int type, void* data)
{
char path[1024];
if (data == 0) {
snprintf(path, 1024, "%s", key);
} else {
snprintf(path, 1024, "%s.%s", (char*) data, key);
}
path[1023] = 0;
switch (type) {
case FLUID_NUM_TYPE:
case FLUID_INT_TYPE:
case FLUID_STR_TYPE:
(*fluid_settings_foreach_func)(fluid_settings_foreach_data, path, type);
break;
case FLUID_SET_TYPE:
fluid_hashtable_foreach((fluid_hashtable_t*) value, fluid_settings_foreach_iter, &path[0]);
break;
}
return 0;
}
void fluid_settings_foreach(fluid_settings_t* settings, void* data, fluid_settings_foreach_t func)
{
fluid_settings_foreach_func = func;
fluid_settings_foreach_data = data;
fluid_hashtable_foreach(settings, fluid_settings_foreach_iter, 0);
}
+55
View File
@@ -0,0 +1,55 @@
/* 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_SETTINGS_H
#define _FLUID_SETTINGS_H
/** returns 1 if the option was added, 0 otherwise */
int fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s);
/** returns 1 if the option was added, 0 otherwise */
int fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s);
typedef int (*fluid_num_update_t)(void* data, char* name, double value);
typedef int (*fluid_str_update_t)(void* data, char* name, char* value);
typedef int (*fluid_int_update_t)(void* data, char* name, int value);
/** returns 0 if the value has been resgister correctly, non-zero
otherwise */
int fluid_settings_register_str(fluid_settings_t* settings, char* name, char* def, int hints,
fluid_str_update_t fun, void* data);
/** returns 0 if the value has been resgister correctly, non-zero
otherwise */
int fluid_settings_register_num(fluid_settings_t* settings, char* name, double min, double max,
double def, int hints, fluid_num_update_t fun, void* data);
/** returns 0 if the value has been resgister correctly, non-zero
otherwise */
int fluid_settings_register_int(fluid_settings_t* settings, char* name, int min, int max,
int def, int hints, fluid_int_update_t fun, void* data);
#endif /* _FLUID_SETTINGS_H */
+68
View File
@@ -0,0 +1,68 @@
/* 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 _PRIV_FLUID_SFONT_H
#define _PRIV_FLUID_SFONT_H
/*
* Utility macros to access soundfonts, presets, and samples
*/
#define fluid_sfloader_delete(_loader) { if ((_loader) && (_loader)->free) (*(_loader)->free)(_loader); }
#define fluid_sfloader_load(_loader, _filename) (*(_loader)->load)(_loader, _filename)
#define delete_fluid_sfont(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
#define fluid_sfont_get_name(_sf) (*(_sf)->get_name)(_sf)
#define fluid_sfont_get_preset(_sf,_bank,_prenum) (*(_sf)->get_preset)(_sf,_bank,_prenum)
#define fluid_sfont_iteration_start(_sf) (*(_sf)->iteration_start)(_sf)
#define fluid_sfont_iteration_next(_sf,_pr) (*(_sf)->iteration_next)(_sf,_pr)
#define fluid_sfont_get_data(_sf) (_sf)->data
#define fluid_sfont_set_data(_sf,_p) { (_sf)->data = (void*) (_p); }
#define delete_fluid_preset(_preset) \
{ if ((_preset) && (_preset)->free) { (*(_preset)->free)(_preset); }}
#define fluid_preset_get_data(_preset) (_preset)->data
#define fluid_preset_set_data(_preset,_p) { (_preset)->data = (void*) (_p); }
#define fluid_preset_get_name(_preset) (*(_preset)->get_name)(_preset)
#define fluid_preset_get_banknum(_preset) (*(_preset)->get_banknum)(_preset)
#define fluid_preset_get_num(_preset) (*(_preset)->get_num)(_preset)
#define fluid_preset_noteon(_preset,_synth,_ch,_key,_vel) \
(*(_preset)->noteon)(_preset,_synth,_ch,_key,_vel)
#define fluid_preset_notify(_preset,_reason,_chan) \
{ if ((_preset) && (_preset)->notify) { (*(_preset)->notify)(_preset,_reason,_chan); }}
#define fluid_sample_incr_ref(_sample) { (_sample)->refcount++; }
#define fluid_sample_decr_ref(_sample) \
(_sample)->refcount--; \
if (((_sample)->refcount == 0) && ((_sample)->notify)) \
(*(_sample)->notify)(_sample, FLUID_SAMPLE_DONE);
#endif /* _PRIV_FLUID_SFONT_H */
+263
View File
@@ -0,0 +1,263 @@
/*
* 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
@@ -0,0 +1,123 @@
/* 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
@@ -0,0 +1,44 @@
/* 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 */
File diff suppressed because it is too large Load Diff
+221
View File
@@ -0,0 +1,221 @@
/* 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_SYNTH_H
#define _FLUID_SYNTH_H
/***************************************************************
*
* INCLUDES
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "fluidsynth_priv.h"
#include "fluid_list.h"
#include "fluid_rev.h"
#include "fluid_voice.h"
#include "fluid_chorus.h"
#include "fluid_ladspa.h"
#include "fluid_midi_router.h"
#include "fluid_sys.h"
/***************************************************************
*
* DEFINES
*/
#define FLUID_NUM_PROGRAMS 129
#define DRUM_INST_MASK ((unsigned int)0x80000000)
#if defined(WITH_FLOAT)
#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_FLOAT
#else
#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_DOUBLE
#endif
/***************************************************************
*
* ENUM
*/
enum fluid_loop {
FLUID_UNLOOPED = 0,
FLUID_LOOP_DURING_RELEASE = 1,
FLUID_NOTUSED = 2,
FLUID_LOOP_UNTIL_RELEASE = 3
};
enum fluid_synth_status
{
FLUID_SYNTH_CLEAN,
FLUID_SYNTH_PLAYING,
FLUID_SYNTH_QUIET,
FLUID_SYNTH_STOPPED
};
typedef struct _fluid_bank_offset_t fluid_bank_offset_t;
struct _fluid_bank_offset_t {
int sfont_id;
int offset;
};
/*
* fluid_synth_t
*/
struct _fluid_synth_t
{
/* fluid_settings_old_t settings_old; the old synthesizer settings */
fluid_settings_t* settings; /** the synthesizer settings */
int polyphony; /** maximum polyphony */
char with_reverb; /** Should the synth use the built-in reverb unit? */
char with_chorus; /** Should the synth use the built-in chorus unit? */
char verbose; /** Turn verbose mode on? */
char dump; /** Dump events to stdout to hook up a user interface? */
double sample_rate; /** The sample rate */
int midi_channels; /** the number of MIDI channels (>= 16) */
int audio_channels; /** the number of audio channels (1 channel=left+right) */
int audio_groups; /** the number of (stereo) 'sub'groups from the synth.
Typically equal to audio_channels. */
int effects_channels; /** the number of effects channels (= 2) */
unsigned int state; /** the synthesizer state */
unsigned int ticks; /** the number of audio samples since the start */
unsigned int start; /** the start in msec, as returned by system clock */
fluid_list_t *loaders; /** the soundfont loaders */
fluid_list_t* sfont; /** the loaded soundfont */
unsigned int sfont_id;
fluid_list_t* bank_offsets; /** the offsets of the soundfont banks */
#if defined(MACOS9)
fluid_list_t* unloading; /** the soundfonts that need to be unloaded */
#endif
double gain; /** master gain */
fluid_channel_t** channel; /** the channels */
int num_channels; /** the number of channels */
int nvoice; /** the length of the synthesis process array */
fluid_voice_t** voice; /** the synthesis processes */
unsigned int noteid; /** the id is incremented for every new note. it's used for noteoff's */
unsigned int storeid;
int nbuf; /** How many audio buffers are used? (depends on nr of audio channels / groups)*/
fluid_real_t** left_buf;
fluid_real_t** right_buf;
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 */
char outbuf[256]; /** buffer for message output */
double cpu_load;
fluid_tuning_t*** tuning; /** 128 banks of 128 programs for the tunings */
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
fluid_mutex_t busy; /* Indicates, whether the audio thread is currently running.
* Note: This simple scheme does -not- provide 100 % protection against
* thread problems, for example from MIDI thread and shell thread
*/
#ifdef LADSPA
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /** Effects unit for LADSPA support */
#endif
};
/** returns 1 if the value has been set, 0 otherwise */
int fluid_synth_setstr(fluid_synth_t* synth, char* name, char* str);
/** returns 1 if the value exists, 0 otherwise */
int fluid_synth_getstr(fluid_synth_t* synth, char* name, char** str);
/** returns 1 if the value has been set, 0 otherwise */
int fluid_synth_setnum(fluid_synth_t* synth, char* name, double val);
/** returns 1 if the value exists, 0 otherwise */
int fluid_synth_getnum(fluid_synth_t* synth, char* name, double* val);
/** returns 1 if the value has been set, 0 otherwise */
int fluid_synth_setint(fluid_synth_t* synth, char* name, int val);
/** returns 1 if the value exists, 0 otherwise */
int fluid_synth_getint(fluid_synth_t* synth, char* name, int* val);
int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num);
int fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out);
fluid_preset_t* fluid_synth_get_preset(fluid_synth_t* synth,
unsigned int sfontnum,
unsigned int banknum,
unsigned int prognum);
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
unsigned int banknum,
unsigned int prognum);
int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan);
int fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan);
int fluid_synth_modulate_voices(fluid_synth_t* synth, int chan, int is_cc, int ctrl);
int fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan);
int fluid_synth_damp_voices(fluid_synth_t* synth, int chan);
int fluid_synth_kill_voice(fluid_synth_t* synth, fluid_voice_t * voice);
void fluid_synth_kill_by_exclusive_class(fluid_synth_t* synth, fluid_voice_t* voice);
void fluid_synth_release_voice_on_same_note(fluid_synth_t* synth, int chan, int key);
void fluid_synth_sfunload_macos9(fluid_synth_t* synth);
void fluid_synth_print_voice(fluid_synth_t* synth);
/** This function assures that every MIDI channels has a valid preset
* (NULL is okay). This function is called after a SoundFont is
* unloaded or reloaded. */
void fluid_synth_update_presets(fluid_synth_t* synth);
int fluid_synth_update_gain(fluid_synth_t* synth, char* name, double value);
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);
/*
* misc
*/
void fluid_synth_settings(fluid_settings_t* settings);
#endif /* _FLUID_SYNTH_H */
File diff suppressed because it is too large Load Diff
+305
View File
@@ -0,0 +1,305 @@
/* 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
*/
/**
This header contains a bunch of (mostly) system and machine
dependent functions:
- timers
- current time in milliseconds and microseconds
- debug logging
- profiling
- memory locking
- checking for floating point exceptions
*/
#ifndef _FLUID_SYS_H
#define _FLUID_SYS_H
#include "fluidsynth_priv.h"
void fluid_sys_config(void);
void fluid_log_config(void);
void fluid_time_config(void);
/**
Additional debugging system, separate from the log system. This
allows to print selected debug messages of a specific subsystem.
*/
extern unsigned int fluid_debug_flags;
#if DEBUG
enum fluid_debug_level {
FLUID_DBG_DRIVER = 1
};
int fluid_debug(int level, char * fmt, ...);
#else
#define fluid_debug
#endif
/** fluid_curtime() returns the current time in milliseconds. This time
should only be used in relative time measurements. */
/** fluid_utime() returns the time in micro seconds. this time should
only be used to measure duration (relative times). */
#if defined(WIN32)
#define fluid_curtime() GetTickCount()
double fluid_utime(void);
#elif defined(MACOS9)
#include <OSUtils.h>
#include <Timer.h>
unsigned int fluid_curtime();
#define fluid_utime() 0.0
#elif defined(__BEOS__)
#include <OS.h>
unsigned int fluid_curtime(void);
double fluid_utime(void);
#else
unsigned int fluid_curtime(void);
double fluid_utime(void);
#endif
/**
Timers
*/
/* if the callback function returns 1 the timer will continue; if it
returns 0 it will stop */
typedef int (*fluid_timer_callback_t)(void* data, unsigned int msec);
typedef struct _fluid_timer_t fluid_timer_t;
fluid_timer_t* new_fluid_timer(int msec, fluid_timer_callback_t callback,
void* data, int new_thread, int auto_destroy);
int delete_fluid_timer(fluid_timer_t* timer);
int fluid_timer_join(fluid_timer_t* timer);
int fluid_timer_stop(fluid_timer_t* timer);
/**
Muteces
*/
#if defined(MACOS9)
typedef int fluid_mutex_t;
#define fluid_mutex_init(_m) { (_m) = 0; }
#define fluid_mutex_destroy(_m)
#define fluid_mutex_lock(_m)
#define fluid_mutex_unlock(_m)
#elif defined(WIN32)
typedef HANDLE fluid_mutex_t;
#define fluid_mutex_init(_m) { (_m) = CreateMutex(NULL, 0, NULL); }
#define fluid_mutex_destroy(_m) if (_m) { CloseHandle(_m); }
#define fluid_mutex_lock(_m) WaitForSingleObject(_m, INFINITE)
#define fluid_mutex_unlock(_m) ReleaseMutex(_m)
#else
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
typedef sem_id fluid_mutex_t;
#define fluid_mutex_init(_m) { (_m) = create_sem(1, "fs_sem"); }
#define fluid_mutex_destroy(_m) delete_sem(_m);
#define fluid_mutex_lock(_m) acquire_sem(_m);
#define fluid_mutex_unlock(_m) release_sem(_m);
#else
typedef pthread_mutex_t fluid_mutex_t;
#define fluid_mutex_init(_m) pthread_mutex_init(&(_m), NULL)
#define fluid_mutex_destroy(_m) pthread_mutex_destroy(&(_m))
#define fluid_mutex_lock(_m) pthread_mutex_lock(&(_m))
#define fluid_mutex_unlock(_m) pthread_mutex_unlock(&(_m))
#endif
#endif
/**
Threads
*/
typedef struct _fluid_thread_t fluid_thread_t;
typedef void (*fluid_thread_func_t)(void* data);
/** When detached, 'join' does not work and the thread destroys itself
when finished. */
fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void* data, int detach);
int delete_fluid_thread(fluid_thread_t* thread);
int fluid_thread_join(fluid_thread_t* thread);
/**
Sockets
*/
/** The function should return 0 if no error occured, non-zero
otherwise. If the function return non-zero, the socket will be
closed by the server. */
typedef int (*fluid_server_func_t)(void* data, fluid_socket_t client_socket, char* addr);
fluid_server_socket_t* new_fluid_server_socket(int port, fluid_server_func_t func, void* data);
int delete_fluid_server_socket(fluid_server_socket_t* sock);
int fluid_server_socket_join(fluid_server_socket_t* sock);
/** Create a new client socket. */
fluid_socket_t new_fluid_client_socket(char* host, int port);
/** Delete the client socket. This function should only be called on
sockets create with 'new_fluid_client_socket'. */
void delete_fluid_client_socket(fluid_socket_t sock);
void fluid_socket_close(fluid_socket_t sock);
fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock);
fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock);
/**
Profiling
*/
/**
Profile numbers. List all the pieces of code you want to profile
here. Be sure to add an entry in the fluid_profile_data table in
fluid_sys.c
*/
enum {
FLUID_PROF_WRITE_S16,
FLUID_PROF_ONE_BLOCK,
FLUID_PROF_ONE_BLOCK_CLEAR,
FLUID_PROF_ONE_BLOCK_VOICE,
FLUID_PROF_ONE_BLOCK_VOICES,
FLUID_PROF_ONE_BLOCK_REVERB,
FLUID_PROF_ONE_BLOCK_CHORUS,
FLUID_PROF_VOICE_NOTE,
FLUID_PROF_VOICE_RELEASE,
FLUID_PROF_LAST
};
#if WITH_PROFILING
void fluid_profiling_print(void);
/** Profiling data. Keep track of min/avg/max values to execute a
piece of code. */
typedef struct _fluid_profile_data_t {
int num;
char* description;
double min, max, total;
unsigned int count;
} fluid_profile_data_t;
extern fluid_profile_data_t fluid_profile_data[];
/** Macro to obtain a time refence used for the profiling */
#define fluid_profile_ref() fluid_utime()
/** Macro to calculate the min/avg/max. Needs a time refence and a
profile number. */
#define fluid_profile(_num,_ref) { \
double _now = fluid_utime(); \
double _delta = _now - _ref; \
fluid_profile_data[_num].min = _delta < fluid_profile_data[_num].min ? _delta : fluid_profile_data[_num].min; \
fluid_profile_data[_num].max = _delta > fluid_profile_data[_num].max ? _delta : fluid_profile_data[_num].max; \
fluid_profile_data[_num].total += _delta; \
fluid_profile_data[_num].count++; \
_ref = _now; \
}
#else
/* No profiling */
#define fluid_profiling_print()
#define fluid_profile_ref() 0
#define fluid_profile(_num,_ref)
#endif
/**
Memory locking
Memory locking is used to avoid swapping of the large block of
sample data.
*/
#if HAVE_SYS_MMAN_H
#define fluid_mlock(_p,_n) mlock(_p, _n)
#define fluid_munlock(_p,_n) munlock(_p,_n)
#else
#define fluid_mlock(_p,_n) 0
#define fluid_munlock(_p,_n)
#endif
/**
Floating point exceptions
fluid_check_fpe() checks for "unnormalized numbers" and other
exceptions of the floating point processsor.
*/
#if 0
/* Enable FPE exception check */
#define fluid_check_fpe(expl) fluid_check_fpe_i386(expl)
#else
/* Disable FPE exception check */
#define fluid_check_fpe(expl)
#endif
unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe);
#endif /* _FLUID_SYS_H */
+108
View File
@@ -0,0 +1,108 @@
/* 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_tuning.h"
#include "fluidsynth_priv.h"
fluid_tuning_t* new_fluid_tuning(char* name, int bank, int prog)
{
fluid_tuning_t* tuning;
int i;
tuning = FLUID_NEW(fluid_tuning_t);
if (tuning == NULL) {
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
tuning->name = NULL;
if (name != NULL) {
tuning->name = FLUID_STRDUP(name);
}
tuning->bank = bank;
tuning->prog = prog;
for (i = 0; i < 128; i++) {
tuning->pitch[i] = i * 100.0;
}
return tuning;
}
void delete_fluid_tuning(fluid_tuning_t* tuning)
{
if (tuning == NULL) {
return;
}
if (tuning->name != NULL) {
FLUID_FREE(tuning->name);
}
FLUID_FREE(tuning);
}
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name)
{
if (tuning->name != NULL) {
FLUID_FREE(tuning->name);
tuning->name = NULL;
}
if (name != NULL) {
tuning->name = FLUID_STRDUP(name);
}
}
char* fluid_tuning_get_name(fluid_tuning_t* tuning)
{
return tuning->name;
}
void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
{
tuning->pitch[key] = pitch;
}
void fluid_tuning_set_octave(fluid_tuning_t* tuning, double* pitch_deriv)
{
int i;
for (i = 0; i < 128; i++) {
tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12];
}
}
void fluid_tuning_set_all(fluid_tuning_t* tuning, double* pitch)
{
int i;
for (i = 0; i < 128; i++) {
tuning->pitch[i] = pitch[i];
}
}
void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch)
{
if ((key >= 0) && (key < 128)) {
tuning->pitch[key] = pitch;
}
}
+64
View File
@@ -0,0 +1,64 @@
/* 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
*/
/*
More information about micro tuning can be found at:
http://www.midi.org/about-midi/tuning.htm
http://www.midi.org/about-midi/tuning-scale.htm
http://www.midi.org/about-midi/tuning_extens.htm
*/
#ifndef _FLUID_TUNING_H
#define _FLUID_TUNING_H
#include "fluidsynth_priv.h"
struct _fluid_tuning_t {
char* name;
int bank;
int prog;
double pitch[128]; /* the pitch of every key, in cents */
};
fluid_tuning_t* new_fluid_tuning(char* name, int bank, int prog);
void delete_fluid_tuning(fluid_tuning_t* tuning);
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name);
char* fluid_tuning_get_name(fluid_tuning_t* tuning);
#define fluid_tuning_get_bank(_t) ((_t)->bank)
#define fluid_tuning_get_prog(_t) ((_t)->prog)
void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch);
#define fluid_tuning_get_pitch(_t, _key) ((_t)->pitch[_key])
void fluid_tuning_set_octave(fluid_tuning_t* tuning, double* pitch_deriv);
void fluid_tuning_set_all(fluid_tuning_t* tuning, double* pitch);
#define fluid_tuning_get_all(_t) (&(_t)->pitch[0])
#endif /* _FLUID_TUNING_H */
File diff suppressed because it is too large Load Diff
+288
View File
@@ -0,0 +1,288 @@
/* 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_VOICE_H
#define _FLUID_VOICE_H
#include "fluid_phase.h"
#include "fluid_gen.h"
#include "fluid_mod.h"
#define NO_CHANNEL 0xff
enum fluid_voice_status
{
FLUID_VOICE_CLEAN,
FLUID_VOICE_ON,
FLUID_VOICE_SUSTAINED,
FLUID_VOICE_OFF
};
/*
* envelope data
*/
struct _fluid_env_data_t {
unsigned int count;
fluid_real_t coeff;
fluid_real_t incr;
fluid_real_t min;
fluid_real_t max;
};
/* Indices for envelope tables */
enum fluid_voice_envelope_index_t{
FLUID_VOICE_ENVDELAY,
FLUID_VOICE_ENVATTACK,
FLUID_VOICE_ENVHOLD,
FLUID_VOICE_ENVDECAY,
FLUID_VOICE_ENVSUSTAIN,
FLUID_VOICE_ENVRELEASE,
FLUID_VOICE_ENVFINISHED,
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
*/
struct _fluid_voice_t
{
unsigned int id; /* the id is incremented for every new noteon.
it's used for noteoff's */
unsigned char status;
unsigned char chan; /* the channel number, quick access for channel messages */
unsigned char key; /* the key, quick acces for noteoff */
unsigned char vel; /* the velocity */
fluid_channel_t* channel;
fluid_gen_t gen[GEN_LAST];
fluid_mod_t mod[FLUID_NUM_MOD];
int mod_count;
int has_looped; /* Flag that is set as soon as the first loop is completed. */
fluid_sample_t* sample;
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
have to be checked. */
#if 0
/* Instead of keeping a pointer to a fluid_sample_t structure,
* I think it would be better to copy the sample data in the
* voice structure. SoundFont loader then do not have to
* allocate and maintain the fluid_sample_t structure. [PH]
*
* The notify callback may be used also for streaming samples.
*/
short* sample_data; /* pointer to the sample data */
int sample_data_offset; /* the offset of data[0] in the whole sample */
int sample_data_length; /* the length of the data array */
unsigned int sample_start;
unsigned int sample_end;
unsigned int sample_loopstart;
unsigned int sample_loopend;
unsigned int sample_rate;
int sample_origpitch;
int sample_pitchadj;
int sample_type;
int (*sample_notify)(fluid_voice_t* voice, int reason);
void* sample_userdata;
#endif
/* basic parameters */
fluid_real_t output_rate; /* the sample rate of the synthesizer */
unsigned int start_time;
unsigned int ticks;
fluid_real_t amp; /* the 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
/* basic parameters */
fluid_real_t pitch; /* the pitch in midicents */
fluid_real_t attenuation; /* the attenuation in centibels */
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
* during the lifetime of the voice */
fluid_real_t root_pitch;
/* sample and loop start and end points (offset in sample memory). */
int start;
int end;
int loopstart;
int loopend;
/* master gain */
fluid_real_t synth_gain;
/* vol env */
fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST];
unsigned int volenv_count;
int volenv_section;
fluid_real_t volenv_val;
fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
fluid_real_t amplitude_that_reaches_noise_floor_loop;
/* mod env */
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
unsigned int modenv_count;
int modenv_section;
fluid_real_t modenv_val; /* the value of the modulation envelope */
fluid_real_t modenv_to_fc;
fluid_real_t modenv_to_pitch;
/* mod lfo */
fluid_real_t modlfo_val; /* the value of the modulation LFO */
unsigned int modlfo_delay; /* the delay of the lfo in samples */
fluid_real_t modlfo_incr; /* the lfo frequency is converted to a per-buffer increment */
fluid_real_t modlfo_to_fc;
fluid_real_t modlfo_to_pitch;
fluid_real_t modlfo_to_vol;
/* vib lfo */
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
unsigned int viblfo_delay; /* the delay of the lfo in samples */
fluid_real_t viblfo_incr; /* the lfo frequency is converted to a per-buffer increment */
fluid_real_t viblfo_to_pitch;
/* resonant filter */
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
/* Serves as a flag: A deviation between fres and last_fres */
/* indicates, that the filter has to be recalculated. */
fluid_real_t q_lin; /* the q-factor on a linear scale */
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
int filter_startup; /* Flag: If set, the filter will be set directly.
Else it changes smoothly. */
/* filter coefficients */
/* The coefficients are normalized to a0. */
/* b0 and b2 are identical => b02 */
fluid_real_t b02; /* b0 / a0 */
fluid_real_t b1; /* b1 / a0 */
fluid_real_t a1; /* a0 / a0 */
fluid_real_t a2; /* a1 / a0 */
fluid_real_t b02_incr;
fluid_real_t b1_incr;
fluid_real_t a1_incr;
fluid_real_t a2_incr;
int filter_coeff_incr_count;
/* pan */
fluid_real_t pan;
fluid_real_t amp_left;
fluid_real_t amp_right;
/* reverb */
fluid_real_t reverb_send;
fluid_real_t amp_reverb;
/* chorus */
fluid_real_t chorus_send;
fluid_real_t amp_chorus;
/* interpolation method, as in fluid_interp in fluidsynth.h */
int interp_method;
/* for debugging */
int debug;
double ref;
};
fluid_voice_t* new_fluid_voice(fluid_real_t output_rate);
int delete_fluid_voice(fluid_voice_t* voice);
void fluid_voice_start(fluid_voice_t* voice);
int fluid_voice_write(fluid_voice_t* voice,
fluid_real_t* left, fluid_real_t* right,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
fluid_channel_t* channel, int key, int vel,
unsigned int id, unsigned int time, fluid_real_t gain);
int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl);
int fluid_voice_modulate_all(fluid_voice_t* voice);
/** Set the NRPN value of a generator. */
int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t value, int abs);
/** Set the gain. */
int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain);
/** Update all the synthesis parameters, which depend on generator
'gen'. This is only necessary after changing a generator of an
already operating voice. Most applications will not need this
function.*/
void fluid_voice_update_param(fluid_voice_t* voice, int gen);
int fluid_voice_noteoff(fluid_voice_t* voice);
int fluid_voice_off(fluid_voice_t* voice);
int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice);
fluid_channel_t* fluid_voice_get_channel(fluid_voice_t* voice);
int calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
int gen_key2base, int is_decay);
int fluid_voice_kill_excl(fluid_voice_t* voice);
fluid_real_t fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice);
fluid_real_t fluid_voice_determine_amplitude_that_reaches_noise_floor_for_sample(fluid_voice_t* voice);
void fluid_voice_check_sample_sanity(fluid_voice_t* voice);
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
#define fluid_voice_get_chan(_voice) (_voice)->chan
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || ((voice)->status == FLUID_VOICE_SUSTAINED))
/* A voice is 'ON', if it has not yet received a noteoff
* event. Sending a noteoff event will advance the envelopes to
* section 5 (release). */
#define _ON(voice) ((voice)->status == FLUID_VOICE_ON && (voice)->volenv_section < FLUID_VOICE_ENVRELEASE)
#define _SUSTAINED(voice) ((voice)->status == FLUID_VOICE_SUSTAINED)
#define _AVAILABLE(voice) (((voice)->status == FLUID_VOICE_CLEAN) || ((voice)->status == FLUID_VOICE_OFF))
#define _RELEASED(voice) ((voice)->chan == NO_CHANNEL)
#define _SAMPLEMODE(voice) ((int)(voice)->gen[GEN_SAMPLEMODE].val)
fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
#define _GEN(_voice, _n) \
((fluid_real_t)(_voice)->gen[_n].val \
+ (fluid_real_t)(_voice)->gen[_n].mod \
+ (fluid_real_t)(_voice)->gen[_n].nrpn)
#define FLUID_SAMPLESANITY_CHECK (1 << 0)
#define FLUID_SAMPLESANITY_STARTUP (1 << 1)
void fluid_voice_config(void);
#endif /* _FLUID_VOICE_H */
+705
View File
@@ -0,0 +1,705 @@
/* 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 "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "fluidsynth_priv.h"
#if !defined(WIN32) && !defined(MACINTOSH)
#define _GNU_SOURCE
#include <getopt.h>
#endif
#if defined(WIN32)
#include <windows.h>
#endif
#include "fluidsynth.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(WIN32) && !defined(MINGW32)
#include "config_win32.h"
#endif
#ifdef HAVE_SIGNAL_H
#include "signal.h"
#endif
#include "fluid_lash.h"
#ifndef WITH_MIDI
#define WITH_MIDI 1
#endif
/* default audio fragment count (if none specified) */
#ifdef WIN32
#define DEFAULT_FRAG_COUNT 32
#else
#define DEFAULT_FRAG_COUNT 16
#endif
void print_usage(void);
void print_help(void);
void print_welcome(void);
static fluid_cmd_handler_t* newclient(void* data, char* addr);
/*
* the globals
*/
fluid_cmd_handler_t* cmd_handler = NULL;
int option_help = 0; /* set to 1 if "-o help" is specified */
/*
* support for the getopt function
*/
#if !defined(WIN32) && !defined(MACINTOSH)
#define GETOPT_SUPPORT 1
int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#endif
/* process_o_cmd_line_option
*
* Purpose:
* Process a command line option -o setting=value,
* for example: -o synth.polyhony=16
*/
void process_o_cmd_line_option(fluid_settings_t* settings, char* optarg){
char* val;
for (val = optarg; *val != '\0'; val++) {
if (*val == '=') {
*val++ = 0;
break;
}
}
/* did user request list of settings */
if (strcmp (optarg, "help") == 0)
{
option_help = 1;
return;
}
/* At this point:
* optarg => "synth.polyphony"
* val => "16"
*/
switch(fluid_settings_get_type(settings, optarg)){
case FLUID_NUM_TYPE:
if (fluid_settings_setnum(settings, optarg, atof(val))){
break;
};
case FLUID_INT_TYPE:
if (fluid_settings_setint(settings, optarg, atoi(val))){
break;
};
case FLUID_STR_TYPE:
if (fluid_settings_setstr(settings, optarg, val)){
break;
};
default:
fprintf (stderr, "Settings argument on command line: Failed to set \"%s\" to \"%s\".\n"
"Most likely the parameter \"%s\" does not exist.\n", optarg, val, optarg);
}
}
static void
print_pretty_int (int i)
{
if (i == INT_MAX) printf ("MAXINT");
else if (i == INT_MIN) printf ("MININT");
else printf ("%d", i);
}
/* fluid_settings_foreach function for displaying option help "-o help" */
static void
settings_foreach_func (void *data, char *name, int type)
{
fluid_settings_t *settings = (fluid_settings_t *)data;
double dmin, dmax, ddef;
int imin, imax, idef;
char *defstr;
switch (type)
{
case FLUID_NUM_TYPE:
fluid_settings_getnum_range (settings, name, &dmin, &dmax);
ddef = fluid_settings_getnum_default (settings, name);
printf ("%-24s FLOAT [min=%0.3f, max=%0.3f, def=%0.3f]\n",
name, dmin, dmax, ddef);
break;
case FLUID_INT_TYPE:
fluid_settings_getint_range (settings, name, &imin, &imax);
idef = fluid_settings_getint_default (settings, name);
printf ("%-24s INT [min=", name);
print_pretty_int (imin);
printf (", max=");
print_pretty_int (imax);
printf (", def=");
print_pretty_int (idef);
printf ("]\n");
break;
case FLUID_STR_TYPE:
defstr = fluid_settings_getstr_default (settings, name);
printf ("%-24s STR", name);
if (defstr) printf (" [def='%s']\n", defstr);
else printf ("\n");
break;
case FLUID_SET_TYPE:
printf ("%-24s SET\n", name);
break;
}
}
#ifdef HAVE_SIGNAL_H
/*
* handle_signal
*/
void handle_signal(int sig_num)
{
}
#endif
/*
* main
*/
int main(int argc, char** argv)
{
fluid_settings_t* settings;
int arg1 = 1;
char buf[512];
int c, i, fragcount = DEFAULT_FRAG_COUNT;
int interactive = 1;
int midi_in = 1;
fluid_player_t* player = NULL;
fluid_midi_router_t* router = NULL;
fluid_midi_driver_t* mdriver = NULL;
fluid_audio_driver_t* adriver = NULL;
fluid_synth_t* synth = NULL;
fluid_server_t* server = NULL;
char* midi_id = NULL;
char* midi_driver = NULL;
char* midi_device = NULL;
char* config_file = NULL;
int audio_groups = 0;
int audio_channels = 0;
int with_server = 0;
int dump = 0;
int connect_lash = 1;
char *optchars = "a:C:c:df:G:g:hijK:L:lm:no:R:r:sVvz:";
#ifdef LASH_ENABLED
int enabled_lash = 0; /* set to TRUE if lash gets enabled */
fluid_lash_args_t *lash_args;
lash_args = fluid_lash_extract_args (&argc, &argv);
#endif
settings = new_fluid_settings();
#ifdef GETOPT_SUPPORT /* pre section of GETOPT supported argument handling */
opterr = 0;
while (1) {
int option_index = 0;
static struct option long_options[] = {
{"audio-bufcount", 1, 0, 'c'},
{"audio-bufsize", 1, 0, 'z'},
{"audio-channels", 1, 0, 'L'},
{"audio-driver", 1, 0, 'a'},
{"audio-groups", 1, 0, 'G'},
{"chorus", 1, 0, 'C'},
{"connect-jack-outputs", 0, 0, 'j'},
{"disable-lash", 0, 0, 'l'},
{"dump", 0, 0, 'd'},
{"gain", 1, 0, 'g'},
{"help", 0, 0, 'h'},
{"load-config", 1, 0, 'f'},
{"midi-channels", 1, 0, 'K'},
{"midi-driver", 1, 0, 'm'},
{"no-midi-in", 0, 0, 'n'},
{"no-shell", 0, 0, 'i'},
{"option", 1, 0, 'o'},
{"reverb", 1, 0, 'R'},
{"sample-rate", 1, 0, 'r'},
{"server", 0, 0, 's'},
{"verbose", 0, 0, 'v'},
{"version", 0, 0, 'V'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, optchars, long_options, &option_index);
if (c == -1) {
break;
}
#else /* "pre" section to non getopt argument handling */
for (i = 1; i < argc; i++) {
char *optarg;
/* Skip non switch arguments (assume they are file names) */
if ((argv[i][0] != '-') || (argv[i][1] == '\0')) continue;
c = argv[i][1];
optarg = strchr (optchars, c); /* find the option character in optchars */
if (optarg && optarg[1] == ':') /* colon follows if switch argument expected */
{
if (++i >= argc)
{
printf ("Option -%c requires an argument\n", c);
print_usage();
exit(0);
}
else
{
optarg = argv[i];
if (optarg[0] == '-')
{
printf ("Expected argument to option -%c found switch instead\n", c);
print_usage();
exit(0);
}
}
}
else optarg = "";
#endif
switch (c) {
#ifdef GETOPT_SUPPORT
case 0: /* shouldn't normally happen, a long option's flag is set to NULL */
printf ("option %s", long_options[option_index].name);
if (optarg) {
printf (" with arg %s", optarg);
}
printf ("\n");
break;
#endif
case 'a':
fluid_settings_setstr(settings, "audio.driver", optarg);
break;
case 'C':
if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) {
fluid_settings_setstr(settings, "synth.chorus.active", "no");
} else {
fluid_settings_setstr(settings, "synth.chorus.active", "yes");
}
break;
case 'c':
fluid_settings_setint(settings, "audio.periods", atoi(optarg));
break;
case 'd':
fluid_settings_setstr(settings, "synth.dump", "yes");
dump = 1;
break;
case 'f':
config_file = optarg;
break;
case 'G':
audio_groups = atoi(optarg);
break;
case 'g':
fluid_settings_setnum(settings, "synth.gain", atof(optarg));
break;
case 'h':
print_help();
break;
case 'i':
interactive = 0;
break;
case 'j':
fluid_settings_setint(settings, "audio.jack.autoconnect", 1);
break;
case 'K':
fluid_settings_setint(settings, "synth.midi-channels", atoi(optarg));
break;
case 'L':
audio_channels = atoi(optarg);
fluid_settings_setint(settings, "synth.audio-channels", audio_channels);
break;
case 'l': /* disable LASH */
connect_lash = 0;
break;
case 'm':
fluid_settings_setstr(settings, "midi.driver", optarg);
break;
case 'n':
midi_in = 0;
break;
case 'o':
process_o_cmd_line_option(settings, optarg);
break;
case 'R':
if ((optarg != NULL) && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "no") == 0))) {
fluid_settings_setstr(settings, "synth.reverb.active", "no");
} else {
fluid_settings_setstr(settings, "synth.reverb.active", "yes");
}
break;
case 'r':
fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg));
break;
case 's':
with_server = 1;
break;
case 'V':
printf("FluidSynth %s\n", VERSION);
exit (0);
break;
case 'v':
fluid_settings_setstr(settings, "synth.verbose", "yes");
break;
case 'z':
fluid_settings_setint(settings, "audio.period-size", atoi(optarg));
break;
#ifdef GETOPT_SUPPORT
case '?':
printf ("Unknown option %c\n", optopt);
print_usage();
exit(0);
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
break;
#else /* Non getopt default case */
default:
printf ("Unknown switch '%c'\n", c);
print_usage();
exit(0);
break;
#endif
} /* end of switch statement */
} /* end of loop */
#ifdef GETOPT_SUPPORT
arg1 = optind;
#else
arg1 = i;
#endif
/* option help requested? "-o help" */
if (option_help)
{
print_welcome ();
printf ("FluidSynth settings:\n");
fluid_settings_foreach (settings, settings, settings_foreach_func);
exit (0);
}
#ifdef WIN32
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
#endif
#ifdef LASH_ENABLED
/* connect to the lash server */
if (connect_lash)
{
enabled_lash = fluid_lash_connect (lash_args);
fluid_settings_setint (settings, "lash.enable", enabled_lash ? 1 : 0);
}
#endif
/* The 'groups' setting is only relevant for LADSPA operation
* If not given, set number groups to number of audio channels, because
* they are the same (there is nothing between synth output and 'sound card')
*/
if ((audio_groups == 0) && (audio_channels != 0)) {
audio_groups = audio_channels;
}
fluid_settings_setint(settings, "synth.audio-groups", audio_groups);
/* create the synthesizer */
synth = new_fluid_synth(settings);
if (synth == NULL) {
fprintf(stderr, "Failed to create the synthesizer\n");
exit(-1);
}
cmd_handler = new_fluid_cmd_handler(synth);
if (cmd_handler == NULL) {
fprintf(stderr, "Failed to create the command handler\n");
goto cleanup;
}
/* try to load the user or system configuration */
if (config_file != NULL) {
fluid_source(cmd_handler, config_file);
} else if (fluid_get_userconf(buf, 512) != NULL) {
fluid_source(cmd_handler, buf);
} else if (fluid_get_sysconf(buf, 512) != NULL) {
fluid_source(cmd_handler, buf);
}
/* load the soundfonts */
for (i = arg1; i < argc; i++) {
if ((argv[i][0] != '-') && 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]);
}
}
}
#ifdef HAVE_SIGNAL_H
/* signal(SIGINT, handle_signal); */
#endif
/* start the synthesis thread */
adriver = new_fluid_audio_driver(settings, synth);
if (adriver == NULL) {
fprintf(stderr, "Failed to create the audio driver\n");
goto cleanup;
}
/* start the midi router and link it to the synth */
#if WITH_MIDI
if (midi_in) {
/* In dump mode, text output is generated for events going into and out of the router.
* The example dump functions are put into the chain before and after the router..
*/
router = new_fluid_midi_router(
settings,
dump ? fluid_midi_dump_postrouter : fluid_synth_handle_midi_event,
(void*)synth);
if (router == NULL) {
fprintf(stderr, "Failed to create the MIDI input router; no MIDI input\n"
"will be available. You can access the synthesizer \n"
"through the console.\n");
} else {
fluid_synth_set_midi_router(synth, router); /* Fixme, needed for command handler */
mdriver = new_fluid_midi_driver(
settings,
dump ? fluid_midi_dump_prerouter : fluid_midi_router_handle_midi_event,
(void*) router);
if (mdriver == NULL) {
fprintf(stderr, "Failed to create the MIDI thread; no MIDI input\n"
"will be available. You can access the synthesizer \n"
"through the console.\n");
}
}
}
#endif
/* play the midi files, if any */
for (i = arg1; i < argc; i++) {
if ((argv[i][0] != '-') && fluid_is_midifile(argv[i])) {
if (player == NULL) {
player = new_fluid_player(synth);
if (player == NULL) {
fprintf(stderr, "Failed to create the midifile player.\n"
"Continuing without a player.\n");
break;
}
}
fluid_player_add(player, argv[i]);
}
}
if (player != NULL) {
fluid_player_play(player);
}
/* run the server, if requested */
#if !defined(MACINTOSH) && !defined(WIN32) && !defined(__BEOS__)
if (with_server) {
server = new_fluid_server(settings, newclient, synth);
if (server == NULL) {
fprintf(stderr, "Failed to create the server.\n"
"Continuing without it.\n");
}
}
#endif
#ifdef LASH_ENABLED
if (enabled_lash)
fluid_lash_create_thread (synth);
#endif
/* run the shell */
if (interactive) {
print_welcome();
printf ("Type 'help' for information on commands and 'help help' for help topics.\n\n");
/* In dump mode we set the prompt to "". The UI cannot easily
* handle lines, which don't end with CR. Changing the prompt
* cannot be done through a command, because the current shell
* does not handle empty arguments. The ordinary case is dump ==
* 0.
*/
fluid_settings_setstr(settings, "shell.prompt", dump ? "" : "> ");
fluid_usershell(settings, cmd_handler);
}
cleanup:
#if !defined(MACINTOSH) && !defined(WIN32) && !defined(__BEOS__)
if (server != NULL) {
/* if the user typed 'quit' in the shell, kill the server */
if (!interactive) {
fluid_server_join(server);
}
delete_fluid_server(server);
}
#endif
if (cmd_handler != NULL) {
delete_fluid_cmd_handler(cmd_handler);
}
if (player != NULL) {
/* if the user typed 'quit' in the shell, stop the player */
if (interactive) {
fluid_player_stop(player);
}
fluid_player_join(player);
delete_fluid_player(player);
}
if (router) {
#if WITH_MIDI
if (mdriver) {
delete_fluid_midi_driver(mdriver);
}
delete_fluid_midi_router(router);
#endif
}
if (adriver) {
delete_fluid_audio_driver(adriver);
}
if (synth) {
delete_fluid_synth(synth);
}
if (settings) {
delete_fluid_settings(settings);
}
return 0;
}
static fluid_cmd_handler_t* newclient(void* data, char* addr)
{
fluid_synth_t* synth = (fluid_synth_t*) data;
return new_fluid_cmd_handler(synth);
}
/*
* print_usage
*/
void
print_usage()
{
print_welcome ();
fprintf(stderr, "Usage: fluidsynth [options] [soundfonts]\n");
fprintf(stderr, "Try -h for help.\n");
exit(0);
}
/*
* print_welcome
*/
void
print_welcome()
{
printf("FluidSynth version %s\n"
"Copyright (C) 2000-2006 Peter Hanappe and others.\n"
"Distributed under the LGPL license.\n"
"SoundFont(R) is a registered trademark of E-mu Systems, Inc.\n\n",
FLUIDSYNTH_VERSION);
}
/*
* print_help
*/
void
print_help()
{
print_welcome ();
printf("Usage: \n");
printf(" fluidsynth [options] [soundfonts] [midifiles]\n");
printf("Possible options:\n");
printf(" -a, --audio-driver=[label]\n"
" The audio driver [alsa,jack,oss,dsound,...]\n");
printf(" -C, --chorus\n"
" Turn the chorus on or off [0|1|yes|no, default = on]\n");
printf(" -c, --audio-bufcount=[count]\n"
" Number of audio buffers\n");
printf(" -d, --dump\n"
" Dump incoming and outgoing MIDI events to stdout\n");
printf(" -f, --load-config\n"
" Load command configuration file (shell commands)\n");
printf(" -G, --audio-groups\n"
" Defines the number of LADSPA audio nodes\n");
printf(" -g, --gain\n"
" Set the master gain [0 < gain < 10, default = 0.2]\n");
printf(" -h, --help\n"
" Print out this help summary\n");
printf(" -i, --no-shell\n"
" Don't read commands from the shell [default = yes]\n");
printf(" -j, --connect-jack-outputs\n"
" Attempt to connect the jack outputs to the physical ports\n");
printf(" -K, --midi-channels=[num]\n"
" The number of midi channels [default = 16]\n");
printf(" -L, --audio-channels=[num]\n"
" The number of stereo audio channels [default = 1]\n");
#ifdef LASH_ENABLED
printf(" -l, --disable-lash\n"
" Don't connect to LASH server\n");
#endif
printf(" -m, --midi-driver=[label]\n"
" The name of the midi driver to use [oss,alsa,alsa_seq,...]\n");
printf(" -n, --no-midi-in\n"
" Don't create a midi driver to read MIDI input events [default = yes]\n");
printf(" -o\n"
" Define a setting, -o name=value (\"-o help\" to dump current values)\n");
printf(" -R, --reverb\n"
" Turn the reverb on or off [0|1|yes|no, default = on]\n");
printf(" -r, --sample-rate\n"
" Set the sample rate\n");
printf(" -s, --server\n"
" Start FluidSynth as a server process\n");
printf(" -V, --version\n"
" Show version of program\n");
printf(" -v, --verbose\n"
" Print out verbose messages about midi events\n");
printf(" -z, --audio-bufsize=[size]\n"
" Size of each audio buffer\n");
exit(0);
}
+326
View File
@@ -0,0 +1,326 @@
/* 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 _FLUIDSYNTH_PRIV_H
#define _FLUIDSYNTH_PRIV_H
#if HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(__POWERPC__) && !(defined(__APPLE__) && defined(__MACH__))
#include "config_maxmsp43.h"
#endif
#if defined(WIN32) && !defined(MINGW32)
#include "config_win32.h"
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_MATH_H
#include <math.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#if HAVE_LIMITS_H
#include <limits.h>
#endif
#if HAVE_PTHREAD_H
#include <pthread.h>
#endif
#if HAVE_IO_H
#include <io.h>
#endif
#if HAVE_WINDOWS_H
#include <windows.h>
#endif
/* MinGW32 special defines */
#ifdef MINGW32
#include <stdint.h>
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define DSOUND_SUPPORT 1
#define WINMIDI_SUPPORT 1
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#define WITHOUT_SERVER 1
#endif
/* Darwin special defines (taken from config_macosx.h) */
#ifdef DARWIN
#define MACINTOSH
#define __Types__
#define WITHOUT_SERVER 1
#endif
#include "fluidsynth.h"
/***************************************************************
*
* BASIC TYPES
*/
#if defined(WITH_FLOAT)
typedef float fluid_real_t;
#else
typedef double fluid_real_t;
#endif
typedef enum {
FLUID_OK = 0,
FLUID_FAILED = -1
} fluid_status;
#if defined(WIN32)
typedef SOCKET fluid_socket_t;
#else
typedef int fluid_socket_t;
#define INVALID_SOCKET -1
#endif
/** Integer types */
#if defined(MINGW32)
/* Windows using MinGW32 */
typedef int8_t sint8;
typedef uint8_t uint8;
typedef int16_t sint16;
typedef uint16_t uint16;
typedef int32_t sint32;
typedef uint32_t uint32;
typedef int64_t sint64;
typedef uint64_t uint64;
#elif defined(_WIN32)
/* Windows */
typedef signed __int8 sint8;
typedef unsigned __int8 uint8;
typedef signed __int16 sint16;
typedef unsigned __int16 uint16;
typedef signed __int32 sint32;
typedef unsigned __int32 uint32;
typedef signed __int64 sint64;
typedef unsigned __int64 uint64;
#elif defined(MACOS9)
/* Macintosh */
typedef signed char sint8;
typedef unsigned char uint8;
typedef signed short sint16;
typedef unsigned short uint16;
typedef signed int sint32;
typedef unsigned int uint32;
/* FIXME: needs to be verified */
typedef long long sint64;
typedef unsigned long long uint64;
#elif defined(__BEOS__)
typedef signed char sint8;
typedef signed short sint16;
typedef signed int sint32;
typedef long long sint64;
#else
/* Linux & Darwin */
typedef int8_t sint8;
typedef u_int8_t uint8;
typedef int16_t sint16;
typedef u_int16_t uint16;
typedef int32_t sint32;
typedef u_int32_t uint32;
typedef int64_t sint64;
typedef u_int64_t uint64;
#endif
/***************************************************************
*
* FORWARD DECLARATIONS
*/
typedef struct _fluid_env_data_t fluid_env_data_t;
typedef struct _fluid_adriver_definition_t fluid_adriver_definition_t;
typedef struct _fluid_channel_t fluid_channel_t;
typedef struct _fluid_tuning_t fluid_tuning_t;
typedef struct _fluid_hashtable_t fluid_hashtable_t;
typedef struct _fluid_client_t fluid_client_t;
typedef struct _fluid_server_socket_t fluid_server_socket_t;
/***************************************************************
*
* CONSTANTS
*/
#define FLUID_BUFSIZE 64
#ifndef PI
#define PI 3.141592654
#endif
/***************************************************************
*
* SYSTEM INTERFACE
*/
typedef FILE* fluid_file;
#define FLUID_MALLOC(_n) malloc(_n)
#define FLUID_REALLOC(_p,_n) realloc(_p,_n)
#define FLUID_NEW(_t) (_t*)malloc(sizeof(_t))
#define FLUID_ARRAY(_t,_n) (_t*)malloc((_n)*sizeof(_t))
#define FLUID_FREE(_p) free(_p)
#define FLUID_FOPEN(_f,_m) fopen(_f,_m)
#define FLUID_FCLOSE(_f) fclose(_f)
#define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
#define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
#define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
#define FLUID_MEMSET(_s,_c,_n) memset(_s,_c,_n)
#define FLUID_STRLEN(_s) strlen(_s)
#define FLUID_STRCMP(_s,_t) strcmp(_s,_t)
#define FLUID_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n)
#define FLUID_STRCPY(_dst,_src) strcpy(_dst,_src)
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
#ifdef strdup
#define FLUID_STRDUP(s) strdup(s)
#else
#define FLUID_STRDUP(s) FLUID_STRCPY(FLUID_MALLOC(FLUID_STRLEN(s) + 1), s)
#endif
#define FLUID_SPRINTF sprintf
#define FLUID_FPRINTF fprintf
#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()
#else
#define FLUID_PRINTF printf
#define FLUID_FLUSH() fflush(stdout)
#endif
#define FLUID_LOG fluid_log
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
#define FLUID_ASSERT(a,b)
#define FLUID_ASSERT_P(a,b)
char* fluid_error(void);
/* Internationalization */
#define _(s) s
#endif /* _FLUIDSYNTH_PRIV_H */