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:
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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,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 ;
|
||||
|
||||
@@ -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
|
||||
@@ -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!
|
||||
@@ -0,0 +1,3 @@
|
||||
SubDir HAIKU_TOP src libs fluidsynth ;
|
||||
|
||||
SubInclude HAIKU_TOP src libs fluidsynth src ;
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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) */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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 = ¤t_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);
|
||||
};
|
||||
@@ -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
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user