Import libfluidsynth into the Ardour codebase

This commit is contained in:
Robin Gareus 2016-08-23 18:50:54 +02:00
parent ac8617017a
commit ac05f05023
69 changed files with 29290 additions and 0 deletions

8
libs/fluidsynth/README Normal file
View File

@ -0,0 +1,8 @@
This is a stripped down version of fluidsynth (library only)
from git://git.code.sf.net/p/fluidsynth/code-git
revisition f52597be038a5a045fc74b6f96d5f9b0bbbbc044 from May/2015
imported into Ardour Aug/2016
fluidsynth is licensed in terms of the LGPL-2+, see individual source
files for (C) holders.

225
libs/fluidsynth/config.h Normal file
View File

@ -0,0 +1,225 @@
#ifndef CONFIG_H
#define CONFIG_H
#define FLUIDSYNTH_VERSION_MAJOR 1
#define FLUIDSYNTH_VERSION_MINOR 0
#define FLUIDSYNTH_VERSION_MICRO 6
#define FLUIDSYNTH_VERSION "1.0.6"
/* Define to enable ALSA driver */
/* #undef ALSA_SUPPORT */
/* Define to activate sound output to files */
/* #undef AUFILE_SUPPORT */
/* whether or not we are supporting CoreAudio */
/* #undef COREAUDIO_SUPPORT */
/* whether or not we are supporting CoreMIDI */
/* #undef COREMIDI_SUPPORT */
/* whether or not we are supporting DART */
/* #undef DART_SUPPORT */
/* Define if building for Mac OS X Darwin */
/* #undef DARWIN */
/* Define if D-Bus support is enabled */
/* #undef DBUS_SUPPORT 1 */
/* Define to enable FPE checks */
/* #undef FPE_CHECK */
/* Define to 1 if you have the <arpa/inet.h> header file. */
#ifndef _WIN32
# define HAVE_ARPA_INET_H 1
#endif
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
/* 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). */
#define HAVE_LIBDL 1
/* Define to 1 if you have the `MidiShare' library (-lMidiShare). */
/* #undef HAVE_LIBMIDISHARE */
/* Define to 1 if you have the `pthread' library (-lpthread). */
#define HAVE_LIBPTHREAD TRUE
/* 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. */
/* #undef HAVE_NETINET_IN_H */
/* Define to 1 if you have the <netinet/tcp.h> header file. */
/* #undef HAVE_NETINET_TCP_H */
/* Define to 1 if you have the <pthread.h> header file. */
#define HAVE_PTHREAD_H 1
/* Define to 1 if you have the <signal.h> header file. */
/* #undef HAVE_SIGNAL_H */
/* Define to 1 if you have the <stdarg.h> header file. */
/* #undef HAVE_STDARG_H */
/* 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. */
#ifndef _WIN32
# define HAVE_SYS_MMAN_H 1
#endif
/* Define to 1 if you have the <sys/socket.h> header file. */
#ifndef _WIN32
# define HAVE_SYS_SOCKET_H 1
#endif
/* 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. */
#ifdef _WIN32
# define HAVE_WINDOWS_H 1
#endif
/* Define to 1 if you have the <getopt.h> header file. */
/* #undef HAVE_GETOPT_H */
/* Define to enable JACK driver */
/* #undef JACK_SUPPORT */
/* Include the LADSPA Fx unit */
/* #undef LADSPA */
/* libsndfile has ogg vorbis support */
/* #undef LIBSNDFILE_HASVORBIS */
/* Define to enable libsndfile support */
/* #undef LIBSNDFILE_SUPPORT */
/* Define to enable MidiShare driver */
/* #undef MIDISHARE_SUPPORT */
/* Define if using the MinGW32 environment */
/* #undef MINGW32 */
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
/* Define to enable OSS driver */
/* #undef OSS_SUPPORT TRUE */
/* Name of package */
#define PACKAGE "fluidsynth"
/* Define to the address where bug reports for this package should be sent. */
/* #undef PACKAGE_BUGREPORT */
/* Define to the full name of this package. */
/* #undef PACKAGE_NAME */
/* Define to the full name and version of this package. */
/* #undef PACKAGE_STRING */
/* Define to the one symbol short name of this package. */
/* #undef PACKAGE_TARNAME */
/* Define to the version of this package. */
/* #undef PACKAGE_VERSION */
/* Define to enable PortAudio driver */
/* #undef PORTAUDIO_SUPPORT */
/* Define to enable PulseAudio driver */
/* #undef PULSE_SUPPORT */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to enable SIGFPE assertions */
/* #undef TRAP_ON_FPE */
/* Version number of package */
#define VERSION "1.1.6"
/* Define to do all DSP in single floating point precision */
/* #undef WITH_FLOAT */
/* Define to profile the DSP code */
/* #undef WITH_PROFILING */
/* Define to use the readline library for line editing */
/* #undef WITH_READLINE */
/* Define if the compiler supports VLA */
#define SUPPORTS_VLA 1
/* 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
#endif /* CONFIG_H */

View File

@ -0,0 +1,135 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_EVENT_H
#define _FLUIDSYNTH_EVENT_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file event.h
* @brief Sequencer event functions and defines.
*
* Functions and constants for creating/processing sequencer events.
*/
/**
* Sequencer event type enumeration.
*/
enum fluid_seq_event_type {
FLUID_SEQ_NOTE = 0, /**< Note event with duration */
FLUID_SEQ_NOTEON, /**< Note on event */
FLUID_SEQ_NOTEOFF, /**< Note off event */
FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
FLUID_SEQ_BANKSELECT, /**< Bank select message */
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was mispelled previously */
FLUID_SEQ_MODULATION, /**< Modulation controller event */
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
FLUID_SEQ_PAN, /**< Stereo pan set event */
FLUID_SEQ_VOLUME, /**< Volume set event */
FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
};
#define FLUID_SEQ_PITCHWHHELSENS FLUID_SEQ_PITCHWHEELSENS /**< Old deprecated misspelling of #FLUID_SEQ_PITCHWHEELSENS */
/* 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);
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val);
FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t* evt);
/* Only for removing events */
FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel);
/* Only when unregistering clients */
FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t* evt);
/* 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 */

View File

@ -0,0 +1,38 @@
#ifndef _FLUIDSYNTH_H
#define _FLUIDSYNTH_H
#include <stdio.h>
#if defined(COMPILER_MSVC)
# define FLUIDSYNTH_API
#else
# define FLUIDSYNTH_API __attribute__ ((visibility ("hidden")))
#endif
#ifdef __cplusplus
extern "C" {
#endif
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
FLUIDSYNTH_API char* fluid_version_str(void);
#include "types.h"
#include "settings.h"
#include "synth.h"
#include "sfont.h"
#include "event.h"
#include "midi.h"
#include "log.h"
#include "misc.h"
#include "mod.h"
#include "gen.h"
#include "voice.h"
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_H */

View File

@ -0,0 +1,135 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_GEN_H
#define _FLUIDSYNTH_GEN_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file gen.h
* @brief Functions and defines for SoundFont generator effects.
*/
/**
* Generator (effect) numbers (Soundfont 2.01 specifications section 8.1.3)
*/
enum fluid_gen_type {
GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
GEN_FILTERFC, /**< Filter cutoff */
GEN_FILTERQ, /**< Filter Q */
GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
GEN_UNUSED1, /**< Unused */
GEN_CHORUSSEND, /**< Chorus send amount */
GEN_REVERBSEND, /**< Reverb send amount */
GEN_PAN, /**< Stereo panning */
GEN_UNUSED2, /**< Unused */
GEN_UNUSED3, /**< Unused */
GEN_UNUSED4, /**< Unused */
GEN_MODLFODELAY, /**< Modulation LFO delay */
GEN_MODLFOFREQ, /**< Modulation LFO frequency */
GEN_VIBLFODELAY, /**< Vibrato LFO delay */
GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
GEN_MODENVDELAY, /**< Modulation envelope delay */
GEN_MODENVATTACK, /**< Modulation envelope attack */
GEN_MODENVHOLD, /**< Modulation envelope hold */
GEN_MODENVDECAY, /**< Modulation envelope decay */
GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
GEN_MODENVRELEASE, /**< Modulation envelope release */
GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
GEN_VOLENVDELAY, /**< Volume envelope delay */
GEN_VOLENVATTACK, /**< Volume envelope attack */
GEN_VOLENVHOLD, /**< Volume envelope hold */
GEN_VOLENVDECAY, /**< Volume envelope decay */
GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
GEN_VOLENVRELEASE, /**< Volume envelope release */
GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
GEN_RESERVED1, /**< Reserved */
GEN_KEYRANGE, /**< MIDI note range */
GEN_VELRANGE, /**< MIDI velocity range */
GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
GEN_KEYNUM, /**< Fixed MIDI note number */
GEN_VELOCITY, /**< Fixed MIDI velocity value */
GEN_ATTENUATION, /**< Initial volume attenuation */
GEN_RESERVED2, /**< Reserved */
GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
GEN_COARSETUNE, /**< Coarse tuning */
GEN_FINETUNE, /**< Fine tuning */
GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
GEN_SAMPLEMODE, /**< Sample mode flags */
GEN_RESERVED3, /**< Reserved */
GEN_SCALETUNE, /**< Scale tuning */
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
/* the initial pitch is not a "standard" generator. It is not
* mentioned in the list of generator in the SF2 specifications. It
* is used, however, as the destination for the default pitch wheel
* modulator. */
GEN_PITCH, /**< Pitch (NOTE: Not a real SoundFont generator) */
GEN_LAST /**< Value defines the count of generators (#fluid_gen_type) */
};
/**
* SoundFont generator structure.
*/
typedef struct _fluid_gen_t
{
unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
double val; /**< The nominal value */
double mod; /**< Change by modulators */
double nrpn; /**< Change by NRPN messages */
} fluid_gen_t;
/**
* Enum value for 'flags' field of #fluid_gen_t (not really flags).
*/
enum fluid_gen_flags
{
GEN_UNUSED, /**< Generator value is not set */
GEN_SET, /**< Generator value is set */
GEN_ABS_NRPN /**< Generator is an absolute value */
};
FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_GEN_H */

View File

@ -0,0 +1,84 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_LOG_H
#define _FLUIDSYNTH_LOG_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file log.h
* @brief Logging interface
*
* The default logging function of the fluidsynth prints its messages
* to the stderr. The synthesizer uses five level of messages: #FLUID_PANIC,
* #FLUID_ERR, #FLUID_WARN, #FLUID_INFO, and #FLUID_DBG.
*
* A client application can install a new log function to handle the
* messages differently. In the following example, the application
* sets a callback function to display #FLUID_PANIC messages in a dialog,
* and ignores all other messages by setting the log function to
* NULL:
*
* @code
* fluid_set_log_function(FLUID_PANIC, show_dialog, (void*) root_window);
* fluid_set_log_function(FLUID_ERR, NULL, NULL);
* fluid_set_log_function(FLUID_WARN, NULL, NULL);
* fluid_set_log_function(FLUID_DBG, NULL, NULL);
* @endcode
*/
/**
* FluidSynth log levels.
*/
enum fluid_log_level {
FLUID_PANIC, /**< The synth can't function correctly any more */
FLUID_ERR, /**< Serious error occurred */
FLUID_WARN, /**< Warning */
FLUID_INFO, /**< Verbose informational messages */
FLUID_DBG, /**< Debugging messages */
LAST_LOG_LEVEL
};
/**
* Log function handler callback type used by fluid_set_log_function().
* @param level Log level (#fluid_log_level)
* @param message Log message text
* @param data User data pointer supplied to fluid_set_log_function().
*/
typedef void (*fluid_log_function_t)(int level, char* message, void* data);
FLUIDSYNTH_API
fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void* data);
FLUIDSYNTH_API void fluid_default_log_function(int level, char* message, void* data);
FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_LOG_H */

View File

@ -0,0 +1,141 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_MIDI_H
#define _FLUIDSYNTH_MIDI_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file midi.h
* @brief Functions for MIDI events, drivers and MIDI file playback.
*/
FLUIDSYNTH_API fluid_midi_event_t* new_fluid_midi_event(void);
FLUIDSYNTH_API int delete_fluid_midi_event(fluid_midi_event_t* event);
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);
FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t* evt, void *data,
int size, int dynamic);
/**
* MIDI router rule type.
* @since 1.1.0
*/
typedef enum
{
FLUID_MIDI_ROUTER_RULE_NOTE, /**< MIDI note rule */
FLUID_MIDI_ROUTER_RULE_CC, /**< MIDI controller rule */
FLUID_MIDI_ROUTER_RULE_PROG_CHANGE, /**< MIDI program change rule */
FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */
FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */
FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */
FLUID_MIDI_ROUTER_RULE_COUNT /**< Total count of rule types */
} fluid_midi_router_rule_type;
/**
* Generic callback function for MIDI events.
* @param data User defined data pointer
* @param event The MIDI event
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* 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);
FLUIDSYNTH_API fluid_midi_router_t* new_fluid_midi_router(fluid_settings_t* settings,
handle_midi_event_func_t handler,
void* event_handler_data);
FLUIDSYNTH_API int delete_fluid_midi_router(fluid_midi_router_t* handler);
FLUIDSYNTH_API int fluid_midi_router_set_default_rules (fluid_midi_router_t *router);
FLUIDSYNTH_API int fluid_midi_router_clear_rules (fluid_midi_router_t *router);
FLUIDSYNTH_API int fluid_midi_router_add_rule (fluid_midi_router_t *router,
fluid_midi_router_rule_t *rule, int type);
FLUIDSYNTH_API fluid_midi_router_rule_t *new_fluid_midi_router_rule (void);
FLUIDSYNTH_API void delete_fluid_midi_router_rule (fluid_midi_router_rule_t *rule);
FLUIDSYNTH_API void fluid_midi_router_rule_set_chan (fluid_midi_router_rule_t *rule,
int min, int max, float mul, int add);
FLUIDSYNTH_API void fluid_midi_router_rule_set_param1 (fluid_midi_router_rule_t *rule,
int min, int max, float mul, int add);
FLUIDSYNTH_API void fluid_midi_router_rule_set_param2 (fluid_midi_router_rule_t *rule,
int min, int max, float mul, int add);
FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event);
FLUIDSYNTH_API int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event);
FLUIDSYNTH_API int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event);
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 player status enum.
* @since 1.1.0
*/
enum fluid_player_status
{
FLUID_PLAYER_READY, /**< Player is ready */
FLUID_PLAYER_PLAYING, /**< Player is currently playing */
FLUID_PLAYER_DONE /**< Player is finished playing */
};
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, const char *midifile);
FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t* player, const void *buffer, size_t len);
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);
FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t* player);
FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t* player, handle_midi_event_func_t handler, void* handler_data);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MIDI_H */

View File

@ -0,0 +1,77 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_MISC_H
#define _FLUIDSYNTH_MISC_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file misc.h
* @brief Miscellaneous utility functions and defines
*/
/**
* Value that indicates success, used by most libfluidsynth functions.
* @since 1.1.0
*
* NOTE: This was not publicly defined prior to libfluidsynth 1.1.0. When
* writing code which should also be compatible with older versions, something
* like the following can be used:
*
* @code
* #include <fluidsynth.h>
*
* #ifndef FLUID_OK
* #define FLUID_OK (0)
* #define FLUID_FAILED (-1)
* #endif
* @endcode
*/
#define FLUID_OK (0)
/**
* Value that indicates failure, used by most libfluidsynth functions.
* @since 1.1.0
*
* NOTE: See #FLUID_OK for more details.
*/
#define FLUID_FAILED (-1)
FLUIDSYNTH_API int fluid_is_soundfont (const char *filename);
FLUIDSYNTH_API int fluid_is_midifile (const char *filename);
#ifdef WIN32
FLUIDSYNTH_API void* fluid_get_hinstance(void);
FLUIDSYNTH_API void fluid_set_hinstance(void* hinstance);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MISC_H */

View File

@ -0,0 +1,112 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_MOD_H
#define _FLUIDSYNTH_MOD_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file mod.h
* @brief SoundFont modulator functions and constants.
*/
#define FLUID_NUM_MOD 64 /**< Maximum number of modulators in a voice */
/**
* Modulator structure. See SoundFont 2.04 PDF section 8.2.
*/
struct _fluid_mod_t
{
unsigned char dest; /**< Destination generator to control */
unsigned char src1; /**< Source controller 1 */
unsigned char flags1; /**< Source controller 1 flags */
unsigned char src2; /**< Source controller 2 */
unsigned char flags2; /**< Source controller 2 flags */
double amount; /**< Multiplier 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 defining the polarity, mapping function and type of a modulator source.
* Compare with SoundFont 2.04 PDF section 8.2.
*
* Note: Bit values do not correspond to the SoundFont spec! Also note that
* #FLUID_MOD_GC and #FLUID_MOD_CC are in the flags field instead of the source field.
*/
enum fluid_mod_flags
{
FLUID_MOD_POSITIVE = 0, /**< Mapping function is positive */
FLUID_MOD_NEGATIVE = 1, /**< Mapping function is negative */
FLUID_MOD_UNIPOLAR = 0, /**< Mapping function is unipolar */
FLUID_MOD_BIPOLAR = 2, /**< Mapping function is bipolar */
FLUID_MOD_LINEAR = 0, /**< Linear mapping function */
FLUID_MOD_CONCAVE = 4, /**< Concave mapping function */
FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
FLUID_MOD_CC = 16 /**< MIDI CC controller (source will be a MIDI CC number) */
};
/**
* General controller (if #FLUID_MOD_GC in flags). This
* corresponds to SoundFont 2.04 PDF section 8.2.1
*/
enum fluid_mod_src
{
FLUID_MOD_NONE = 0, /**< No source controller */
FLUID_MOD_VELOCITY = 2, /**< MIDI note-on velocity */
FLUID_MOD_KEY = 3, /**< MIDI note-on note number */
FLUID_MOD_KEYPRESSURE = 10, /**< MIDI key pressure */
FLUID_MOD_CHANNELPRESSURE = 13, /**< MIDI channel pressure */
FLUID_MOD_PITCHWHEEL = 14, /**< Pitch wheel */
FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */
};
FLUIDSYNTH_API fluid_mod_t* fluid_mod_new(void);
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);
FLUIDSYNTH_API int fluid_mod_test_identity(fluid_mod_t * mod1, fluid_mod_t * mod2);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MOD_H */

View File

@ -0,0 +1,219 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SETTINGS_H
#define _FLUIDSYNTH_SETTINGS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file settings.h
* @brief Synthesizer settings
* @defgroup SettingsFunctions Functions for settings management
*
* To create a synthesizer object you will have to specify its
* settings. These settings are stored in a fluid_settings_t object.
* @code
* 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);
* // ...
* }
* @endcode
* @sa @ref CreatingSettings
*/
/**
* 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.
*/
#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.
* @deprecated
*
* As there is an integer setting type, this hint is not used.
*/
#define FLUID_HINT_INTEGER 0x20
#define FLUID_HINT_FILENAME 0x01 /**< String setting is a file name */
#define FLUID_HINT_OPTIONLIST 0x02 /**< Setting is a list of string options */
/**
* Settings type
*
* Each setting has a defined type: numeric (double), integer, string or a
* set of values. The type of each setting can be retrieved using the
* function fluid_settings_get_type()
*/
enum fluid_types_enum {
FLUID_NO_TYPE = -1, /**< Undefined type */
FLUID_NUM_TYPE, /**< Numeric (double) */
FLUID_INT_TYPE, /**< Integer */
FLUID_STR_TYPE, /**< String */
FLUID_SET_TYPE /**< Set of values */
};
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, const char *name);
FLUIDSYNTH_API
int fluid_settings_get_hints(fluid_settings_t* settings, const char *name);
FLUIDSYNTH_API
int fluid_settings_is_realtime(fluid_settings_t* settings, const char *name);
FLUIDSYNTH_API
int fluid_settings_setstr(fluid_settings_t* settings, const char *name, const char *str);
FLUIDSYNTH_API
int fluid_settings_copystr(fluid_settings_t* settings, const char *name, char *str, int len);
FLUIDSYNTH_API
int fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str);
FLUIDSYNTH_API
int fluid_settings_getstr(fluid_settings_t* settings, const char *name, char** str);
FLUIDSYNTH_API
char* fluid_settings_getstr_default(fluid_settings_t* settings, const char *name);
FLUIDSYNTH_API
int fluid_settings_str_equal(fluid_settings_t* settings, const char *name, const char *value);
FLUIDSYNTH_API
int fluid_settings_setnum(fluid_settings_t* settings, const char *name, double val);
FLUIDSYNTH_API
int fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val);
FLUIDSYNTH_API
double fluid_settings_getnum_default(fluid_settings_t* settings, const char *name);
FLUIDSYNTH_API
void fluid_settings_getnum_range(fluid_settings_t* settings, const char *name,
double* min, double* max);
FLUIDSYNTH_API
int fluid_settings_setint(fluid_settings_t* settings, const char *name, int val);
FLUIDSYNTH_API
int fluid_settings_getint(fluid_settings_t* settings, const char *name, int* val);
FLUIDSYNTH_API
int fluid_settings_getint_default(fluid_settings_t* settings, const char *name);
FLUIDSYNTH_API
void fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
int* min, int* max);
/**
* Callback function type used with fluid_settings_foreach_option()
* @param data User defined data pointer
* @param name Setting name
* @param option A string option for this setting (iterates through the list)
*/
typedef void (*fluid_settings_foreach_option_t)(void *data, char *name, char *option);
FLUIDSYNTH_API
void fluid_settings_foreach_option(fluid_settings_t* settings,
const char* name, void* data,
fluid_settings_foreach_option_t func);
FLUIDSYNTH_API
int fluid_settings_option_count (fluid_settings_t* settings, const char* name);
FLUIDSYNTH_API char *fluid_settings_option_concat (fluid_settings_t* settings,
const char* name,
const char* separator);
/**
* Callback function type used with fluid_settings_foreach()
* @param data User defined data pointer
* @param name Setting name
* @param type Setting type (#fluid_types_enum)
*/
typedef void (*fluid_settings_foreach_t)(void *data, char *name, 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 */

View File

@ -0,0 +1,281 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SFONT_H
#define _FLUIDSYNTH_SFONT_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file sfont.h
* @brief 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. This API allows for virtual SoundFont files to be loaded
* and synthesized, which may not actually be SoundFont files, as long as they
* can be represented by the SoundFont synthesis model.
*
* 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 a #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 increment the values of a
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
* finished initializing the voice call fluid_voice_start() to
* start playing the synthesis voice.
*/
/**
* Some notification enums for presets and samples.
*/
enum {
FLUID_PRESET_SELECTED, /**< Preset selected notify */
FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
FLUID_SAMPLE_DONE /**< Sample no longer needed notify */
};
/**
* SoundFont loader structure.
*/
struct _fluid_sfloader_t {
void* data; /**< User defined data pointer */
/**
* The free method should free the memory allocated for the loader in
* addition to any private data.
* @param loader SoundFont loader
* @return Should return 0 if no error occured, non-zero otherwise
*/
int (*free)(fluid_sfloader_t* loader);
/**
* Method to load an instrument file (does not actually need to be a real file name,
* could be another type of string identifier that the \a loader understands).
* @param loader SoundFont loader
* @param filename File name or other string identifier
* @return The loaded instrument file (SoundFont) or NULL if an error occured.
*/
fluid_sfont_t* (*load)(fluid_sfloader_t* loader, const char* filename);
};
/**
* Virtual SoundFont instance structure.
*/
struct _fluid_sfont_t {
void* data; /**< User defined data */
unsigned int id; /**< SoundFont ID */
/**
* Method to free a virtual SoundFont bank.
* @param sfont Virtual SoundFont to free.
* @return Should return 0 when it was able to free all resources or non-zero
* if some of the samples could not be freed because they are still in use,
* in which case the free will be tried again later, until success.
*/
int (*free)(fluid_sfont_t* sfont);
/**
* Method to return the name of a virtual SoundFont.
* @param sfont Virtual SoundFont
* @return The name of the virtual SoundFont.
*/
char* (*get_name)(fluid_sfont_t* sfont);
/**
* Get a virtual SoundFont preset by bank and program numbers.
* @param sfont Virtual SoundFont
* @param bank MIDI bank number (0-16384)
* @param prenum MIDI preset number (0-127)
* @return Should return an allocated virtual preset or NULL if it could not
* be found.
*/
fluid_preset_t* (*get_preset)(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
/**
* Start virtual SoundFont preset iteration method.
* @param sfont Virtual SoundFont
*
* Starts/re-starts virtual preset iteration in a SoundFont.
*/
void (*iteration_start)(fluid_sfont_t* sfont);
/**
* Virtual SoundFont preset iteration function.
* @param sfont Virtual SoundFont
* @param preset Caller supplied preset to fill in with current preset information
* @return 0 when no more presets are available, 1 otherwise
*
* Should store preset information to the caller supplied \a preset structure
* and advance the internal iteration state to the next preset for subsequent
* calls.
*/
int (*iteration_next)(fluid_sfont_t* sfont, fluid_preset_t* preset);
};
#define fluid_sfont_get_id(_sf) ((_sf)->id)
/**
* Virtual SoundFont preset.
*/
struct _fluid_preset_t {
void* data; /**< User supplied data */
fluid_sfont_t* sfont; /**< Parent virtual SoundFont */
/**
* Method to free a virtual SoundFont preset.
* @param preset Virtual SoundFont preset
* @return Should return 0
*/
int (*free)(fluid_preset_t* preset);
/**
* Method to get a virtual SoundFont preset name.
* @param preset Virtual SoundFont preset
* @return Should return the name of the preset. The returned string must be
* valid for the duration of the virtual preset (or the duration of the
* SoundFont, in the case of preset iteration).
*/
char* (*get_name)(fluid_preset_t* preset);
/**
* Method to get a virtual SoundFont preset MIDI bank number.
* @param preset Virtual SoundFont preset
* @param return The bank number of the preset
*/
int (*get_banknum)(fluid_preset_t* preset);
/**
* Method to get a virtual SoundFont preset MIDI program number.
* @param preset Virtual SoundFont preset
* @param return The program number of the preset
*/
int (*get_num)(fluid_preset_t* preset);
/**
* Method to handle a noteon event (synthesize the instrument).
* @param preset Virtual SoundFont preset
* @param synth Synthesizer instance
* @param chan MIDI channel number of the note on event
* @param key MIDI note number (0-127)
* @param vel MIDI velocity (0-127)
* @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
*
* This method may be called from within synthesis context and therefore
* should be as efficient as possible and not perform any operations considered
* bad for realtime audio output (memory allocations and other OS calls).
*
* 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 increment the values of a
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
* finished initializing the voice call fluid_voice_start() to
* start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
* created will be started at the same time.
*/
int (*noteon)(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
/**
* Virtual SoundFont preset notify method.
* @param preset Virtual SoundFont preset
* @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED
* @param chan MIDI channel number
* @return Should return #FLUID_OK
*
* Implement this optional method if the preset needs to be notified about
* preset select and unselect events.
*
* This method may be called from within synthesis context and therefore
* should be as efficient as possible and not perform any operations considered
* bad for realtime audio output (memory allocations and other OS calls).
*/
int (*notify)(fluid_preset_t* preset, int reason, int chan);
};
/**
* Virtual SoundFont sample.
*/
struct _fluid_sample_t
{
char name[21]; /**< Sample name */
unsigned int start; /**< Start index */
unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */
unsigned int loopstart; /**< Loop start index */
unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */
unsigned int samplerate; /**< Sample rate */
int origpitch; /**< Original pitch (MIDI note number, 0-127) */
int pitchadj; /**< Fine pitch adjustment (+/- 99 cents) */
int sampletype; /**< Values: #FLUID_SAMPLETYPE_MONO, FLUID_SAMPLETYPE_RIGHT, FLUID_SAMPLETYPE_LEFT, FLUID_SAMPLETYPE_ROM */
int valid; /**< Should be TRUE if sample data is valid, FALSE otherwise (in which case it will not be synthesized) */
short* data; /**< Pointer to the sample's data */
int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */
double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */
unsigned int refcount; /**< Count of voices using this sample (use #fluid_sample_refcount to access this field) */
/**
* Implement this function to receive notification when sample is no longer used.
* @param sample Virtual SoundFont sample
* @param reason #FLUID_SAMPLE_DONE only currently
* @return Should return #FLUID_OK
*/
int (*notify)(fluid_sample_t* sample, int reason);
void* userdata; /**< User defined data */
};
#define fluid_sample_refcount(_sample) ((_sample)->refcount) /**< Get the reference count of a sample. Should only be called from within synthesis context (noteon method for example) */
#define FLUID_SAMPLETYPE_MONO 1 /**< Flag for #fluid_sample_t \a sampletype field for mono samples */
#define FLUID_SAMPLETYPE_RIGHT 2 /**< Flag for #fluid_sample_t \a sampletype field for right samples of a stereo pair */
#define FLUID_SAMPLETYPE_LEFT 4 /**< Flag for #fluid_sample_t \a sampletype field for left samples of a stereo pair */
#define FLUID_SAMPLETYPE_LINKED 8 /**< Flag for #fluid_sample_t \a sampletype field, not used currently */
#define FLUID_SAMPLETYPE_ROM 0x8000 /**< Flag for #fluid_sample_t \a sampletype field, ROM sample, causes sample to be ignored */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SFONT_H */

View File

@ -0,0 +1,315 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SYNTH_H
#define _FLUIDSYNTH_SYNTH_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file synth.h
* @brief Embeddable SoundFont 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(), ...
*/
#define FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE 32 /**< Length of channel info name field (including zero terminator) */
/**
* Channel information structure for fluid_synth_get_channel_info().
* @since 1.1.1
*/
struct _fluid_synth_channel_info_t
{
int assigned : 1; /**< TRUE if a preset is assigned, FALSE otherwise */
/* Reserved flag bits (at the least 31) */
int sfont_id; /**< ID of parent SoundFont */
int bank; /**< MIDI bank number (0-16383) */
int program; /**< MIDI program number (0-127) */
char name[FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE]; /**< Channel preset name */
char reserved[32]; /**< Reserved data for future expansion */
};
FLUIDSYNTH_API fluid_synth_t* new_fluid_synth(fluid_settings_t* settings);
FLUIDSYNTH_API int delete_fluid_synth(fluid_synth_t* synth);
FLUIDSYNTH_API fluid_settings_t* fluid_synth_get_settings(fluid_synth_t* synth);
/* MIDI channel messages */
FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel);
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key);
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t* synth, int chan, int ctrl, int val);
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t* synth, int chan, int ctrl, int* pval);
FLUIDSYNTH_API int fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
char *response, int *response_len, int *handled, int dryrun);
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend);
FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id);
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);
FLUIDSYNTH_API int
fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
const char *sfont_name, unsigned int bank_num,
unsigned int preset_num);
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);
FLUIDSYNTH_API int fluid_synth_unset_program (fluid_synth_t *synth, int chan);
FLUIDSYNTH_API int fluid_synth_get_channel_info (fluid_synth_t *synth, int chan,
fluid_synth_channel_info_t *info);
FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan);
FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan);
enum fluid_midi_channel_type
{
CHANNEL_TYPE_MELODIC = 0,
CHANNEL_TYPE_DRUM = 1
};
int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type);
/* Low level access */
FLUIDSYNTH_API fluid_preset_t* fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan);
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);
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t* synth, unsigned int id);
/* SoundFont management */
FLUIDSYNTH_API
int fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets);
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets);
FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
FLUIDSYNTH_API void fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t* synth);
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num);
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id);
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_name (fluid_synth_t* synth,
const char *name);
FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset);
FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id);
/* Reverb */
FLUIDSYNTH_API void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize,
double damping, double width, double level);
FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t* synth, int on);
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);
#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f /**< Default reverb room size */
#define FLUID_REVERB_DEFAULT_DAMP 0.0f /**< Default reverb damping */
#define FLUID_REVERB_DEFAULT_WIDTH 0.5f /**< Default reverb width */
#define FLUID_REVERB_DEFAULT_LEVEL 0.9f /**< Default reverb level */
/* Chorus */
/**
* Chorus modulation waveform type.
*/
enum fluid_chorus_mod {
FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */
FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
};
FLUIDSYNTH_API void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
double speed, double depth_ms, int type);
FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t* synth, int on);
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 */
#define FLUID_CHORUS_DEFAULT_N 3 /**< Default chorus voice count */
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f /**< Default chorus level */
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f /**< Default chorus speed */
#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f /**< Default chorus depth */
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE /**< Default chorus waveform type */
/* Audio and MIDI channels */
FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t* synth);
/* Synthesis parameters */
FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t* synth, float sample_rate);
FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t* synth, float gain);
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony);
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_get_active_voice_count(fluid_synth_t* synth);
FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t* synth);
FLUIDSYNTH_API
int fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method);
/**
* Synthesis interpolation method.
*/
enum fluid_interp {
FLUID_INTERP_NONE = 0, /**< No interpolation: Fastest, but questionable audio quality */
FLUID_INTERP_LINEAR = 1, /**< Straight-line interpolation: A bit slower, reasonable audio quality */
FLUID_INTERP_4THORDER = 4, /**< Fourth-order interpolation, good quality, the default */
FLUID_INTERP_7THORDER = 7 /**< Seventh-order interpolation */
};
#define FLUID_INTERP_DEFAULT FLUID_INTERP_4THORDER /**< Default interpolation method from #fluid_interp. */
#define FLUID_INTERP_HIGHEST FLUID_INTERP_7THORDER /**< Highest interpolation method from #fluid_interp. */
/* Generator interface */
FLUIDSYNTH_API
int fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value);
FLUIDSYNTH_API int fluid_synth_set_gen2 (fluid_synth_t* synth, int chan,
int param, float value,
int absolute, int normalized);
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
/* Tuning */
FLUIDSYNTH_API
int fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
const char* name, const double* pitch);
FLUIDSYNTH_API
int fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
const char* name, const double* pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
const char* name, const double* pitch);
FLUIDSYNTH_API
int fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
const char* name, const double* pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
int len, const int *keys, const double* pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog);
FLUIDSYNTH_API
int fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
int apply);
FLUIDSYNTH_API int fluid_synth_reset_tuning(fluid_synth_t* synth, int chan);
FLUIDSYNTH_API
int fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply);
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t* synth);
FLUIDSYNTH_API
int fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog);
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
char* name, int len, double* pitch);
/* Misc */
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t* synth);
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.
*/
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);
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);
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.
* @param synth FluidSynth instance
* @param len Count of audio frames to synthesize
* @param out1 Array to store left channel of audio to
* @param loff Offset index in 'out1' for first sample
* @param lincr Increment between samples stored to 'out1'
* @param out2 Array to store right channel of audio to
* @param roff Offset index in 'out2' for first sample
* @param rincr Increment between samples stored to 'out2'
*/
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 */
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader);
FLUIDSYNTH_API fluid_voice_t* fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample,
int channum, int key, int vel);
FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice);
FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t* synth,
fluid_voice_t* buf[], int bufsize, int ID);
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event);
FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
fluid_midi_router_t* router);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SYNTH_H */

View File

@ -0,0 +1,68 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_TYPES_H
#define _FLUIDSYNTH_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file types.h
* @brief Type declarations
*/
typedef struct _fluid_hashtable_t fluid_settings_t; /**< Configuration settings instance */
typedef struct _fluid_synth_t fluid_synth_t; /**< Synthesizer instance */
typedef struct _fluid_synth_channel_info_t fluid_synth_channel_info_t; /**< SoundFont channel info */
typedef struct _fluid_voice_t fluid_voice_t; /**< Synthesis voice instance */
typedef struct _fluid_sfloader_t fluid_sfloader_t; /**< SoundFont loader plugin */
typedef struct _fluid_sfont_t fluid_sfont_t; /**< SoundFont */
typedef struct _fluid_preset_t fluid_preset_t; /**< SoundFont preset */
typedef struct _fluid_sample_t fluid_sample_t; /**< SoundFont sample */
typedef struct _fluid_mod_t fluid_mod_t; /**< SoundFont modulator */
typedef struct _fluid_audio_driver_t fluid_audio_driver_t; /**< Audio driver instance */
typedef struct _fluid_file_renderer_t fluid_file_renderer_t; /**< Audio file renderer instance */
typedef struct _fluid_player_t fluid_player_t; /**< MIDI player instance */
typedef struct _fluid_midi_event_t fluid_midi_event_t; /**< MIDI event */
typedef struct _fluid_midi_driver_t fluid_midi_driver_t; /**< MIDI driver instance */
typedef struct _fluid_midi_router_t fluid_midi_router_t; /**< MIDI router instance */
typedef struct _fluid_midi_router_rule_t fluid_midi_router_rule_t; /**< MIDI router rule */
typedef struct _fluid_hashtable_t fluid_cmd_handler_t; /**< Command handler */
typedef struct _fluid_shell_t fluid_shell_t; /**< Command shell */
typedef struct _fluid_server_t fluid_server_t; /**< TCP/IP shell server instance */
typedef struct _fluid_event_t fluid_event_t; /**< Sequencer event */
typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer instance */
typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */
typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */
typedef int fluid_istream_t; /**< Input stream descriptor */
typedef int fluid_ostream_t; /**< Output stream descriptor */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_TYPES_H */

View File

@ -0,0 +1,64 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_VOICE_H
#define _FLUIDSYNTH_VOICE_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file voice.h
* @brief Synthesis voice manipulation functions.
*
* The interface to the synthesizer's voices.
* Examples on using them can be found in fluid_defsfont.c.
* Most of these functions should only be called from within synthesis context,
* such as the SoundFont loader's noteon method.
*/
FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t* voice, int gen);
/**
* Enum used with fluid_voice_add_mod() to specify how to handle duplicate modulators.
*/
enum fluid_voice_add_mod {
FLUID_VOICE_OVERWRITE, /**< Overwrite any existing matching modulator */
FLUID_VOICE_ADD, /**< Add (sum) modulator amounts */
FLUID_VOICE_DEFAULT /**< For default modulators only, no need to check for duplicates */
};
FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t* voice, fluid_mod_t* mod, int mode);
FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t* voice, int gen, float val);
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t* voice, int gen);
FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t* voice, int gen, float val);
FLUIDSYNTH_API unsigned int fluid_voice_get_id(fluid_voice_t* voice);
FLUIDSYNTH_API int fluid_voice_is_playing(fluid_voice_t* voice);
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t* s);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_VOICE_H */

View File

@ -0,0 +1,38 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_adsr_env.h"
void
fluid_adsr_env_set_data(fluid_adsr_env_t* env,
fluid_adsr_env_section_t section,
unsigned int count,
fluid_real_t coeff,
fluid_real_t increment,
fluid_real_t min,
fluid_real_t max)
{
env->data[section].count = count;
env->data[section].coeff = coeff;
env->data[section].increment = increment;
env->data[section].min = min;
env->data[section].max = max;
}

View File

@ -0,0 +1,162 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_ADSR_ENVELOPE_H
#define _FLUID_ADSR_ENVELOPE_H
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
/*
* envelope data
*/
struct _fluid_env_data_t {
unsigned int count;
fluid_real_t coeff;
fluid_real_t increment;
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
};
typedef enum fluid_voice_envelope_index_t fluid_adsr_env_section_t;
typedef struct _fluid_adsr_env_t fluid_adsr_env_t;
struct _fluid_adsr_env_t {
fluid_env_data_t data[FLUID_VOICE_ENVLAST];
unsigned int count;
int section;
fluid_real_t val; /* the current value of the envelope */
};
/* For performance, all functions are inlined */
static FLUID_INLINE void
fluid_adsr_env_calc(fluid_adsr_env_t* env, int is_volenv)
{
fluid_env_data_t* env_data;
fluid_real_t x;
env_data = &env->data[env->section];
/* skip to the next section of the envelope if necessary */
while (env->count >= env_data->count)
{
// If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage
// Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH]
if (env->section == FLUID_VOICE_ENVDECAY && is_volenv)
env->val = env_data->min * env_data->coeff;
env_data = &env->data[++env->section];
env->count = 0;
}
/* calculate the envelope value and check for valid range */
x = env_data->coeff * env->val + env_data->increment;
if (x < env_data->min)
{
x = env_data->min;
env->section++;
env->count = 0;
}
else if (x > env_data->max)
{
x = env_data->max;
env->section++;
env->count = 0;
}
env->val = x;
env->count++;
}
/* This one cannot be inlined since it is referenced in
the event queue */
void
fluid_adsr_env_set_data(fluid_adsr_env_t* env,
fluid_adsr_env_section_t section,
unsigned int count,
fluid_real_t coeff,
fluid_real_t increment,
fluid_real_t min,
fluid_real_t max);
static inline void
fluid_adsr_env_reset(fluid_adsr_env_t* env)
{
env->count = 0;
env->section = 0;
env->val = 0.0f;
}
static inline fluid_real_t
fluid_adsr_env_get_val(fluid_adsr_env_t* env)
{
return env->val;
}
static inline void
fluid_adsr_env_set_val(fluid_adsr_env_t* env, fluid_real_t val)
{
env->val = val;
}
static inline fluid_adsr_env_section_t
fluid_adsr_env_get_section(fluid_adsr_env_t* env)
{
return env->section;
}
static inline void
fluid_adsr_env_set_section(fluid_adsr_env_t* env,
fluid_adsr_env_section_t section)
{
env->section = section;
env->count = 0;
}
/* Used for determining which voice to kill.
Returns max amplitude from now, and forward in time.
*/
static inline fluid_real_t
fluid_adsr_env_get_max_val(fluid_adsr_env_t* env)
{
if (env->section > FLUID_VOICE_ENVATTACK){
return env->val * 1000;
} else {
return env->data[FLUID_VOICE_ENVATTACK].max;
}
}
#endif

View File

@ -0,0 +1,291 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_chan.h"
#include "fluid_mod.h"
#include "fluid_synth.h"
#include "fluid_sfont.h"
/* Field shift amounts for sfont_bank_prog bit field integer */
#define PROG_SHIFTVAL 0
#define BANK_SHIFTVAL 8
#define SFONT_SHIFTVAL 22
/* Field mask values for sfont_bank_prog bit field integer */
#define PROG_MASKVAL 0x000000FF /* Bit 7 is used to indicate unset state */
#define BANK_MASKVAL 0x003FFF00
#define BANKLSB_MASKVAL 0x00007F00
#define BANKMSB_MASKVAL 0x003F8000
#define SFONT_MASKVAL 0xFFC00000
static void fluid_channel_init(fluid_channel_t* chan);
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;
chan->preset = NULL;
chan->tuning = NULL;
fluid_channel_init(chan);
fluid_channel_init_ctrl(chan, 0);
return chan;
}
static void
fluid_channel_init(fluid_channel_t* chan)
{
fluid_preset_t *newpreset;
int prognum, banknum;
chan->sostenuto_orderid = 0;
chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
prognum = 0;
banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
| prognum << PROG_SHIFTVAL;
newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
fluid_channel_set_preset(chan, newpreset);
chan->interp_method = FLUID_INTERP_DEFAULT;
chan->tuning_bank = 0;
chan->tuning_prog = 0;
chan->nrpn_select = 0;
chan->nrpn_active = 0;
if (chan->tuning)
{
fluid_tuning_unref (chan->tuning, 1);
chan->tuning = NULL;
}
}
/*
@param is_all_ctrl_off if nonzero, only resets some controllers, according to
http://www.midi.org/techspecs/rp15.php
*/
void
fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
{
int i;
chan->key_pressure = 0;
chan->channel_pressure = 0;
chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
for (i = 0; i < GEN_LAST; i++) {
chan->gen[i] = 0.0f;
chan->gen_abs[i] = 0;
}
if (is_all_ctrl_off) {
for (i = 0; i < ALL_SOUND_OFF; i++) {
if (i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5) {
continue;
}
if (i >= SOUND_CTRL1 && i <= SOUND_CTRL10) {
continue;
}
if (i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB) {
continue;
}
fluid_channel_set_cc (chan, i, 0);
}
}
else {
for (i = 0; i < 128; i++) {
fluid_channel_set_cc (chan, i, 0);
}
}
/* Set RPN controllers to NULL state */
fluid_channel_set_cc (chan, RPN_LSB, 127);
fluid_channel_set_cc (chan, RPN_MSB, 127);
/* Set NRPN controllers to NULL state */
fluid_channel_set_cc (chan, NRPN_LSB, 127);
fluid_channel_set_cc (chan, NRPN_MSB, 127);
/* Expression (MSB & LSB) */
fluid_channel_set_cc (chan, EXPRESSION_MSB, 127);
fluid_channel_set_cc (chan, EXPRESSION_LSB, 127);
if (!is_all_ctrl_off) {
chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
/* Just like panning, a value of 64 indicates no change for sound ctrls */
for (i = SOUND_CTRL1; i <= SOUND_CTRL10; i++) {
fluid_channel_set_cc (chan, i, 64);
}
/* Volume / initial attenuation (MSB & LSB) */
fluid_channel_set_cc (chan, VOLUME_MSB, 100);
fluid_channel_set_cc (chan, VOLUME_LSB, 0);
/* Pan (MSB & LSB) */
fluid_channel_set_cc (chan, PAN_MSB, 64);
fluid_channel_set_cc (chan, PAN_LSB, 0);
/* Reverb */
/* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */
/* Note: although XG standard specifies the default amount of reverb to
be 40, most people preferred having it at zero.
See http://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
}
}
/* Only called by delete_fluid_synth(), so no need to queue a preset free event */
int
delete_fluid_channel(fluid_channel_t* chan)
{
if (chan->preset) delete_fluid_preset (chan->preset);
FLUID_FREE(chan);
return FLUID_OK;
}
/* FIXME - Calls fluid_channel_init() potentially in synthesis context */
void
fluid_channel_reset(fluid_channel_t* chan)
{
fluid_channel_init(chan);
fluid_channel_init_ctrl(chan, 0);
}
/* Should only be called from synthesis context */
int
fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
{
fluid_preset_notify (chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
if (chan->preset) {
fluid_sfont_t *sfont;
sfont = chan->preset->sfont;
delete_fluid_preset (chan->preset);
fluid_synth_sfont_unref (chan->synth, sfont); /* -- unref preset's SoundFont */
}
chan->preset = preset;
fluid_preset_notify (preset, FLUID_PRESET_SELECTED, chan->channum);
return FLUID_OK;
}
/* Set SoundFont ID, MIDI bank and/or program. Use -1 to use current value. */
void
fluid_channel_set_sfont_bank_prog(fluid_channel_t* chan, int sfontnum,
int banknum, int prognum)
{
int oldval, newval, oldmask;
newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)
| ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)
| ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);
oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)
| ((banknum != -1) ? 0 : BANK_MASKVAL)
| ((prognum != -1) ? 0 : PROG_MASKVAL);
oldval = chan->sfont_bank_prog;
newval = (newval & ~oldmask) | (oldval & oldmask);
chan->sfont_bank_prog = newval;
}
/* Set bank LSB 7 bits */
void
fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb)
{
int oldval, newval, style;
style = chan->synth->bank_select;
if (style == FLUID_BANK_STYLE_GM ||
style == FLUID_BANK_STYLE_GS)
return; /* ignored */
oldval = chan->sfont_bank_prog;
if (style == FLUID_BANK_STYLE_XG)
newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL);
else /* style == FLUID_BANK_STYLE_MMA */
newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);
chan->sfont_bank_prog = newval;
}
/* Set bank MSB 7 bits */
void
fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb)
{
int oldval, newval, style;
style = chan->synth->bank_select;
if (style == FLUID_BANK_STYLE_XG)
{
/* XG bank, do drum-channel auto-switch */
/* The number "120" was based on several keyboards having drums at 120 - 127,
reference: http://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
return;
}
if (style == FLUID_BANK_STYLE_GM ||
chan->channel_type == CHANNEL_TYPE_DRUM)
return; /* ignored */
oldval = chan->sfont_bank_prog;
if (style == FLUID_BANK_STYLE_GS)
newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL);
else /* style == FLUID_BANK_STYLE_MMA */
newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
chan->sfont_bank_prog = newval;
}
/* Get SoundFont ID, MIDI bank and/or program. Use NULL to ignore a value. */
void
fluid_channel_get_sfont_bank_prog(fluid_channel_t* chan, int *sfont,
int *bank, int *prog)
{
int sfont_bank_prog;
sfont_bank_prog = chan->sfont_bank_prog;
if (sfont) *sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL;
if (bank) *bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;
if (prog) *prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;
}

View File

@ -0,0 +1,149 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_CHAN_H
#define _FLUID_CHAN_H
#include "fluidsynth_priv.h"
#include "fluid_midi.h"
#include "fluid_tuning.h"
/*
* fluid_channel_t
*
* Mutual exclusion notes (as of 1.1.2):
* None - everything should have been synchronized by the synth.
*/
struct _fluid_channel_t
{
fluid_mutex_t mutex; /* Lock for thread sensitive parameters */
fluid_synth_t* synth; /**< Parent synthesizer instance */
int channum; /**< MIDI channel number */
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
fluid_preset_t* preset; /**< Selected preset */
int key_pressure; /**< MIDI key pressure */
int channel_pressure; /**< MIDI channel pressure */
int pitch_bend; /**< Current pitch bend value */
int pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
int cc[128]; /**< MIDI controller values */
/* Sostenuto order id gives the order of SostenutoOn event.
This value is useful to known when the sostenuto pedal is depressed
(before or after a key note). We need to compare SostenutoOrderId with voice id.
*/
unsigned int sostenuto_orderid;
int interp_method; /**< Interpolation method (enum fluid_interp) */
fluid_tuning_t* tuning; /**< Micro tuning */
int tuning_bank; /**< Current tuning bank number */
int tuning_prog; /**< Current tuning program number */
/* NRPN system */
int nrpn_select; /* Generator ID of SoundFont NRPN message */
int nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
/* 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(), which 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 SoundFont
* 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];
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
int channel_type;
};
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
void fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off);
int delete_fluid_channel(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);
void fluid_channel_set_sfont_bank_prog(fluid_channel_t* chan, int sfont,
int bank, int prog);
void fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb);
void fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb);
void fluid_channel_get_sfont_bank_prog(fluid_channel_t* chan, int *sfont,
int *bank, int *prog);
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_get_preset(chan) ((chan)->preset)
#define fluid_channel_set_cc(chan, num, val) \
((chan)->cc[num] = (val))
#define fluid_channel_get_cc(chan, num) \
((chan)->cc[num])
#define fluid_channel_get_key_pressure(chan) \
((chan)->key_pressure)
#define fluid_channel_set_key_pressure(chan, val) \
((chan)->key_pressure = (val))
#define fluid_channel_get_channel_pressure(chan) \
((chan)->channel_pressure)
#define fluid_channel_set_channel_pressure(chan, val) \
((chan)->channel_pressure = (val))
#define fluid_channel_get_pitch_bend(chan) \
((chan)->pitch_bend)
#define fluid_channel_set_pitch_bend(chan, val) \
((chan)->pitch_bend = (val))
#define fluid_channel_get_pitch_wheel_sensitivity(chan) \
((chan)->pitch_wheel_sensitivity)
#define fluid_channel_set_pitch_wheel_sensitivity(chan, val) \
((chan)->pitch_wheel_sensitivity = (val))
#define fluid_channel_get_num(chan) ((chan)->channum)
#define fluid_channel_set_interp_method(chan, new_method) \
((chan)->interp_method = (new_method))
#define fluid_channel_get_interp_method(chan) \
((chan)->interp_method);
#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_get_tuning_bank(chan) \
((chan)->tuning_bank)
#define fluid_channel_set_tuning_bank(chan, bank) \
((chan)->tuning_bank = (bank))
#define fluid_channel_get_tuning_prog(chan) \
((chan)->tuning_prog)
#define fluid_channel_set_tuning_prog(chan, prog) \
((chan)->tuning_prog = (prog))
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
#define fluid_channel_sostenuto(_c) ((_c)->cc[SOSTENUTO_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])
#define fluid_channel_get_min_note_length_ticks(chan) \
((chan)->synth->min_note_length_ticks)
#endif /* _FLUID_CHAN_H */

View File

@ -0,0 +1,506 @@
/*
* 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 {
int type;
fluid_real_t depth_ms;
fluid_real_t level;
fluid_real_t speed_Hz;
int number_blocks;
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];
};
static void fluid_chorus_triangle(int *buf, int len, int depth);
static 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;
}
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);
}
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 (chorus, FLUID_CHORUS_SET_ALL, FLUID_CHORUS_DEFAULT_N,
FLUID_CHORUS_DEFAULT_LEVEL, FLUID_CHORUS_DEFAULT_SPEED,
FLUID_CHORUS_DEFAULT_DEPTH, FLUID_CHORUS_MOD_SINE);
return FLUID_OK;
}
void
fluid_chorus_reset(fluid_chorus_t* chorus)
{
fluid_chorus_init(chorus);
}
/**
* Set one or more chorus parameters.
* @param chorus Chorus instance
* @param set Flags indicating which chorus parameters to set (#fluid_chorus_set_t)
* @param nr Chorus voice count (0-99, CPU time consumption proportional to
* this value)
* @param level Chorus level (0.0-10.0)
* @param speed Chorus speed in Hz (0.29-5.0)
* @param depth_ms Chorus depth (max value depends on synth sample rate,
* 0.0-21.0 is safe for sample rate values up to 96KHz)
* @param type Chorus waveform type (#fluid_chorus_mod)
*/
void
fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
float speed, float depth_ms, int type)
{
int modulation_depth_samples;
int i;
if (set & FLUID_CHORUS_SET_NR) chorus->number_blocks = nr;
if (set & FLUID_CHORUS_SET_LEVEL) chorus->level = level;
if (set & FLUID_CHORUS_SET_SPEED) chorus->speed_Hz = speed;
if (set & FLUID_CHORUS_SET_DEPTH) chorus->depth_ms = depth_ms;
if (set & FLUID_CHORUS_SET_TYPE) chorus->type = type;
if (chorus->number_blocks < 0) {
fluid_log(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0.");
chorus->number_blocks = 0;
} else if (chorus->number_blocks > MAX_CHORUS) {
fluid_log(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.",
MAX_CHORUS);
chorus->number_blocks = MAX_CHORUS;
}
if (chorus->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->speed_Hz = MIN_SPEED_HZ;
} else if (chorus->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->speed_Hz = MAX_SPEED_HZ;
}
if (chorus->depth_ms < 0.0) {
fluid_log(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
chorus->depth_ms = 0.0;
}
/* Depth: Check for too high value through modulation_depth_samples. */
if (chorus->level < 0.0) {
fluid_log(FLUID_WARN, "chorus: level must be positive! Setting value to 0.");
chorus->level = 0.0;
} else if (chorus->level > 10) {
fluid_log(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! "
"Setting it to 0.1.");
chorus->level = 0.1;
}
/* The modulating LFO goes through a full period every x samples: */
chorus->modulation_period_samples = chorus->sample_rate / chorus->speed_Hz;
/* The variation in delay time is x: */
modulation_depth_samples = (int)
(chorus->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;
}
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 ... (replaces sample data instead of mixing) */
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
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;
/* Store 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.
*/
static 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.
*/
static 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;
}
}

View File

@ -0,0 +1,61 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_CHORUS_H
#define _FLUID_CHORUS_H
#include "fluidsynth_priv.h"
typedef struct _fluid_chorus_t fluid_chorus_t;
/** Flags for fluid_chorus_set() */
typedef enum
{
FLUID_CHORUS_SET_NR = 1 << 0,
FLUID_CHORUS_SET_LEVEL = 1 << 1,
FLUID_CHORUS_SET_SPEED = 1 << 2,
FLUID_CHORUS_SET_DEPTH = 1 << 3,
FLUID_CHORUS_SET_TYPE = 1 << 4,
} fluid_chorus_set_t;
/** Value for fluid_chorus_set() which sets all chorus parameters. */
#define FLUID_CHORUS_SET_ALL 0x1F
/*
* chorus
*/
fluid_chorus_t* new_fluid_chorus(fluid_real_t sample_rate);
void delete_fluid_chorus(fluid_chorus_t* chorus);
int fluid_chorus_init(fluid_chorus_t* chorus);
void fluid_chorus_reset(fluid_chorus_t* chorus);
void fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
float speed, float depth_ms, int type);
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);
#endif /* _FLUID_CHORUS_H */

View File

@ -0,0 +1,320 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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];
}

View File

@ -0,0 +1,63 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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. */
/* 07/11/2008 modified by S. Christian Collins for increased velocity sensitivity. Now it equals the response of EMU10K1 programming.*/
#define FLUID_ATTEN_POWER_FACTOR (-200.0) /* was (-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

View File

@ -0,0 +1,530 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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 */
fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */
}
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_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 02110-1301, USA.
*/
#include <glib.h>
/*-----------------------------------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, ...);
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(fluid_settings_t* settings);
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 */
int mlock; /* Should we try memlock (avoid swapping)? */
fluid_preset_t iter_preset; /* preset interface used in the iteration */
fluid_defpreset_t* iter_cur; /* the current preset in the iteration */
fluid_preset_t** preset_stack; /* List of presets that are available to use */
int preset_stack_capacity; /* Length of preset_stack array */
int preset_stack_size; /* Current number of items in the stack */
};
fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings);
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_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 */

View File

@ -0,0 +1,781 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
/*
2002 : API design by Peter Hanappe and Antoine Schmitt
August 2002 : Implementation by Antoine Schmitt as@gratin.org
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 */
void
fluid_event_clear(fluid_event_t* evt)
{
FLUID_MEMSET(evt, 0, sizeof(fluid_event_t));
// by default, no type
evt->dest = -1;
evt->src = -1;
evt->type = -1;
}
/**
* Create a new sequencer event structure.
* @return New sequencer event structure or NULL if out of memory
*/
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_event_clear(evt);
return(evt);
}
/**
* Delete a sequencer event structure.
* @param evt Sequencer event structure created by new_fluid_event().
*/
void
delete_fluid_event(fluid_event_t* evt)
{
if (evt == NULL) {
return;
}
FLUID_FREE(evt);
}
/**
* Set the time field of a sequencer event.
* @internal
* @param evt Sequencer event structure
* @param time Time value to assign
*/
void
fluid_event_set_time(fluid_event_t* evt, unsigned int time)
{
evt->time = time;
}
/**
* Set source of a sequencer event (DOCME).
* @param evt Sequencer event structure
* @param src DOCME
*/
void
fluid_event_set_source(fluid_event_t* evt, short src)
{
evt->src = src;
}
/**
* Set destination of a sequencer event (DOCME).
* @param evt Sequencer event structure
* @param dest DOCME
*/
void
fluid_event_set_dest(fluid_event_t* evt, short dest)
{
evt->dest = dest;
}
/**
* Set a sequencer event to be a timer event.
* @param evt Sequencer event structure
* @param data DOCME
*/
void
fluid_event_timer(fluid_event_t* evt, void* data)
{
evt->type = FLUID_SEQ_TIMER;
evt->data = data;
}
/**
* Set a sequencer event to be a note on event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param key MIDI note number (0-127)
* @param vel MIDI velocity value (0-127)
*/
void
fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel)
{
evt->type = FLUID_SEQ_NOTEON;
evt->channel = channel;
evt->key = key;
evt->vel = vel;
}
/**
* Set a sequencer event to be a note off event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param key MIDI note number (0-127)
*/
void
fluid_event_noteoff(fluid_event_t* evt, int channel, short key)
{
evt->type = FLUID_SEQ_NOTEOFF;
evt->channel = channel;
evt->key = key;
}
/**
* Set a sequencer event to be a note duration event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param key MIDI note number (0-127)
* @param vel MIDI velocity value (0-127)
* @param duration Duration of note (DOCME units?)
*/
void
fluid_event_note(fluid_event_t* evt, int channel, short key, short vel, unsigned int duration)
{
evt->type = FLUID_SEQ_NOTE;
evt->channel = channel;
evt->key = key;
evt->vel = vel;
evt->duration = duration;
}
/**
* Set a sequencer event to be an all sounds off event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
*/
void
fluid_event_all_sounds_off(fluid_event_t* evt, int channel)
{
evt->type = FLUID_SEQ_ALLSOUNDSOFF;
evt->channel = channel;
}
/**
* Set a sequencer event to be a all notes off event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
*/
void
fluid_event_all_notes_off(fluid_event_t* evt, int channel)
{
evt->type = FLUID_SEQ_ALLNOTESOFF;
evt->channel = channel;
}
/**
* Set a sequencer event to be a bank select event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param bank_num MIDI bank number (0-16383)
*/
void
fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num)
{
evt->type = FLUID_SEQ_BANKSELECT;
evt->channel = channel;
evt->control = bank_num;
}
/**
* Set a sequencer event to be a program change event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val MIDI program number (0-127)
*/
void
fluid_event_program_change(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_PROGRAMCHANGE;
evt->channel = channel;
evt->value = val;
}
/**
* Set a sequencer event to be a program select event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param sfont_id SoundFont ID number
* @param bank_num MIDI bank number (0-16383)
* @param preset_num MIDI preset number (0-127)
*/
void
fluid_event_program_select(fluid_event_t* evt, int channel,
unsigned int sfont_id, short bank_num, short preset_num)
{
evt->type = FLUID_SEQ_PROGRAMSELECT;
evt->channel = channel;
evt->duration = sfont_id;
evt->value = preset_num;
evt->control = bank_num;
}
/**
* Set a sequencer event to be an any control change event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* DOCME
*/
void
fluid_event_any_control_change(fluid_event_t* evt, int channel)
{
evt->type = FLUID_SEQ_ANYCONTROLCHANGE;
evt->channel = channel;
}
/**
* Set a sequencer event to be a pitch bend event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param pitch MIDI pitch bend value (0-16383, 8192 = no bend)
*/
void
fluid_event_pitch_bend(fluid_event_t* evt, int channel, int pitch)
{
evt->type = FLUID_SEQ_PITCHBEND;
evt->channel = channel;
if (pitch < 0) pitch = 0;
if (pitch > 16383) pitch = 16383;
evt->pitch = pitch;
}
/**
* Set a sequencer event to be a pitch wheel sensitivity event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param value MIDI pitch wheel sensitivity value (DOCME units?)
*/
void
fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short value)
{
evt->type = FLUID_SEQ_PITCHWHHELSENS;
evt->channel = channel;
evt->value = value;
}
/**
* Set a sequencer event to be a modulation event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val MIDI modulation value (0-127)
*/
void
fluid_event_modulation(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_MODULATION;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/**
* Set a sequencer event to be a MIDI sustain event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val MIDI sustain value (0-127)
*/
void
fluid_event_sustain(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_SUSTAIN;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/**
* Set a sequencer event to be a MIDI control change event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param control MIDI control number (0-127)
* @param val MIDI control value (0-16383 DOCME is that true?)
*/
void
fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val)
{
evt->type = FLUID_SEQ_CONTROLCHANGE;
evt->channel = channel;
evt->control = control;
evt->value = val;
}
/**
* Set a sequencer event to be a stereo pan event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val MIDI panning value (0-127, 0=left, 64 = middle, 127 = right)
*/
void
fluid_event_pan(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_PAN;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/**
* Set a sequencer event to be a volume event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val Volume value (0-127)
*/
void
fluid_event_volume(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_VOLUME;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/**
* Set a sequencer event to be a reverb send event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val Reverb amount (0-127)
*/
void
fluid_event_reverb_send(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_REVERBSEND;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/**
* Set a sequencer event to be a chorus send event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val Chorus amount (0-127)
*/
void
fluid_event_chorus_send(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_CHORUSSEND;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/**
* Set a sequencer event to be an unregistering event.
* @param evt Sequencer event structure
* @since 1.1.0
*/
void
fluid_event_unregistering(fluid_event_t* evt)
{
evt->type = FLUID_SEQ_UNREGISTERING;
}
/**
* Set a sequencer event to be a channel-wide aftertouch event.
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param val Aftertouch amount (0-127)
* @since 1.1.0
*/
void
fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val)
{
evt->type = FLUID_SEQ_CHANNELPRESSURE;
evt->channel = channel;
if (val < 0) val = 0;
if (val > 127) val = 127;
evt->value = val;
}
/**
* Set a sequencer event to be a midi system reset event.
* @param evt Sequencer event structure
* @since 1.1.0
*/
void
fluid_event_system_reset(fluid_event_t* evt)
{
evt->type = FLUID_SEQ_SYSTEMRESET;
}
/*
* Accessing event data
*/
/**
* Get the event type (#fluid_seq_event_type) field from a sequencer event structure.
* @param evt Sequencer event structure
* @return Event type (#fluid_seq_event_type).
*/
int fluid_event_get_type(fluid_event_t* evt)
{
return evt->type;
}
/**
* Get the time field from a sequencer event structure.
* @param evt Sequencer event structure
* @return Time value (DOCME units?)
*/
unsigned int fluid_event_get_time(fluid_event_t* evt)
{
return evt->time;
}
/**
* Get the source field from a sequencer event structure.
* @param evt Sequencer event structure
* @return DOCME
*/
short fluid_event_get_source(fluid_event_t* evt)
{
return evt->src;
}
/**
* Get the dest field from a sequencer event structure.
* @param evt Sequencer event structure
* @return DOCME
*/
short fluid_event_get_dest(fluid_event_t* evt)
{
return evt->dest;
}
/**
* Get the MIDI channel field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI channel number (DOCME 0-15 or more?)
*/
int fluid_event_get_channel(fluid_event_t* evt)
{
return evt->channel;
}
/**
* Get the MIDI note field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI note number (0-127)
*/
short fluid_event_get_key(fluid_event_t* evt)
{
return evt->key;
}
/**
* Get the MIDI velocity field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI velocity value (0-127)
*/
short fluid_event_get_velocity(fluid_event_t* evt)
{
return evt->vel;
}
/**
* Get the MIDI control number field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI control number (0-127)
*/
short fluid_event_get_control(fluid_event_t* evt)
{
return evt->control;
}
/**
* Get the value field from a sequencer event structure.
* @param evt Sequencer event structure
* @return Value field of event.
*
* The Value field is used by the following event types:
* #FLUID_SEQ_PROGRAMCHANGE, #FLUID_SEQ_PROGRAMSELECT (preset_num),
* #FLUID_SEQ_PITCHWHHELSENS, #FLUID_SEQ_MODULATION, #FLUID_SEQ_SUSTAIN,
* #FLUID_SEQ_CONTROLCHANGE, #FLUID_SEQ_PAN, #FLUID_SEQ_VOLUME,
* #FLUID_SEQ_REVERBSEND, #FLUID_SEQ_CHORUSSEND.
*/
short fluid_event_get_value(fluid_event_t* evt)
{
return evt->value;
}
/**
* Get the data field from a sequencer event structure.
* @param evt Sequencer event structure
* @return Data field of event.
*
* Used by the #FLUID_SEQ_TIMER event type.
*/
void* fluid_event_get_data(fluid_event_t* evt)
{
return evt->data;
}
/**
* Get the duration field from a sequencer event structure.
* @param evt Sequencer event structure
* @return Note duration value (DOCME units?)
*
* Used by the #FLUID_SEQ_NOTE event type.
*/
unsigned int fluid_event_get_duration(fluid_event_t* evt)
{
return evt->duration;
}
/**
* Get the MIDI bank field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI bank number (0-16383)
*
* Used by the #FLUID_SEQ_BANKSELECT and #FLUID_SEQ_PROGRAMSELECT
* event types.
*/
short fluid_event_get_bank(fluid_event_t* evt)
{
return evt->control;
}
/**
* Get the pitch field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI pitch bend pitch value (0-16383, 8192 = no bend)
*
* Used by the #FLUID_SEQ_PITCHBEND event type.
*/
int fluid_event_get_pitch(fluid_event_t* evt)
{
return evt->pitch;
}
/**
* Get the MIDI program field from a sequencer event structure.
* @param evt Sequencer event structure
* @return MIDI program number (0-127)
*
* Used by the #FLUID_SEQ_PROGRAMCHANGE and #FLUID_SEQ_PROGRAMSELECT
* event types.
*/
short
fluid_event_get_program(fluid_event_t* evt)
{
return evt->value;
}
/**
* Get the SoundFont ID field from a sequencer event structure.
* @param evt Sequencer event structure
* @return SoundFont identifier value.
*
* Used by the #FLUID_SEQ_PROGRAMSELECT event type.
*/
unsigned int
fluid_event_get_sfont_id(fluid_event_t* evt)
{
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
}

View File

@ -0,0 +1,83 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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);
void fluid_event_clear(fluid_event_t* evt);
/* 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 */

View File

@ -0,0 +1,195 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_EVENT_QUEUE_H
#define _FLUID_EVENT_QUEUE_H
#include "fluid_sys.h"
#include "fluid_midi.h"
#include "fluid_ringbuffer.h"
/**
* Type of queued event.
*/
enum fluid_event_queue_elem
{
FLUID_EVENT_QUEUE_ELEM_MIDI, /**< MIDI event. Uses midi field of event value */
FLUID_EVENT_QUEUE_ELEM_UPDATE_GAIN, /**< Update synthesizer gain. No payload value */
FLUID_EVENT_QUEUE_ELEM_POLYPHONY, /**< Synth polyphony event. No payload value */
FLUID_EVENT_QUEUE_ELEM_GEN, /**< Generator event. Uses gen field of event value */
FLUID_EVENT_QUEUE_ELEM_PRESET, /**< Preset set event. Uses preset field of event value */
FLUID_EVENT_QUEUE_ELEM_STOP_VOICES, /**< Stop voices event. Uses ival field of event value */
FLUID_EVENT_QUEUE_ELEM_FREE_PRESET, /**< Free preset return event. Uses pval field of event value */
FLUID_EVENT_QUEUE_ELEM_SET_TUNING, /**< Set tuning event. Uses set_tuning field of event value */
FLUID_EVENT_QUEUE_ELEM_REPL_TUNING, /**< Replace tuning event. Uses repl_tuning field of event value */
FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING /**< Unref tuning return event. Uses unref_tuning field of event value */
};
/**
* SoundFont generator set event structure.
*/
typedef struct
{
int channel; /**< MIDI channel number */
int param; /**< FluidSynth generator ID */
float value; /**< Value for the generator (absolute or relative) */
int absolute; /**< 1 if value is absolute, 0 if relative */
} fluid_event_gen_t;
/**
* Preset channel assignment event structure.
*/
typedef struct
{
int channel; /**< MIDI channel number */
fluid_preset_t *preset; /**< Preset to assign (synth thread owns) */
} fluid_event_preset_t;
/**
* Tuning assignment event structure.
*/
typedef struct
{
char apply; /**< TRUE to set tuning in realtime */
int channel; /**< MIDI channel number */
fluid_tuning_t *tuning; /**< Tuning to assign */
} fluid_event_set_tuning_t;
/**
* Tuning replacement event structure.
*/
typedef struct
{
char apply; /**< TRUE if tuning change should be applied in realtime */
fluid_tuning_t *old_tuning; /**< Old tuning pointer to replace */
fluid_tuning_t *new_tuning; /**< New tuning to assign */
} fluid_event_repl_tuning_t;
/**
* Tuning unref event structure.
*/
typedef struct
{
fluid_tuning_t *tuning; /**< Tuning to unref */
int count; /**< Number of times to unref */
} fluid_event_unref_tuning_t;
/**
* Structure for an integer parameter sent to a MIDI channel (bank or SoundFont ID for example).
*/
typedef struct
{
int channel;
int val;
} fluid_event_channel_int_t;
/**
* Event queue element structure.
*/
typedef struct
{
char type; /**< fluid_event_queue_elem */
union
{
fluid_midi_event_t midi; /**< If type == FLUID_EVENT_QUEUE_ELEM_MIDI */
fluid_event_gen_t gen; /**< If type == FLUID_EVENT_QUEUE_ELEM_GEN */
fluid_event_preset_t preset; /**< If type == FLUID_EVENT_QUEUE_ELEM_PRESET */
fluid_event_set_tuning_t set_tuning; /**< If type == FLUID_EVENT_QUEUE_ELEM_SET_TUNING */
fluid_event_repl_tuning_t repl_tuning; /**< If type == FLUID_EVENT_QUEUE_ELEM_REPL_TUNING */
fluid_event_unref_tuning_t unref_tuning; /**< If type == FLUID_EVENT_QUEUE_ELEM_UNREF_TUNING */
double dval; /**< A floating point payload value */
int ival; /**< An integer payload value */
void *pval; /**< A pointer payload value */
};
} fluid_event_queue_elem_t;
typedef struct _fluid_ringbuffer_t fluid_event_queue_t;
static FLUID_INLINE fluid_event_queue_t *
fluid_event_queue_new (int count)
{
return (fluid_event_queue_t *) new_fluid_ringbuffer(count, sizeof(fluid_event_queue_elem_t));
}
static FLUID_INLINE void fluid_event_queue_free (fluid_event_queue_t *queue)
{
delete_fluid_ringbuffer(queue);
}
/**
* Get pointer to next input array element in queue.
* @param queue Lockless queue instance
* @return Pointer to array element in queue to store data to or NULL if queue is full
*
* This function along with fluid_queue_next_inptr() form a queue "push"
* operation and is split into 2 functions to avoid an element copy. Note that
* the returned array element pointer may contain the data of a previous element
* if the queue has wrapped around. This can be used to reclaim pointers to
* allocated memory, etc.
*/
static FLUID_INLINE fluid_event_queue_elem_t *
fluid_event_queue_get_inptr (fluid_event_queue_t *queue)
{
return (fluid_event_queue_elem_t *) fluid_ringbuffer_get_inptr(queue, 0);
}
/**
* Advance the input queue index to complete a "push" operation.
* @param queue Lockless queue instance
*
* This function along with fluid_queue_get_inptr() form a queue "push"
* operation and is split into 2 functions to avoid element copy.
*/
static FLUID_INLINE void
fluid_event_queue_next_inptr (fluid_event_queue_t *queue)
{
fluid_ringbuffer_next_inptr(queue, 1);
}
/**
* Get pointer to next output array element in queue.
* @param queue Lockless queue instance
* @return Pointer to array element data in the queue or NULL if empty, can only
* be used up until fluid_queue_next_outptr() is called.
*
* This function along with fluid_queue_next_outptr() form a queue "pop"
* operation and is split into 2 functions to avoid an element copy.
*/
static FLUID_INLINE fluid_event_queue_elem_t *
fluid_event_queue_get_outptr (fluid_event_queue_t *queue)
{
return (fluid_event_queue_elem_t *) fluid_ringbuffer_get_outptr(queue);
}
/**
* Advance the output queue index to complete a "pop" operation.
* @param queue Lockless queue instance
*
* This function along with fluid_queue_get_outptr() form a queue "pop"
* operation and is split into 2 functions to avoid an element copy.
*/
static FLUID_INLINE void
fluid_event_queue_next_outptr (fluid_event_queue_t *queue)
{
fluid_ringbuffer_next_outptr(queue);
}
#endif /* _FLUID_EVENT_QUEUE_H */

View File

@ -0,0 +1,149 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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 }
};
/**
* Set an array of generators to their default values.
* @param gen Array of generators (should be #GEN_LAST in size).
* @return Always returns 0
*/
int
fluid_gen_set_default_values(fluid_gen_t* gen)
{
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;
}

View File

@ -0,0 +1,44 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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 */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,131 @@
/* 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 02110-1301, 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/.
*/
/*
* Adapted for FluidSynth use by Josh Green <jgreen@users.sourceforge.net>
* September 8, 2009 from glib 2.18.4
*
* - Self contained (no dependencies on glib)
* - changed names to fluid_hashtable_...
*/
#ifndef _FLUID_HASH_H
#define _FLUID_HASH_H
#include "fluidsynth_priv.h"
#include "fluid_list.h"
#include "fluid_sys.h"
/* Extracted from gtypes.h */
typedef void (*fluid_destroy_notify_t)(void *data);
typedef unsigned int (*fluid_hash_func_t)(const void *key);
typedef int (*fluid_equal_func_t)(const void *a, const void *b);
/* End gtypes.h extraction */
typedef int (*fluid_hr_func_t)(void *key, void *value, void *user_data);
typedef struct _fluid_hashtable_iter_t fluid_hashtable_iter_t;
typedef struct _fluid_hashnode_t fluid_hashnode_t;
struct _fluid_hashnode_t
{
void *key;
void *value;
fluid_hashnode_t *next;
unsigned int key_hash;
};
struct _fluid_hashtable_t
{
int size;
int nnodes;
fluid_hashnode_t **nodes;
fluid_hash_func_t hash_func;
fluid_equal_func_t key_equal_func;
volatile int ref_count;
fluid_destroy_notify_t key_destroy_func;
fluid_destroy_notify_t value_destroy_func;
fluid_rec_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
};
struct _fluid_hashtable_iter_t
{
/*< private >*/
void * dummy1;
void * dummy2;
void * dummy3;
int dummy4;
int dummy5; // Bool
void * dummy6;
};
fluid_hashtable_t* new_fluid_hashtable (fluid_hash_func_t hash_func,
fluid_equal_func_t key_equal_func);
fluid_hashtable_t* new_fluid_hashtable_full (fluid_hash_func_t hash_func,
fluid_equal_func_t key_equal_func,
fluid_destroy_notify_t key_destroy_func,
fluid_destroy_notify_t value_destroy_func);
void delete_fluid_hashtable(fluid_hashtable_t *hashtable);
void fluid_hashtable_iter_init (fluid_hashtable_iter_t *iter, fluid_hashtable_t *hashtable);
int fluid_hashtable_iter_next (fluid_hashtable_iter_t *iter, void **key, void **value);
fluid_hashtable_t *fluid_hashtable_iter_get_hash_table (fluid_hashtable_iter_t *iter);
void fluid_hashtable_iter_remove (fluid_hashtable_iter_t *iter);
void fluid_hashtable_iter_steal (fluid_hashtable_iter_t *iter);
fluid_hashtable_t* fluid_hashtable_ref (fluid_hashtable_t *hashtable);
void fluid_hashtable_unref (fluid_hashtable_t *hashtable);
void *fluid_hashtable_lookup (fluid_hashtable_t *hashtable, const void *key);
int fluid_hashtable_lookup_extended (fluid_hashtable_t *hashtable, const void *lookup_key,
void **orig_key, void **value);
void fluid_hashtable_insert (fluid_hashtable_t *hashtable, void *key, void *value);
void fluid_hashtable_replace (fluid_hashtable_t *hashtable, void *key, void *value);
int fluid_hashtable_remove (fluid_hashtable_t *hashtable, const void *key);
int fluid_hashtable_steal (fluid_hashtable_t *hashtable, const void *key);
void fluid_hashtable_remove_all (fluid_hashtable_t *hashtable);
void fluid_hashtable_steal_all (fluid_hashtable_t *hashtable);
unsigned int fluid_hashtable_foreach_steal (fluid_hashtable_t *hashtable,
fluid_hr_func_t func, void *user_data);
void fluid_hashtable_foreach (fluid_hashtable_t *hashtable, fluid_hr_func_t func,
void *user_data);
void *fluid_hashtable_find (fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
void *user_data);
unsigned int fluid_hashtable_size (fluid_hashtable_t *hashtable);
fluid_list_t *fluid_hashtable_get_keys (fluid_hashtable_t *hashtable);
fluid_list_t *fluid_hashtable_get_values (fluid_hashtable_t *hashtable);
int fluid_str_equal (const void *v1, const void *v2);
unsigned int fluid_str_hash (const void *v);
int fluid_direct_equal (const void *v1, const void *v2);
unsigned int fluid_direct_hash (const void *v);
int fluid_int_equal (const void *v1, const void *v2);
unsigned int fluid_int_hash (const void *v);
#endif /* _FLUID_HASH_H */

View File

@ -0,0 +1,301 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_iir_filter.h"
#include "fluid_sys.h"
#include "fluid_conv.h"
/**
* Applies a lowpass filter with variable cutoff frequency and quality factor.
* Also modifies filter state accordingly.
* @param iir_filter Filter parameter
* @param dsp_buf Pointer to the synthesized audio data
* @param count Count of samples in dsp_buf
*/
/*
* Variable description:
* - dsp_a1, dsp_a2, dsp_b0, dsp_b1, dsp_b2: Filter coefficients
*
* 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
*/
void
fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
fluid_real_t *dsp_buf, int count)
{
/* IIR filter sample history */
fluid_real_t dsp_hist1 = iir_filter->hist1;
fluid_real_t dsp_hist2 = iir_filter->hist2;
/* IIR filter coefficients */
fluid_real_t dsp_a1 = iir_filter->a1;
fluid_real_t dsp_a2 = iir_filter->a2;
fluid_real_t dsp_b02 = iir_filter->b02;
fluid_real_t dsp_b1 = iir_filter->b1;
int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count;
fluid_real_t dsp_centernode;
int dsp_i;
/* filter (implement the voice filter according to SoundFont standard) */
/* Check for denormal number (too close to zero). */
if (fabs (dsp_hist1) < 1e-20) dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */
/* Two versions of the filter loop. One, while the filter is
* changing towards its new setting. The other, if the filter
* doesn't change.
*/
if (dsp_filter_coeff_incr_count > 0)
{
fluid_real_t dsp_a1_incr = iir_filter->a1_incr;
fluid_real_t dsp_a2_incr = iir_filter->a2_incr;
fluid_real_t dsp_b02_incr = iir_filter->b02_incr;
fluid_real_t dsp_b1_incr = iir_filter->b1_incr;
/* Increment is added to each filter coefficient filter_coeff_incr_count times. */
for (dsp_i = 0; dsp_i < count; dsp_i++)
{
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
if (dsp_filter_coeff_incr_count-- > 0)
{
fluid_real_t old_b02 = dsp_b02;
dsp_a1 += dsp_a1_incr;
dsp_a2 += dsp_a2_incr;
dsp_b02 += dsp_b02_incr;
dsp_b1 += dsp_b1_incr;
/* Compensate history to avoid the filter going havoc with large frequency changes */
if (iir_filter->compensate_incr && fabs(dsp_b02) > 0.001) {
fluid_real_t compensate = old_b02 / dsp_b02;
dsp_centernode *= compensate;
dsp_hist1 *= compensate;
dsp_hist2 *= compensate;
}
}
} /* for dsp_i */
}
else /* The filter parameters are constant. This is duplicated to save time. */
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
{ /* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
}
}
iir_filter->hist1 = dsp_hist1;
iir_filter->hist2 = dsp_hist2;
iir_filter->a1 = dsp_a1;
iir_filter->a2 = dsp_a2;
iir_filter->b02 = dsp_b02;
iir_filter->b1 = dsp_b1;
iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
fluid_check_fpe ("voice_filter");
}
void
fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter)
{
iir_filter->hist1 = 0;
iir_filter->hist2 = 0;
iir_filter->last_fres = -1.;
iir_filter->filter_startup = 1;
}
void
fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
fluid_real_t fres)
{
iir_filter->fres = fres;
iir_filter->last_fres = -1.;
}
void
fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
fluid_real_t q_dB)
{
/* The 'sound font' Q is defined in dB. The filter needs a linear
q. Convert. */
iir_filter->q_lin = (fluid_real_t) (pow(10.0f, q_dB / 20.0f));
/* SF 2.01 page 59:
*
* The SoundFont specs ask for a gain reduction equal to half the
* height of the resonance peak (Q). For example, for a 10 dB
* resonance peak, the gain is reduced by 5 dB. This is done by
* multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
* by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
* The gain is later factored into the 'b' coefficients
* (numerator of the filter equation). This gain factor depends
* only on Q, so this is the right place to calculate it.
*/
iir_filter->filter_gain = (fluid_real_t) (1.0 / sqrt(iir_filter->q_lin));
/* The synthesis loop will have to recalculate the filter coefficients. */
iir_filter->last_fres = -1.;
}
static inline void
fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter,
int transition_samples,
fluid_real_t output_rate)
{
/*
* Those equations from Robert Bristow-Johnson's `Cookbook
* formulae for audio EQ biquad filter coefficients', obtained
* from Harmony-central.com / Computer / Programming. They are
* the result of the bilinear transform on an analogue filter
* prototype. To quote, `BLT frequency warping has been taken
* into account for both significant frequency relocation and for
* bandwidth readjustment'. */
fluid_real_t omega = (fluid_real_t) (2.0 * M_PI *
(iir_filter->last_fres / ((float) output_rate)));
fluid_real_t sin_coeff = (fluid_real_t) sin(omega);
fluid_real_t cos_coeff = (fluid_real_t) cos(omega);
fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->q_lin);
fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff);
/* Calculate the filter coefficients. All coefficients are
* normalized by a0. Think of `a1' as `a1/a0'.
*
* Here a couple of multiplications are saved by reusing common expressions.
* The original equations should be:
* iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain;
* iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
* iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */
fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
fluid_real_t b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain;
/* both b0 -and- b2 */
fluid_real_t b02_temp = b1_temp * 0.5f;
iir_filter->compensate_incr = 0;
if (iir_filter->filter_startup || (transition_samples == 0))
{
/* The filter is calculated, because the voice was started up.
* In this case set the filter coefficients without delay.
*/
iir_filter->a1 = a1_temp;
iir_filter->a2 = a2_temp;
iir_filter->b02 = b02_temp;
iir_filter->b1 = b1_temp;
iir_filter->filter_coeff_incr_count = 0;
iir_filter->filter_startup = 0;
// printf("Setting initial filter coefficients.\n");
}
else
{
/* The filter frequency is changed. Calculate an increment
* factor, so that the new setting is reached after one buffer
* length. x_incr is added to the current value FLUID_BUFSIZE
* times. The length is arbitrarily chosen. Longer than one
* buffer will sacrifice some performance, though. Note: If
* the filter is still too 'grainy', then increase this number
* at will.
*/
iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples;
iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples;
iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples;
iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples;
if (fabs(iir_filter->b02) > 0.0001) {
fluid_real_t quota = b02_temp / iir_filter->b02;
iir_filter->compensate_incr = quota < 0.5 || quota > 2;
}
/* Have to add the increments filter_coeff_incr_count times. */
iir_filter->filter_coeff_incr_count = transition_samples;
}
fluid_check_fpe ("voice_write filter calculation");
}
void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
fluid_real_t output_rate,
fluid_real_t fres_mod)
{
fluid_real_t fres;
/* calculate the frequency of the resonant filter in Hz */
fres = fluid_ct2hz(iir_filter->fres + fres_mod);
/* FIXME - Still potential for a click during turn on, can we interpolate
between 20khz cutoff and 0 Q? */
/* I removed the optimization of turning the filter off when the
* resonance frequence is above the maximum frequency. Instead, the
* filter frequency is set to a maximum of 0.45 times the sampling
* rate. For a 44100 kHz sampling rate, this amounts to 19845
* Hz. The reason is that there were problems with anti-aliasing when the
* synthesizer was run at lower sampling rates. Thanks to Stephan
* Tassart for pointing me to this bug. By turning the filter on and
* clipping the maximum filter frequency at 0.45*srate, the filter
* is used as an anti-aliasing filter. */
if (fres > 0.45f * output_rate)
fres = 0.45f * output_rate;
else if (fres < 5)
fres = 5;
/* if filter enabled and there is a significant frequency change.. */
if ((abs (fres - iir_filter->last_fres) > 0.01))
{
/* The filter coefficients have to be recalculated (filter
* parameters have changed). Recalculation for various reasons is
* forced by setting last_fres to -1. The flag filter_startup
* indicates, that the DSP loop runs for the first time, in this
* case, the filter is set directly, instead of smoothly fading
* between old and new settings. */
iir_filter->last_fres = fres;
fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE,
output_rate);
}
fluid_check_fpe ("voice_write DSP coefficients");
}

View File

@ -0,0 +1,75 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_IIR_FILTER_H
#define _FLUID_IIR_FILTER_H
#include "fluidsynth_priv.h"
typedef struct _fluid_iir_filter_t fluid_iir_filter_t;
void fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
fluid_real_t *dsp_buf, int dsp_buf_count);
void fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter);
void fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
fluid_real_t q_dB);
void fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
fluid_real_t fres);
void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
fluid_real_t output_rate,
fluid_real_t fres_mod);
/* We can't do information hiding here, as fluid_voice_t includes the struct
without a pointer. */
struct _fluid_iir_filter_t
{
/* 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;
int compensate_incr; /* Flag: If set, must compensate history */
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. */
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 */
};
#endif

View File

@ -0,0 +1,13 @@
#include "fluid_lfo.h"
void
fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t increment)
{
lfo->increment = increment;
}
void
fluid_lfo_set_delay(fluid_lfo_t* lfo, unsigned int delay)
{
lfo->delay = delay;
}

View File

@ -0,0 +1,72 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_LFO_H
#define _FLUID_LFO_H
#include "fluidsynth_priv.h"
typedef struct _fluid_lfo_t fluid_lfo_t;
struct _fluid_lfo_t {
fluid_real_t val; /* the current value of the LFO */
unsigned int delay; /* the delay of the lfo in samples */
fluid_real_t increment; /* the lfo frequency is converted to a per-buffer increment */
};
static inline void
fluid_lfo_reset(fluid_lfo_t* lfo)
{
lfo->val = 0.0f;
}
// These two cannot be inlined since they're used by event_dispatch
void fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t increment);
void fluid_lfo_set_delay(fluid_lfo_t* lfo, unsigned int delay);
static inline fluid_real_t
fluid_lfo_get_val(fluid_lfo_t* lfo)
{
return lfo->val;
}
static inline void
fluid_lfo_calc(fluid_lfo_t* lfo, unsigned int cur_delay)
{
if (cur_delay < lfo->delay)
return;
lfo->val += lfo->increment;
if (lfo->val > (fluid_real_t) 1.0)
{
lfo->increment = -lfo->increment;
lfo->val = (fluid_real_t) 2.0 - lfo->val;
}
else if (lfo->val < (fluid_real_t) -1.0)
{
lfo->increment = -lfo->increment;
lfo->val = (fluid_real_t) -2.0 - lfo->val;
}
}
#endif

View File

@ -0,0 +1,268 @@
/* 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 02110-1301, 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;
}
}
/* Compare function to sort strings alphabetically,
* for use with fluid_list_sort(). */
int
fluid_list_str_compare_func (void *a, void *b)
{
if (a && b) return FLUID_STRCMP ((char *)a, (char *)b);
if (!a && !b) return 0;
if (a) return -1;
return 1;
}

View File

@ -0,0 +1,62 @@
/* 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 02110-1301, 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)
int fluid_list_str_compare_func (void *a, void *b);
#endif /* _FLUID_LIST_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,382 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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);
/***************************************************************
*
* 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
};
/* General MIDI RPN event numbers (LSB, MSB = 0) */
enum midi_rpn_event {
RPN_PITCH_BEND_RANGE = 0x00,
RPN_CHANNEL_FINE_TUNE = 0x01,
RPN_CHANNEL_COARSE_TUNE = 0x02,
RPN_TUNING_PROGRAM_CHANGE = 0x03,
RPN_TUNING_BANK_SELECT = 0x04,
RPN_MODULATION_DEPTH_RANGE = 0x05
};
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
};
/* MIDI SYSEX useful manufacturer values */
enum midi_sysex_manuf {
MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
};
#define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */
/* SYSEX sub-ID #1 which follows device ID */
#define MIDI_SYSEX_MIDI_TUNING_ID 0x08 /**< Sysex sub-ID #1 for MIDI tuning messages */
#define MIDI_SYSEX_GM_ID 0x09 /**< Sysex sub-ID #1 for General MIDI messages */
/**
* SYSEX tuning message IDs.
*/
enum midi_sysex_tuning_msg_id {
MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
};
/* General MIDI sub-ID #2 */
#define MIDI_SYSEX_GM_ON 0x01 /**< Enable GM mode */
#define MIDI_SYSEX_GM_OFF 0x02 /**< Disable GM mode */
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; /* Link to next event */
void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
unsigned int param1; /* First parameter */
unsigned int param2; /* Second parameter */
unsigned char type; /* MIDI event type */
unsigned char channel; /* MIDI channel */
};
/*
* 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_playlist_item
* Used as the `data' elements of the fluid_player.playlist.
* Represents either a filename or a pre-loaded memory buffer.
* Exactly one of `filename' and `buffer' is non-NULL.
*/
typedef struct
{
char* filename; /** Name of file (owned); NULL if data pre-loaded */
void* buffer; /** The MIDI file data (owned); NULL if filename */
size_t buffer_len; /** Number of bytes in buffer; 0 if filename */
} fluid_playlist_item;
/*
* fluid_player
*/
struct _fluid_player_t {
int status;
int ntracks;
fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
fluid_synth_t* synth;
fluid_timer_t* system_timer;
fluid_sample_timer_t* sample_timer;
int loop; /* -1 = loop infinitely, otherwise times left to loop the playlist */
fluid_list_t* playlist; /* List of fluid_playlist_item* objects */
fluid_list_t* currentfile; /* points to an item in files, or NULL if not playing */
char send_program_change; /* should we ignore the program changes? */
char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */
char reset_synth_between_songs; /* 1 if system reset should be sent to the synth between songs. */
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;
handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */
void* playback_userdata; /* pointer to user-defined data passed to playback_callback function */
};
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, fluid_playlist_item *item);
void fluid_player_settings(fluid_settings_t* settings);
/*
* fluid_midi_file
*/
typedef struct {
const char* buffer; /* Entire contents of MIDI file (borrowed) */
int buf_len; /* Length of buffer, in bytes */
int buf_pos; /* Current read position in contents buffer */
int eof; /* The "end of file" condition */
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;
int dtime;
} fluid_midi_file;
fluid_midi_file* new_fluid_midi_file(const char* buffer, size_t length);
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_eof(fluid_midi_file* mf);
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);
#define FLUID_MIDI_PARSER_MAX_DATA_SIZE 1024 /**< Maximum size of MIDI parameters/data (largest is SYSEX data) */
/*
* 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 char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */
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);
#endif /* _FLUID_MIDI_H */

View File

@ -0,0 +1,488 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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;
}
/**
* Set a modulator's primary source controller and flags.
* @param mod Modulator
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
* @param flags Flags determining mapping function and whether the source
* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
* (#FLUID_MOD_CC), see #fluid_mod_flags.
*/
void
fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags)
{
mod->src1 = src;
mod->flags1 = flags;
}
/**
* Set a modulator's secondary source controller and flags.
* @param mod Modulator
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
* @param flags Flags determining mapping function and whether the source
* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
* (#FLUID_MOD_CC), see #fluid_mod_flags.
*/
void
fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags)
{
mod->src2 = src;
mod->flags2 = flags;
}
/**
* Set the destination effect of a modulator.
* @param mod Modulator
* @param dest Destination generator (#fluid_gen_type)
*/
void
fluid_mod_set_dest(fluid_mod_t* mod, int dest)
{
mod->dest = dest;
}
/**
* Set the scale amount of a modulator.
* @param mod Modulator
* @param amount Scale amount to assign
*/
void
fluid_mod_set_amount(fluid_mod_t* mod, double amount)
{
mod->amount = (double) amount;
}
/**
* Get the primary source value from a modulator.
* @param mod Modulator
* @return The primary source value (#fluid_mod_src or a MIDI CC controller value).
*/
int
fluid_mod_get_source1(fluid_mod_t* mod)
{
return mod->src1;
}
/**
* Get primary source flags from a modulator.
* @param mod Modulator
* @return The primary source flags (#fluid_mod_flags).
*/
int
fluid_mod_get_flags1(fluid_mod_t* mod)
{
return mod->flags1;
}
/**
* Get the secondary source value from a modulator.
* @param mod Modulator
* @return The secondary source value (#fluid_mod_src or a MIDI CC controller value).
*/
int
fluid_mod_get_source2(fluid_mod_t* mod)
{
return mod->src2;
}
/**
* Get secondary source flags from a modulator.
* @param mod Modulator
* @return The secondary source flags (#fluid_mod_flags).
*/
int
fluid_mod_get_flags2(fluid_mod_t* mod)
{
return mod->flags2;
}
/**
* Get destination effect from a modulator.
* @param mod Modulator
* @return Destination generator (#fluid_gen_type)
*/
int
fluid_mod_get_dest(fluid_mod_t* mod)
{
return mod->dest;
}
/**
* Get the scale amount from a modulator.
* @param mod Modulator
* @return Scale amount
*/
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)) {
// S. Christian Collins' mod, to stop forcing velocity based filtering
/*
if (voice->vel < 64){
return (fluid_real_t) mod->amount / 2.0;
} else {
return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
}
*/
return 0; // (fluid_real_t) mod->amount / 2.0;
}
// end S. Christian Collins' mod
/* 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 = fluid_channel_get_key_pressure (chan);
break;
case FLUID_MOD_CHANNELPRESSURE:
v1 = fluid_channel_get_channel_pressure (chan);
break;
case FLUID_MOD_PITCHWHEEL:
v1 = fluid_channel_get_pitch_bend (chan);
range1 = 0x4000;
break;
case FLUID_MOD_PITCHWHEELSENS:
v1 = fluid_channel_get_pitch_wheel_sensitivity (chan);
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 = fluid_channel_get_key_pressure (chan);
break;
case FLUID_MOD_CHANNELPRESSURE:
v2 = fluid_channel_get_channel_pressure (chan);
break;
case FLUID_MOD_PITCHWHEEL:
v2 = fluid_channel_get_pitch_bend (chan);
break;
case FLUID_MOD_PITCHWHEELSENS:
v2 = fluid_channel_get_pitch_wheel_sensitivity (chan);
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;
}
/**
* Create a new uninitialized modulator structure.
* @return New allocated modulator or NULL if out of memory
*/
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;
}
/**
* Free a modulator structure.
* @param mod Modulator to free
*/
void
fluid_mod_delete (fluid_mod_t *mod)
{
FLUID_FREE(mod);
}
/**
* Checks if two modulators are identical in sources, flags and destination.
* @param mod1 First modulator
* @param mod2 Second modulator
* @return TRUE if identical, FALSE otherwise
*
* 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)
{
return mod1->dest == mod2->dest
&& mod1->src1 == mod2->src1
&& mod1->src2 == mod2->src2
&& mod1->flags1 == mod2->flags1
&& mod1->flags2 == mod2->flags2;
}
/* 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);
};

View File

@ -0,0 +1,40 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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 */

View File

@ -0,0 +1,117 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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.
*/
typedef unsigned long long fluid_phase_t;
/* Purpose:
* Set a to b.
* a: fluid_phase_t
* b: fluid_phase_t
*/
#define fluid_phase_set(a,b) a=b;
#define fluid_phase_set_int(a, b) ((a) = ((unsigned long long)(b)) << 32)
/* Purpose:
* Sets the phase a to a phase increment given in b.
* For example, assume b is 0.9. After setting a to it, adding a to
* the playing pointer will advance it by 0.9 samples. */
#define fluid_phase_set_float(a, b) \
(a) = (((unsigned long long)(b)) << 32) \
| (uint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX)
/* create a fluid_phase_t from an index and a fraction value */
#define fluid_phase_from_index_fract(index, fract) \
((((unsigned long long)(index)) << 32) + (fract))
/* Purpose:
* Return the index and the fractional part, respectively. */
#define fluid_phase_index(_x) \
((unsigned int)((_x) >> 32))
#define fluid_phase_fract(_x) \
((uint32)((_x) & 0xFFFFFFFF))
/* Get the phase index with fractional rounding */
#define fluid_phase_index_round(_x) \
((unsigned int)(((_x) + 0x80000000) >> 32))
/* Purpose:
* Takes the fractional part of the argument phase and
* 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) \
((unsigned int)(fluid_phase_fract(_x) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT)
#define fluid_phase_double(_x) \
((double)(fluid_phase_index(_x)) + ((double)fluid_phase_fract(_x) / FLUID_FRACT_MAX))
/* Purpose:
* Advance a by a step of b (both are fluid_phase_t).
*/
#define fluid_phase_incr(a, b) a += b
/* Purpose:
* Subtract b from a (both are fluid_phase_t).
*/
#define fluid_phase_decr(a, b) a -= b
/* Purpose:
* Subtract b samples from a.
*/
#define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32)
/* Purpose:
* Creates the expression a.index++. */
#define fluid_phase_index_plusplus(a) (((a) += 0x100000000LL)
#endif /* _FLUID_PHASE_H */

View File

@ -0,0 +1,544 @@
/*
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_init(fluid_allpass* allpass);
void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
static void
fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
{
allpass->bufidx = 0;
allpass->buffer = FLUID_ARRAY(fluid_real_t,size);
allpass->bufsize = size;
}
static void
fluid_allpass_release(fluid_allpass* allpass)
{
FLUID_FREE(allpass->buffer);
}
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, int size);
void fluid_comb_release(fluid_comb* comb);
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, int size)
{
comb->filterstore = 0;
comb->bufidx = 0;
comb->buffer = FLUID_ARRAY(fluid_real_t,size);
comb->bufsize = size;
}
void
fluid_comb_release(fluid_comb* comb)
{
FLUID_FREE(comb->buffer);
}
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 1.0f
#define scaleroom 0.28f
#define offsetroom 0.7f
#define initialroom 0.5f
#define initialdamp 0.2f
#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];
};
static void fluid_revmodel_update(fluid_revmodel_t* rev);
static void fluid_revmodel_init(fluid_revmodel_t* rev);
void fluid_set_revmodel_buffers(fluid_revmodel_t* rev, fluid_real_t sample_rate);
fluid_revmodel_t*
new_fluid_revmodel(fluid_real_t sample_rate)
{
fluid_revmodel_t* rev;
rev = FLUID_NEW(fluid_revmodel_t);
if (rev == NULL) {
return NULL;
}
fluid_set_revmodel_buffers(rev, sample_rate);
/* 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);
rev->gain = fixedgain;
fluid_revmodel_set(rev,FLUID_REVMODEL_SET_ALL,initialroom,initialdamp,initialwidth,initialwet);
return rev;
}
void
delete_fluid_revmodel(fluid_revmodel_t* rev)
{
int i;
for (i = 0; i < numcombs;i++) {
fluid_comb_release(&rev->combL[i]);
fluid_comb_release(&rev->combR[i]);
}
for (i = 0; i < numallpasses; i++) {
fluid_allpass_release(&rev->allpassL[i]);
fluid_allpass_release(&rev->allpassR[i]);
}
FLUID_FREE(rev);
}
void
fluid_set_revmodel_buffers(fluid_revmodel_t* rev, fluid_real_t sample_rate) {
float srfactor = sample_rate/44100.0f;
fluid_comb_setbuffer(&rev->combL[0], combtuningL1*srfactor);
fluid_comb_setbuffer(&rev->combR[0], combtuningR1*srfactor);
fluid_comb_setbuffer(&rev->combL[1], combtuningL2*srfactor);
fluid_comb_setbuffer(&rev->combR[1], combtuningR2*srfactor);
fluid_comb_setbuffer(&rev->combL[2], combtuningL3*srfactor);
fluid_comb_setbuffer(&rev->combR[2], combtuningR3*srfactor);
fluid_comb_setbuffer(&rev->combL[3], combtuningL4*srfactor);
fluid_comb_setbuffer(&rev->combR[3], combtuningR4*srfactor);
fluid_comb_setbuffer(&rev->combL[4], combtuningL5*srfactor);
fluid_comb_setbuffer(&rev->combR[4], combtuningR5*srfactor);
fluid_comb_setbuffer(&rev->combL[5], combtuningL6*srfactor);
fluid_comb_setbuffer(&rev->combR[5], combtuningR6*srfactor);
fluid_comb_setbuffer(&rev->combL[6], combtuningL7*srfactor);
fluid_comb_setbuffer(&rev->combR[6], combtuningR7*srfactor);
fluid_comb_setbuffer(&rev->combL[7], combtuningL8*srfactor);
fluid_comb_setbuffer(&rev->combR[7], combtuningR8*srfactor);
fluid_allpass_setbuffer(&rev->allpassL[0], allpasstuningL1*srfactor);
fluid_allpass_setbuffer(&rev->allpassR[0], allpasstuningR1*srfactor);
fluid_allpass_setbuffer(&rev->allpassL[1], allpasstuningL2*srfactor);
fluid_allpass_setbuffer(&rev->allpassR[1], allpasstuningR2*srfactor);
fluid_allpass_setbuffer(&rev->allpassL[2], allpasstuningL3*srfactor);
fluid_allpass_setbuffer(&rev->allpassR[2], allpasstuningR3*srfactor);
fluid_allpass_setbuffer(&rev->allpassL[3], allpasstuningL4*srfactor);
fluid_allpass_setbuffer(&rev->allpassR[3], allpasstuningR4*srfactor);
/* Clear all buffers */
fluid_revmodel_init(rev);
}
static 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.0f * 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.0f * 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;
}
}
static void
fluid_revmodel_update(fluid_revmodel_t* rev)
{
/* Recalculate internal values after parameter change */
int i;
rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
rev->wet2 = rev->wet * ((1.0f - rev->width) / 2.0f);
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);
}
}
/**
* Set one or more reverb parameters.
* @param rev Reverb instance
* @param set One or more flags from #fluid_revmodel_set_t indicating what
* parameters to set (#FLUID_REVMODEL_SET_ALL to set all parameters)
* @param roomsize Reverb room size
* @param damping Reverb damping
* @param width Reverb width
* @param level Reverb level
*/
void
fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
float damping, float width, float level)
{
if (set & FLUID_REVMODEL_SET_ROOMSIZE)
rev->roomsize = (roomsize * scaleroom) + offsetroom;
if (set & FLUID_REVMODEL_SET_DAMPING)
rev->damp = damping * scaledamp;
if (set & FLUID_REVMODEL_SET_WIDTH)
rev->width = width;
if (set & FLUID_REVMODEL_SET_LEVEL)
{
fluid_clip(level, 0.0f, 1.0f);
rev->wet = level * scalewet;
}
fluid_revmodel_update (rev);
}
void
fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, fluid_real_t sample_rate) {
int i;
for (i = 0; i < numcombs;i++) {
fluid_comb_release(&rev->combL[i]);
fluid_comb_release(&rev->combR[i]);
}
for (i = 0; i < numallpasses; i++) {
fluid_allpass_release(&rev->allpassL[i]);
fluid_allpass_release(&rev->allpassR[i]);
}
fluid_set_revmodel_buffers(rev, sample_rate);
}

View File

@ -0,0 +1,73 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_REV_H
#define _FLUID_REV_H
#include "fluidsynth_priv.h"
typedef struct _fluid_revmodel_t fluid_revmodel_t;
/** Flags for fluid_revmodel_set() */
typedef enum
{
FLUID_REVMODEL_SET_ROOMSIZE = 1 << 0,
FLUID_REVMODEL_SET_DAMPING = 1 << 1,
FLUID_REVMODEL_SET_WIDTH = 1 << 2,
FLUID_REVMODEL_SET_LEVEL = 1 << 3
} fluid_revmodel_set_t;
/** Value for fluid_revmodel_set() which sets all reverb parameters. */
#define FLUID_REVMODEL_SET_ALL 0x0F
/*
* 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;
/*
* reverb
*/
fluid_revmodel_t* new_fluid_revmodel(fluid_real_t sample_rate);
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_set(fluid_revmodel_t* rev, int set, float roomsize,
float damping, float width, float level);
void fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, fluid_real_t sample_rate);
#endif /* _FLUID_REV_H */

View File

@ -0,0 +1,89 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
/*
* Josh Green <josh@resonance.org>
* 2009-05-28
*/
#include "fluid_ringbuffer.h"
#include "fluidsynth_priv.h"
/**
* Create a lock free queue with a fixed maximum count and size of elements.
* @param count Count of elements in queue (fixed max number of queued elements)
* @return New lock free queue or NULL if out of memory (error message logged)
*
* Lockless FIFO queues don't use any locking mechanisms and can therefore be
* advantageous in certain situations, such as passing data between a lower
* priority thread and a higher "real time" thread, without potential lock
* contention which could stall the high priority thread. Note that there may
* only be one producer thread and one consumer thread.
*/
fluid_ringbuffer_t *
new_fluid_ringbuffer (int count, int elementsize)
{
fluid_ringbuffer_t *queue;
fluid_return_val_if_fail (count > 0, NULL);
queue = FLUID_NEW (fluid_ringbuffer_t);
if (!queue)
{
FLUID_LOG (FLUID_ERR, "Out of memory");
return NULL;
}
queue->array = FLUID_MALLOC (elementsize * count);
if (!queue->array)
{
FLUID_FREE (queue);
FLUID_LOG (FLUID_ERR, "Out of memory");
return NULL;
}
/* Clear array, in case dynamic pointer reclaiming is being done */
FLUID_MEMSET (queue->array, 0, elementsize * count);
queue->totalcount = count;
queue->elementsize = elementsize;
queue->count = 0;
queue->in = 0;
queue->out = 0;
return (queue);
}
/**
* Free an event queue.
* @param queue Lockless queue instance
*
* Care must be taken when freeing a queue, to ensure that the consumer and
* producer threads will no longer access it.
*/
void
delete_fluid_ringbuffer (fluid_ringbuffer_t *queue)
{
FLUID_FREE (queue->array);
FLUID_FREE (queue);
}

View File

@ -0,0 +1,128 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_RINGBUFFER_H
#define _FLUID_RINGBUFFER_H
#include "fluid_sys.h"
/**
* Lockless event queue instance.
*/
struct _fluid_ringbuffer_t
{
char *array; /**< Queue array of arbitrary size elements */
int totalcount; /**< Total count of elements in array */
int count; /**< Current count of elements */
int in; /**< Index in queue to store next pushed element */
int out; /**< Index in queue of next popped element */
int elementsize; /**< Size of each element */
void* userdata;
};
typedef struct _fluid_ringbuffer_t fluid_ringbuffer_t;
fluid_ringbuffer_t *new_fluid_ringbuffer (int count, int elementsize);
void delete_fluid_ringbuffer (fluid_ringbuffer_t *queue);
/**
* Get pointer to next input array element in queue.
* @param queue Lockless queue instance
* @param count Normally zero, or more if you need to push several items at once
* @return Pointer to array element in queue to store data to or NULL if queue is full
*
* This function along with fluid_ringbuffer_next_inptr() form a queue "push"
* operation and is split into 2 functions to avoid an element copy. Note that
* the returned array element pointer may contain the data of a previous element
* if the queue has wrapped around. This can be used to reclaim pointers to
* allocated memory, etc.
*/
static FLUID_INLINE void*
fluid_ringbuffer_get_inptr (fluid_ringbuffer_t *queue, int offset)
{
return fluid_atomic_int_get (&queue->count) + offset >= queue->totalcount ? NULL
: queue->array + queue->elementsize * ((queue->in + offset) % queue->totalcount);
}
/**
* Advance the input queue index to complete a "push" operation.
* @param queue Lockless queue instance
* @param count Normally one, or more if you need to push several items at once
*
* This function along with fluid_ringbuffer_get_inptr() form a queue "push"
* operation and is split into 2 functions to avoid element copy.
*/
static FLUID_INLINE void
fluid_ringbuffer_next_inptr (fluid_ringbuffer_t *queue, int count)
{
fluid_atomic_int_add (&queue->count, count);
queue->in += count;
if (queue->in >= queue->totalcount)
queue->in -= queue->totalcount;
}
/**
* Get amount of items currently in queue
* @param queue Lockless queue instance
* @return amount of items currently in queue
*/
static FLUID_INLINE int
fluid_ringbuffer_get_count (fluid_ringbuffer_t *queue)
{
return fluid_atomic_int_get (&queue->count);
}
/**
* Get pointer to next output array element in queue.
* @param queue Lockless queue instance
* @return Pointer to array element data in the queue or NULL if empty, can only
* be used up until fluid_ringbuffer_next_outptr() is called.
*
* This function along with fluid_ringbuffer_next_outptr() form a queue "pop"
* operation and is split into 2 functions to avoid an element copy.
*/
static FLUID_INLINE void*
fluid_ringbuffer_get_outptr (fluid_ringbuffer_t *queue)
{
return fluid_ringbuffer_get_count(queue) == 0 ? NULL
: queue->array + queue->elementsize * queue->out;
}
/**
* Advance the output queue index to complete a "pop" operation.
* @param queue Lockless queue instance
*
* This function along with fluid_ringbuffer_get_outptr() form a queue "pop"
* operation and is split into 2 functions to avoid an element copy.
*/
static FLUID_INLINE void
fluid_ringbuffer_next_outptr (fluid_ringbuffer_t *queue)
{
fluid_atomic_int_add (&queue->count, -1);
if (++queue->out == queue->totalcount)
queue->out = 0;
}
#endif /* _FLUID_ringbuffer_H */

View File

@ -0,0 +1,664 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_rvoice.h"
#include "fluid_conv.h"
#include "fluid_sys.h"
/**
* @return -1 if voice has finished, 0 if it's currently quiet, 1 otherwise
*/
static inline int
fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
{
fluid_real_t target_amp; /* target amplitude */
if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVDELAY)
return -1; /* The volume amplitude is in hold phase. No sound is produced. */
if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
{
/* the envelope is in the attack section: ramp linearly to max value.
* A positive modlfo_to_vol should increase volume (negative attenuation).
*/
target_amp = fluid_atten2amp (voice->dsp.attenuation)
* fluid_cb2amp (fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
* fluid_adsr_env_get_val(&voice->envlfo.volenv);
}
else
{
fluid_real_t amplitude_that_reaches_noise_floor;
fluid_real_t amp_max;
target_amp = fluid_atten2amp (voice->dsp.attenuation)
* fluid_cb2amp (960.0f * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
+ fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);
/* We turn off a voice, if the volume has dropped low enough. */
/* A voice can be turned off, when an estimate for the volume
* (upper bound) falls below that volume, that will drop the
* sample below the noise floor.
*/
/* If the loop amplitude is known, we can use it if the voice loop is within
* the sample loop
*/
/* Is the playing pointer already in the loop? */
if (voice->dsp.has_looped)
amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_loop;
else
amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
/* voice->attenuation_min is a lower boundary for the attenuation
* now and in the future (possibly 0 in the worst case). Now the
* amplitude of sample and volenv cannot exceed amp_max (since
* volenv_val can only drop):
*/
amp_max = fluid_atten2amp (voice->dsp.min_attenuation_cB) *
fluid_adsr_env_get_val(&voice->envlfo.volenv);
/* And if amp_max is already smaller than the known amplitude,
* which will attenuate the sample below the noise floor, then we
* can safely turn off the voice. Duh. */
if (amp_max < amplitude_that_reaches_noise_floor)
{
return 0;
}
}
/* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
voice->dsp.amp_incr = (target_amp - voice->dsp.amp) / FLUID_BUFSIZE;
fluid_check_fpe ("voice_write amplitude calculation");
/* no volume and not changing? - No need to process */
if ((voice->dsp.amp == 0.0f) && (voice->dsp.amp_incr == 0.0f))
return -1;
return 1;
}
/* these should be the absolute minimum that FluidSynth can deal with */
#define FLUID_MIN_LOOP_SIZE 2
#define FLUID_MIN_LOOP_PAD 0
#define FLUID_SAMPLESANITY_CHECK (1 << 0)
#define FLUID_SAMPLESANITY_STARTUP (1 << 1)
/* Purpose:
*
* Make sure, that sample start / end point and loop points are in
* proper order. When starting up, calculate the initial phase.
* TODO: Investigate whether this can be moved from rvoice to voice.
*/
static void
fluid_rvoice_check_sample_sanity(fluid_rvoice_t* voice)
{
int min_index_nonloop=(int) voice->dsp.sample->start;
int max_index_nonloop=(int) voice->dsp.sample->end;
/* make sure we have enough samples surrounding the loop */
int min_index_loop=(int) voice->dsp.sample->start + FLUID_MIN_LOOP_PAD;
int max_index_loop=(int) voice->dsp.sample->end - FLUID_MIN_LOOP_PAD + 1; /* 'end' is last valid sample, loopend can be + 1 */
fluid_check_fpe("voice_check_sample_sanity start");
if (!voice->dsp.check_sample_sanity_flag){
return;
}
#if 0
printf("Sample from %i to %i\n",voice->dsp.sample->start, voice->dsp.sample->end);
printf("Sample loop from %i %i\n",voice->dsp.sample->loopstart, voice->dsp.sample->loopend);
printf("Playback from %i to %i\n", voice->dsp.start, voice->dsp.end);
printf("Playback loop from %i to %i\n",voice->dsp.loopstart, voice->dsp.loopend);
#endif
/* Keep the start point within the sample data */
if (voice->dsp.start < min_index_nonloop){
voice->dsp.start = min_index_nonloop;
} else if (voice->dsp.start > max_index_nonloop){
voice->dsp.start = max_index_nonloop;
}
/* Keep the end point within the sample data */
if (voice->dsp.end < min_index_nonloop){
voice->dsp.end = min_index_nonloop;
} else if (voice->dsp.end > max_index_nonloop){
voice->dsp.end = max_index_nonloop;
}
/* Keep start and end point in the right order */
if (voice->dsp.start > voice->dsp.end){
int temp = voice->dsp.start;
voice->dsp.start = voice->dsp.end;
voice->dsp.end = temp;
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
}
/* Zero length? */
if (voice->dsp.start == voice->dsp.end){
fluid_rvoice_voiceoff(voice);
return;
}
if ((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) {
/* Keep the loop start point within the sample data */
if (voice->dsp.loopstart < min_index_loop){
voice->dsp.loopstart = min_index_loop;
} else if (voice->dsp.loopstart > max_index_loop){
voice->dsp.loopstart = max_index_loop;
}
/* Keep the loop end point within the sample data */
if (voice->dsp.loopend < min_index_loop){
voice->dsp.loopend = min_index_loop;
} else if (voice->dsp.loopend > max_index_loop){
voice->dsp.loopend = max_index_loop;
}
/* Keep loop start and end point in the right order */
if (voice->dsp.loopstart > voice->dsp.loopend){
int temp = voice->dsp.loopstart;
voice->dsp.loopstart = voice->dsp.loopend;
voice->dsp.loopend = temp;
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
}
/* Loop too short? Then don't loop. */
if (voice->dsp.loopend < voice->dsp.loopstart + FLUID_MIN_LOOP_SIZE){
voice->dsp.samplemode = FLUID_UNLOOPED;
}
/* The loop points may have changed. Obtain a new estimate for the loop volume. */
/* Is the voice loop within the sample loop? */
if ((int)voice->dsp.loopstart >= (int)voice->dsp.sample->loopstart
&& (int)voice->dsp.loopend <= (int)voice->dsp.sample->loopend){
/* Is there a valid peak amplitude available for the loop, and can we use it? */
if (voice->dsp.sample->amplitude_that_reaches_noise_floor_is_valid && voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE){
voice->dsp.amplitude_that_reaches_noise_floor_loop=voice->dsp.sample->amplitude_that_reaches_noise_floor / voice->dsp.synth_gain;
} else {
/* Worst case */
voice->dsp.amplitude_that_reaches_noise_floor_loop=voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
};
};
} /* if sample mode is looped */
/* Run startup specific code (only once, when the voice is started) */
if (voice->dsp.check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP){
if (max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE){
if ((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)){
voice->dsp.samplemode = FLUID_UNLOOPED;
}
}
/* Set the initial phase of the voice (using the result from the
start offset modulators). */
fluid_phase_set_int(voice->dsp.phase, voice->dsp.start);
} /* if startup */
/* Is this voice run in loop mode, or does it run straight to the
end of the waveform data? */
if (((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) &&
(fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE))
|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) {
/* Yes, it will loop as soon as it reaches the loop point. In
* this case we must prevent, that the playback pointer (phase)
* happens to end up beyond the 2nd loop point, because the
* point has moved. The DSP algorithm is unable to cope with
* that situation. So if the phase is beyond the 2nd loop
* point, set it to the start of the loop. No way to avoid some
* noise here. Note: If the sample pointer ends up -before the
* first loop point- instead, then the DSP loop will just play
* the sample, enter the loop and proceed as expected => no
* actions required.
*/
int index_in_sample = fluid_phase_index(voice->dsp.phase);
if (index_in_sample >= voice->dsp.loopend){
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
fluid_phase_set_int(voice->dsp.phase, voice->dsp.loopstart);
}
}
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->dsp.start, voice->dsp.end, voice->dsp.loopstart, voice->dsp.loopend); */
/* Sample sanity has been assured. Don't check again, until some
sample parameter is changed by modulation. */
voice->dsp.check_sample_sanity_flag=0;
#if 0
printf("Sane? playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend);
#endif
fluid_check_fpe("voice_check_sample_sanity");
}
/**
* Synthesize a voice to a buffer.
*
* @param voice rvoice to synthesize
* @param dsp_buf Audio buffer to synthesize to (#FLUID_BUFSIZE in length)
* @return Count of samples written to dsp_buf. (-1 means voice is currently
* quiet, 0 .. #FLUID_BUFSIZE-1 means voice finished.)
*
* Panning, reverb and chorus are processed separately. The dsp interpolation
* routine is in (fluid_dsp_float.c).
*/
int
fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
{
int ticks = voice->envlfo.ticks;
int count;
/******************* sample sanity check **********/
if (!voice->dsp.sample)
return 0;
if (voice->dsp.check_sample_sanity_flag)
fluid_rvoice_check_sample_sanity(voice);
/******************* noteoff check ****************/
if (voice->envlfo.noteoff_ticks != 0 &&
voice->envlfo.ticks >= voice->envlfo.noteoff_ticks) {
fluid_rvoice_noteoff(voice, 0);
}
voice->envlfo.ticks += FLUID_BUFSIZE;
/******************* vol env **********************/
fluid_adsr_env_calc(&voice->envlfo.volenv, 1);
fluid_check_fpe ("voice_write vol env");
if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED)
return 0;
/******************* mod env **********************/
fluid_adsr_env_calc(&voice->envlfo.modenv, 0);
fluid_check_fpe ("voice_write mod env");
/******************* lfo **********************/
fluid_lfo_calc(&voice->envlfo.modlfo, ticks);
fluid_check_fpe ("voice_write mod LFO");
fluid_lfo_calc(&voice->envlfo.viblfo, ticks);
fluid_check_fpe ("voice_write vib LFO");
/******************* amplitude **********************/
count = fluid_rvoice_calc_amp(voice);
if (count <= 0)
return count;
/******************* phase **********************/
/* Calculate the number of samples, that the DSP loop advances
* through the original waveform with each step in the output
* buffer. It is the ratio between the frequencies of original
* waveform and output waveform.*/
voice->dsp.phase_incr = fluid_ct2hz_real(voice->dsp.pitch +
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch
+ fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch
+ fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_pitch)
/ voice->dsp.root_pitch_hz;
fluid_check_fpe ("voice_write phase calculation");
/* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
if (voice->dsp.phase_incr == 0) voice->dsp.phase_incr = 1;
voice->dsp.is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
|| (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
&& fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
/*********************** run the dsp chain ************************
* The sample is mixed with the output buffer.
* The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
* Depending on the position in the loop and the loop size, this
* may require several runs. */
voice->dsp.dsp_buf = dsp_buf;
switch (voice->dsp.interp_method)
{
case FLUID_INTERP_NONE:
count = fluid_rvoice_dsp_interpolate_none (&voice->dsp);
break;
case FLUID_INTERP_LINEAR:
count = fluid_rvoice_dsp_interpolate_linear (&voice->dsp);
break;
case FLUID_INTERP_4THORDER:
default:
count = fluid_rvoice_dsp_interpolate_4th_order (&voice->dsp);
break;
case FLUID_INTERP_7THORDER:
count = fluid_rvoice_dsp_interpolate_7th_order (&voice->dsp);
break;
}
fluid_check_fpe ("voice_write interpolation");
if (count == 0)
return count;
/*************** resonant filter ******************/
fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);
fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);
return count;
}
static inline fluid_real_t*
get_dest_buf(fluid_rvoice_buffers_t* buffers, int index,
fluid_real_t** dest_bufs, int dest_bufcount)
{
int j = buffers->bufs[index].mapping;
if (j >= dest_bufcount || j < 0) return NULL;
return dest_bufs[j];
}
/**
* Mix data down to buffers
*
* @param buffers Destination buffer(s)
* @param dsp_buf Mono sample source
* @param samplecount Number of samples to process (no FLUID_BUFSIZE restriction)
* @param dest_bufs Array of buffers to mixdown to
* @param dest_bufcount Length of dest_bufs
*/
void
fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
fluid_real_t* dsp_buf, int samplecount,
fluid_real_t** dest_bufs, int dest_bufcount)
{
int bufcount = buffers->count;
int i, dsp_i;
if (!samplecount || !bufcount || !dest_bufcount)
return;
for (i=0; i < bufcount; i++) {
fluid_real_t* buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
fluid_real_t* next_buf;
fluid_real_t amp = buffers->bufs[i].amp;
if (buf == NULL || amp == 0.0f)
continue;
/* Optimization for centered stereo samples - we can save one
multiplication per sample */
next_buf = (i+1 >= bufcount ? NULL : get_dest_buf(buffers, i+1, dest_bufs, dest_bufcount));
if (next_buf && buffers->bufs[i+1].amp == amp) {
for (dsp_i = 0; dsp_i < samplecount; dsp_i++) {
fluid_real_t samp = amp * dsp_buf[dsp_i];
buf[dsp_i] += samp;
next_buf[dsp_i] += samp;
}
i++;
}
else {
for (dsp_i = 0; dsp_i < samplecount; dsp_i++)
buf[dsp_i] += amp * dsp_buf[dsp_i];
}
}
}
/**
* Initialize buffers up to (and including) bufnum
*/
static int
fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t* buffers, unsigned int bufnum)
{
unsigned int i;
if (bufnum < buffers->count) return FLUID_OK;
if (bufnum >= FLUID_RVOICE_MAX_BUFS) return FLUID_FAILED;
for (i = buffers->count; i <= bufnum; i++) {
buffers->bufs[bufnum].amp = 0.0f;
buffers->bufs[bufnum].mapping = i;
}
buffers->count = bufnum+1;
return FLUID_OK;
}
void
fluid_rvoice_buffers_set_amp(fluid_rvoice_buffers_t* buffers,
unsigned int bufnum, fluid_real_t value)
{
if (fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
return;
buffers->bufs[bufnum].amp = value;
}
void
fluid_rvoice_buffers_set_mapping(fluid_rvoice_buffers_t* buffers,
unsigned int bufnum, int mapping)
{
if (fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
return;
buffers->bufs[bufnum].mapping = mapping;
}
void
fluid_rvoice_reset(fluid_rvoice_t* voice)
{
voice->dsp.has_looped = 0;
voice->envlfo.ticks = 0;
voice->envlfo.noteoff_ticks = 0;
voice->dsp.amp = 0.0f; /* The last value of the volume envelope, used to
calculate the volume increment during
processing */
/* mod env initialization*/
fluid_adsr_env_reset(&voice->envlfo.modenv);
/* vol env initialization */
fluid_adsr_env_reset(&voice->envlfo.volenv);
/* Fixme: Retrieve from any other existing
voice on this channel to keep LFOs in
unison? */
fluid_lfo_reset(&voice->envlfo.viblfo);
fluid_lfo_reset(&voice->envlfo.modlfo);
/* Clear sample history in filter */
fluid_iir_filter_reset(&voice->resonant_filter);
/* Force setting of the phase at the first DSP loop run
* This cannot be done earlier, because it depends on modulators.
[DH] Is that comment really true? */
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
}
void
fluid_rvoice_noteoff(fluid_rvoice_t* voice, unsigned int min_ticks)
{
if (min_ticks > voice->envlfo.ticks) {
/* Delay noteoff */
voice->envlfo.noteoff_ticks = min_ticks;
return;
}
voice->envlfo.noteoff_ticks = 0;
if (fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK) {
/* A voice is turned off during the attack section of the volume
* envelope. The attack section ramps up linearly with
* amplitude. The other sections use logarithmic scaling. Calculate new
* volenv_val to achieve equievalent amplitude during the release phase
* for seamless volume transition.
*/
if (fluid_adsr_env_get_val(&voice->envlfo.volenv) > 0){
fluid_real_t lfo = fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol;
fluid_real_t amp = fluid_adsr_env_get_val(&voice->envlfo.volenv) * pow (10.0, lfo / -200);
fluid_real_t env_value = - ((-200 * log (amp) / log (10.0) - lfo) / 960.0 - 1);
fluid_clip (env_value, 0.0, 1.0);
fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
}
}
fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVRELEASE);
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVRELEASE);
}
void
fluid_rvoice_set_output_rate(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->dsp.output_rate = value;
}
void
fluid_rvoice_set_interp_method(fluid_rvoice_t* voice, int value)
{
voice->dsp.interp_method = value;
}
void
fluid_rvoice_set_root_pitch_hz(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->dsp.root_pitch_hz = value;
}
void
fluid_rvoice_set_pitch(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->dsp.pitch = value;
}
void
fluid_rvoice_set_attenuation(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->dsp.attenuation = value;
}
void
fluid_rvoice_set_min_attenuation_cB(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->dsp.min_attenuation_cB = value;
}
void
fluid_rvoice_set_viblfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->envlfo.viblfo_to_pitch = value;
}
void fluid_rvoice_set_modlfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->envlfo.modlfo_to_pitch = value;
}
void
fluid_rvoice_set_modlfo_to_vol(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->envlfo.modlfo_to_vol = value;
}
void
fluid_rvoice_set_modlfo_to_fc(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->envlfo.modlfo_to_fc = value;
}
void
fluid_rvoice_set_modenv_to_fc(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->envlfo.modenv_to_fc = value;
}
void
fluid_rvoice_set_modenv_to_pitch(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->envlfo.modenv_to_pitch = value;
}
void
fluid_rvoice_set_synth_gain(fluid_rvoice_t* voice, fluid_real_t value)
{
voice->dsp.synth_gain = value;
/* For a looped sample, this value will be overwritten as soon as the
* loop parameters are initialized (they may depend on modulators).
* This value can be kept, it is a worst-case estimate.
*/
voice->dsp.amplitude_that_reaches_noise_floor_nonloop = FLUID_NOISE_FLOOR / value;
voice->dsp.amplitude_that_reaches_noise_floor_loop = FLUID_NOISE_FLOOR / value;
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
void
fluid_rvoice_set_start(fluid_rvoice_t* voice, int value)
{
voice->dsp.start = value;
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
void
fluid_rvoice_set_end(fluid_rvoice_t* voice, int value)
{
voice->dsp.end = value;
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
void
fluid_rvoice_set_loopstart(fluid_rvoice_t* voice, int value)
{
voice->dsp.loopstart = value;
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
void fluid_rvoice_set_loopend(fluid_rvoice_t* voice, int value)
{
voice->dsp.loopend = value;
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
void fluid_rvoice_set_samplemode(fluid_rvoice_t* voice, enum fluid_loop value)
{
voice->dsp.samplemode = value;
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
}
void
fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value)
{
voice->dsp.sample = value;
if (value) {
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
}
}
void
fluid_rvoice_voiceoff(fluid_rvoice_t* voice)
{
fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVFINISHED);
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVFINISHED);
}

View File

@ -0,0 +1,200 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_RVOICE_H
#define _FLUID_RVOICE_H
#include "fluidsynth_priv.h"
#include "fluid_iir_filter.h"
#include "fluid_adsr_env.h"
#include "fluid_lfo.h"
#include "fluid_phase.h"
#include "fluid_sfont.h"
typedef struct _fluid_rvoice_envlfo_t fluid_rvoice_envlfo_t;
typedef struct _fluid_rvoice_dsp_t fluid_rvoice_dsp_t;
typedef struct _fluid_rvoice_buffers_t fluid_rvoice_buffers_t;
typedef struct _fluid_rvoice_t fluid_rvoice_t;
/* Smallest amplitude that can be perceived (full scale is +/- 0.5)
* 16 bits => 96+4=100 dB dynamic range => 0.00001
* 0.00001 * 2 is approximately 0.00003 :)
*/
#define FLUID_NOISE_FLOOR 0.00003
enum fluid_loop {
FLUID_UNLOOPED = 0,
FLUID_LOOP_DURING_RELEASE = 1,
FLUID_NOTUSED = 2,
FLUID_LOOP_UNTIL_RELEASE = 3
};
/**
* rvoice ticks-based parameters
* These parameters must be updated even if the voice is currently quiet.
*/
struct _fluid_rvoice_envlfo_t
{
/* Note-off minimum length */
unsigned int ticks;
unsigned int noteoff_ticks;
/* vol env */
fluid_adsr_env_t volenv;
/* mod env */
fluid_adsr_env_t modenv;
fluid_real_t modenv_to_fc;
fluid_real_t modenv_to_pitch;
/* mod lfo */
fluid_lfo_t modlfo;
fluid_real_t modlfo_to_fc;
fluid_real_t modlfo_to_pitch;
fluid_real_t modlfo_to_vol;
/* vib lfo */
fluid_lfo_t viblfo;
fluid_real_t viblfo_to_pitch;
};
/**
* rvoice parameters needed for dsp interpolation
*/
struct _fluid_rvoice_dsp_t
{
/* interpolation method, as in fluid_interp in fluidsynth.h */
int interp_method;
fluid_sample_t* sample;
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
have to be checked. */
/* sample and loop start and end points (offset in sample memory). */
int start;
int end;
int loopstart;
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
enum fluid_loop samplemode;
/* Stuff needed for phase calculations */
fluid_real_t pitch; /* the pitch in midicents */
fluid_real_t root_pitch_hz;
fluid_real_t output_rate;
/* Stuff needed for amplitude calculations */
int has_looped; /* Flag that is set as soon as the first loop is completed. */
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 amplitude_that_reaches_noise_floor_nonloop;
fluid_real_t amplitude_that_reaches_noise_floor_loop;
fluid_real_t synth_gain; /* master gain */
/* Dynamic input to the interpolator below */
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
fluid_real_t amp; /* current linear amplitude */
fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */
fluid_phase_t phase; /* the phase (current sample offset) of the sample wave */
fluid_real_t phase_incr; /* the phase increment for the next FLUID_BUFSIZE samples */
int is_looping;
};
/* Currently left, right, reverb, chorus. To be changed if we
ever add surround positioning, or stereo reverb/chorus */
#define FLUID_RVOICE_MAX_BUFS (4)
/**
* rvoice mixer-related parameters
*/
struct _fluid_rvoice_buffers_t
{
unsigned int count; /* Number of records in "bufs" */
struct {
fluid_real_t amp;
int mapping; /* Mapping to mixdown buffer index */
} bufs[FLUID_RVOICE_MAX_BUFS];
};
/**
* Parameters needed to synthesize a voice
*/
struct _fluid_rvoice_t
{
fluid_rvoice_envlfo_t envlfo;
fluid_rvoice_dsp_t dsp;
fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */
fluid_rvoice_buffers_t buffers;
};
int fluid_rvoice_write(fluid_rvoice_t* voice, fluid_real_t *dsp_buf);
void fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
fluid_real_t* dsp_buf, int samplecount,
fluid_real_t** dest_bufs, int dest_bufcount);
void fluid_rvoice_buffers_set_amp(fluid_rvoice_buffers_t* buffers,
unsigned int bufnum, fluid_real_t value);
void fluid_rvoice_buffers_set_mapping(fluid_rvoice_buffers_t* buffers,
unsigned int bufnum, int mapping);
/* Dynamic update functions */
void fluid_rvoice_noteoff(fluid_rvoice_t* voice, unsigned int min_ticks);
void fluid_rvoice_voiceoff(fluid_rvoice_t* voice);
void fluid_rvoice_reset(fluid_rvoice_t* voice);
void fluid_rvoice_set_output_rate(fluid_rvoice_t* voice, fluid_real_t output_rate);
void fluid_rvoice_set_interp_method(fluid_rvoice_t* voice, int interp_method);
void fluid_rvoice_set_root_pitch_hz(fluid_rvoice_t* voice, fluid_real_t root_pitch_hz);
void fluid_rvoice_set_pitch(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_synth_gain(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_attenuation(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_min_attenuation_cB(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_viblfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_modlfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_modlfo_to_vol(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_modlfo_to_fc(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_modenv_to_fc(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_modenv_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
void fluid_rvoice_set_start(fluid_rvoice_t* voice, int value);
void fluid_rvoice_set_end(fluid_rvoice_t* voice, int value);
void fluid_rvoice_set_loopstart(fluid_rvoice_t* voice, int value);
void fluid_rvoice_set_loopend(fluid_rvoice_t* voice, int value);
void fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value);
void fluid_rvoice_set_samplemode(fluid_rvoice_t* voice, enum fluid_loop value);
/* defined in fluid_rvoice_dsp.c */
void fluid_rvoice_dsp_config (void);
int fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice);
int fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice);
int fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice);
int fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice);
#endif

View File

@ -0,0 +1,675 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluidsynth_priv.h"
#include "fluid_phase.h"
#include "fluid_rvoice.h"
#include "fluid_sys.h"
/* Purpose:
*
* Interpolates audio data (obtains values between the samples of the original
* waveform data).
*
* Variables loaded from the voice structure (assigned in fluid_voice_write()):
* - dsp_data: Pointer to the original waveform data
* - 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_buf: Output buffer of floating point values (FLUID_BUFSIZE in length)
*/
/* Interpolation (find a value between two samples of the original waveform) */
/* Linear interpolation table (2 coefficients centered on 1st) */
static fluid_real_t interp_coeff_linear[FLUID_INTERP_MAX][2];
/* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */
static fluid_real_t interp_coeff[FLUID_INTERP_MAX][4];
/* 7th order interpolation (7 coefficients centered on 3rd) */
static fluid_real_t sinc_table7[FLUID_INTERP_MAX][7];
#define SINC_INTERP_ORDER 7 /* 7th order constant */
/* Initializes interpolation tables */
void fluid_rvoice_dsp_config (void)
{
int i, i2;
double x, v;
double i_shifted;
/* Initialize the coefficients for the interpolation. The math comes
* from a mail, posted by Olli Niemitalo to the music-dsp mailing
* list (I found it in the music-dsp archives
* http://www.smartelectronix.com/musicdsp/). */
for (i = 0; i < FLUID_INTERP_MAX; i++)
{
x = (double) i / (double) FLUID_INTERP_MAX;
interp_coeff[i][0] = (fluid_real_t)(x * (-0.5 + x * (1 - 0.5 * x)));
interp_coeff[i][1] = (fluid_real_t)(1.0 + x * x * (1.5 * x - 2.5));
interp_coeff[i][2] = (fluid_real_t)(x * (0.5 + x * (2.0 - 1.5 * x)));
interp_coeff[i][3] = (fluid_real_t)(0.5 * x * x * (x - 1.0));
interp_coeff_linear[i][0] = (fluid_real_t)(1.0 - x);
interp_coeff_linear[i][1] = (fluid_real_t)x;
}
/* i: Offset in terms of whole samples */
for (i = 0; i < SINC_INTERP_ORDER; i++)
{ /* i2: Offset in terms of fractional samples ('subsamples') */
for (i2 = 0; i2 < FLUID_INTERP_MAX; i2++)
{
/* center on middle of table */
i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
+ (double)i2 / (double)FLUID_INTERP_MAX;
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
if (fabs (i_shifted) > 0.000001)
{
v = (fluid_real_t)sin (i_shifted * M_PI) / (M_PI * i_shifted);
/* Hamming window */
v *= (fluid_real_t)0.5 * (1.0 + cos (2.0 * M_PI * i_shifted / (fluid_real_t)SINC_INTERP_ORDER));
}
else v = 1.0;
sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
}
}
#if 0
for (i = 0; i < FLUID_INTERP_MAX; i++)
{
printf ("%d %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",
i, sinc_table7[0][i], sinc_table7[1][i], sinc_table7[2][i],
sinc_table7[3][i], sinc_table7[4][i], sinc_table7[5][i], sinc_table7[6][i]);
}
#endif
fluid_check_fpe("interpolation table calculation");
}
/* No interpolation. Just take the sample, which is closest to
* the playback pointer. Questionable quality, but very
* efficient. */
int
fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr;
short int *dsp_data = voice->sample->data;
fluid_real_t *dsp_buf = voice->dsp_buf;
fluid_real_t dsp_amp = voice->amp;
fluid_real_t dsp_amp_incr = voice->amp_incr;
unsigned int dsp_i = 0;
unsigned int dsp_phase_index;
unsigned int end_index;
int looping;
/* Convert playback "speed" floating point value to phase index/fract */
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
/* voice is currently looping? */
looping = voice->is_looping;
end_index = looping ? voice->loopend - 1 : voice->end;
while (1)
{
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
/* interpolate sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
dsp_amp += dsp_amp_incr;
}
/* break out if not looping (buffer may not be full) */
if (!looping) break;
/* go back to loop start */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
voice->has_looped = 1;
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}
/* Straight line interpolation.
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
* smaller if end of sample occurs).
*/
int
fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr;
short int *dsp_data = voice->sample->data;
fluid_real_t *dsp_buf = voice->dsp_buf;
fluid_real_t dsp_amp = voice->amp;
fluid_real_t dsp_amp_incr = voice->amp_incr;
unsigned int dsp_i = 0;
unsigned int dsp_phase_index;
unsigned int end_index;
short int point;
fluid_real_t *coeffs;
int looping;
/* Convert playback "speed" floating point value to phase index/fract */
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
/* voice is currently looping? */
looping = voice->is_looping;
/* last index before 2nd interpolation point must be specially handled */
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
/* 2nd interpolation point to use at end of loop or sample */
if (looping) point = dsp_data[voice->loopstart]; /* loop start */
else point = dsp_data[voice->end]; /* duplicate end for samples no longer looping */
while (1)
{
dsp_phase_index = fluid_phase_index (dsp_phase);
/* interpolate the sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
+ coeffs[1] * dsp_data[dsp_phase_index+1]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* break out if buffer filled */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index++; /* we're now interpolating the last point */
/* interpolate within last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
+ coeffs[1] * point);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr; /* increment amplitude */
}
if (!looping) break; /* break out if not looping (end of sample) */
/* go back to loop start (if past */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
voice->has_looped = 1;
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index--; /* set end back to second to last sample point */
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}
/* 4th order (cubic) interpolation.
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
* smaller if end of sample occurs).
*/
int
fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr;
short int *dsp_data = voice->sample->data;
fluid_real_t *dsp_buf = voice->dsp_buf;
fluid_real_t dsp_amp = voice->amp;
fluid_real_t dsp_amp_incr = voice->amp_incr;
unsigned int dsp_i = 0;
unsigned int dsp_phase_index;
unsigned int start_index, end_index;
short int start_point, end_point1, end_point2;
fluid_real_t *coeffs;
int looping;
/* Convert playback "speed" floating point value to phase index/fract */
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
/* voice is currently looping? */
looping = voice->is_looping;
/* last index before 4th interpolation point must be specially handled */
end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
if (voice->has_looped) /* set start_index and start point if looped or not */
{
start_index = voice->loopstart;
start_point = dsp_data[voice->loopend - 1]; /* last point in loop (wrap around) */
}
else
{
start_index = voice->start;
start_point = dsp_data[voice->start]; /* just duplicate the point */
}
/* get points off the end (loop start if looping, duplicate point if end) */
if (looping)
{
end_point1 = dsp_data[voice->loopstart];
end_point2 = dsp_data[voice->loopstart + 1];
}
else
{
end_point1 = dsp_data[voice->end];
end_point2 = end_point1;
}
while (1)
{
dsp_phase_index = fluid_phase_index (dsp_phase);
/* interpolate first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * start_point
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * dsp_data[dsp_phase_index+1]
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* interpolate the sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * dsp_data[dsp_phase_index+1]
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* break out if buffer filled */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index++; /* we're now interpolating the 2nd to last point */
/* interpolate within 2nd to last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * dsp_data[dsp_phase_index+1]
+ coeffs[3] * end_point1);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the last point */
/* interpolate within the last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * end_point1
+ coeffs[3] * end_point2);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
if (!looping) break; /* break out if not looping (end of sample) */
/* go back to loop start */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
if (!voice->has_looped)
{
voice->has_looped = 1;
start_index = voice->loopstart;
start_point = dsp_data[voice->loopend - 1];
}
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index -= 2; /* set end back to third to last sample point */
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}
/* 7th order interpolation.
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
* smaller if end of sample occurs).
*/
int
fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr;
short int *dsp_data = voice->sample->data;
fluid_real_t *dsp_buf = voice->dsp_buf;
fluid_real_t dsp_amp = voice->amp;
fluid_real_t dsp_amp_incr = voice->amp_incr;
unsigned int dsp_i = 0;
unsigned int dsp_phase_index;
unsigned int start_index, end_index;
short int start_points[3];
short int end_points[3];
fluid_real_t *coeffs;
int looping;
/* Convert playback "speed" floating point value to phase index/fract */
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
/* add 1/2 sample to dsp_phase since 7th order interpolation is centered on
* the 4th sample point */
fluid_phase_incr (dsp_phase, (fluid_phase_t)0x80000000);
/* voice is currently looping? */
looping = voice->is_looping;
/* last index before 7th interpolation point must be specially handled */
end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
if (voice->has_looped) /* set start_index and start point if looped or not */
{
start_index = voice->loopstart;
start_points[0] = dsp_data[voice->loopend - 1];
start_points[1] = dsp_data[voice->loopend - 2];
start_points[2] = dsp_data[voice->loopend - 3];
}
else
{
start_index = voice->start;
start_points[0] = dsp_data[voice->start]; /* just duplicate the start point */
start_points[1] = start_points[0];
start_points[2] = start_points[0];
}
/* get the 3 points off the end (loop start if looping, duplicate point if end) */
if (looping)
{
end_points[0] = dsp_data[voice->loopstart];
end_points[1] = dsp_data[voice->loopstart + 1];
end_points[2] = dsp_data[voice->loopstart + 2];
}
else
{
end_points[0] = dsp_data[voice->end];
end_points[1] = end_points[0];
end_points[2] = end_points[0];
}
while (1)
{
dsp_phase_index = fluid_phase_index (dsp_phase);
/* interpolate first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)start_points[2]
+ coeffs[1] * (fluid_real_t)start_points[1]
+ coeffs[2] * (fluid_real_t)start_points[0]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
start_index++;
/* interpolate 2nd to first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)start_points[1]
+ coeffs[1] * (fluid_real_t)start_points[0]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
start_index++;
/* interpolate 3rd to first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)start_points[0]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
start_index -= 2; /* set back to original start index */
/* interpolate the sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* break out if buffer filled */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index++; /* we're now interpolating the 3rd to last point */
/* interpolate within 3rd to last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)end_points[0]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the 2nd to last point */
/* interpolate within 2nd to last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)end_points[0]
+ coeffs[6] * (fluid_real_t)end_points[1]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the last point */
/* interpolate within last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)end_points[0]
+ coeffs[5] * (fluid_real_t)end_points[1]
+ coeffs[6] * (fluid_real_t)end_points[2]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
if (!looping) break; /* break out if not looping (end of sample) */
/* go back to loop start */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
if (!voice->has_looped)
{
voice->has_looped = 1;
start_index = voice->loopstart;
start_points[0] = dsp_data[voice->loopend - 1];
start_points[1] = dsp_data[voice->loopend - 2];
start_points[2] = dsp_data[voice->loopend - 3];
}
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index -= 3; /* set end back to 4th to last sample point */
}
/* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on
* the 4th sample point (correct back to real value) */
fluid_phase_decr (dsp_phase, (fluid_phase_t)0x80000000);
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}

View File

@ -0,0 +1,293 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_rvoice_event.h"
#include "fluid_rvoice.h"
#include "fluid_rvoice_mixer.h"
#include "fluid_iir_filter.h"
#include "fluid_lfo.h"
#include "fluid_adsr_env.h"
#define EVENTFUNC_0(proc, type) \
if (event->method == proc) { \
proc((type) event->object); \
return; }
#define EVENTFUNC_R1(proc, type) \
if (event->method == proc) { \
if(event->intparam != 0) { FLUID_LOG(FLUID_DBG, "IR-mismatch"); } \
proc((type) event->object, event->realparams[0]); \
return; }
#define EVENTFUNC_PTR(proc, type, type2) \
if (event->method == proc) { \
proc((type) event->object, (type2) event->ptr); \
return; }
#define EVENTFUNC_I1(proc, type) \
if (event->method == proc) { \
if(event->realparams[0] != 0.0f) { FLUID_LOG(FLUID_DBG, "IR-mismatch"); } \
proc((type) event->object, event->intparam); \
return; }
#define EVENTFUNC_IR(proc, type) \
if (event->method == proc) { \
proc((type) event->object, event->intparam, event->realparams[0]); \
return; }
#define EVENTFUNC_ALL(proc, type) \
if (event->method == proc) { \
proc((type) event->object, event->intparam, event->realparams[0], \
event->realparams[1], event->realparams[2], event->realparams[3], \
event->realparams[4]); \
return; }
#define EVENTFUNC_R4(proc, type) \
if (event->method == proc) { \
proc((type) event->object, event->intparam, event->realparams[0], \
event->realparams[1], event->realparams[2], event->realparams[3]); \
return; }
void
fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event)
{
EVENTFUNC_PTR(fluid_rvoice_mixer_add_voice, fluid_rvoice_mixer_t*, fluid_rvoice_t*);
EVENTFUNC_I1(fluid_rvoice_noteoff, fluid_rvoice_t*);
EVENTFUNC_0(fluid_rvoice_voiceoff, fluid_rvoice_t*);
EVENTFUNC_0(fluid_rvoice_reset, fluid_rvoice_t*);
EVENTFUNC_ALL(fluid_adsr_env_set_data, fluid_adsr_env_t*);
EVENTFUNC_I1(fluid_lfo_set_delay, fluid_lfo_t*);
EVENTFUNC_R1(fluid_lfo_set_incr, fluid_lfo_t*);
EVENTFUNC_R1(fluid_iir_filter_set_fres, fluid_iir_filter_t*);
EVENTFUNC_R1(fluid_iir_filter_set_q_dB, fluid_iir_filter_t*);
EVENTFUNC_IR(fluid_rvoice_buffers_set_mapping, fluid_rvoice_buffers_t*);
EVENTFUNC_IR(fluid_rvoice_buffers_set_amp, fluid_rvoice_buffers_t*);
EVENTFUNC_R1(fluid_rvoice_set_modenv_to_pitch, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_output_rate, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_root_pitch_hz, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_synth_gain, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_pitch, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_attenuation, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_min_attenuation_cB, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_viblfo_to_pitch, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_pitch, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_vol, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_fc, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_modenv_to_fc, fluid_rvoice_t*);
EVENTFUNC_R1(fluid_rvoice_set_modenv_to_pitch, fluid_rvoice_t*);
EVENTFUNC_I1(fluid_rvoice_set_interp_method, fluid_rvoice_t*);
EVENTFUNC_I1(fluid_rvoice_set_start, fluid_rvoice_t*);
EVENTFUNC_I1(fluid_rvoice_set_end, fluid_rvoice_t*);
EVENTFUNC_I1(fluid_rvoice_set_loopstart, fluid_rvoice_t*);
EVENTFUNC_I1(fluid_rvoice_set_loopend, fluid_rvoice_t*);
EVENTFUNC_I1(fluid_rvoice_set_samplemode, fluid_rvoice_t*);
EVENTFUNC_PTR(fluid_rvoice_set_sample, fluid_rvoice_t*, fluid_sample_t*);
EVENTFUNC_R1(fluid_rvoice_mixer_set_samplerate, fluid_rvoice_mixer_t*);
EVENTFUNC_I1(fluid_rvoice_mixer_set_polyphony, fluid_rvoice_mixer_t*);
EVENTFUNC_I1(fluid_rvoice_mixer_set_reverb_enabled, fluid_rvoice_mixer_t*);
EVENTFUNC_I1(fluid_rvoice_mixer_set_chorus_enabled, fluid_rvoice_mixer_t*);
EVENTFUNC_I1(fluid_rvoice_mixer_set_mix_fx, fluid_rvoice_mixer_t*);
EVENTFUNC_0(fluid_rvoice_mixer_reset_fx, fluid_rvoice_mixer_t*);
EVENTFUNC_0(fluid_rvoice_mixer_reset_reverb, fluid_rvoice_mixer_t*);
EVENTFUNC_0(fluid_rvoice_mixer_reset_chorus, fluid_rvoice_mixer_t*);
EVENTFUNC_IR(fluid_rvoice_mixer_set_threads, fluid_rvoice_mixer_t*);
EVENTFUNC_ALL(fluid_rvoice_mixer_set_chorus_params, fluid_rvoice_mixer_t*);
EVENTFUNC_R4(fluid_rvoice_mixer_set_reverb_params, fluid_rvoice_mixer_t*);
FLUID_LOG(FLUID_ERR, "fluid_rvoice_event_dispatch: Unknown method %p to dispatch!", event->method);
}
/**
* In order to be able to push more than one event atomically,
* use push for all events, then use flush to commit them to the
* queue. If threadsafe is false, all events are processed immediately. */
int
fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t* handler,
void* method, void* object, int intparam,
fluid_real_t realparam)
{
fluid_rvoice_event_t* event;
fluid_rvoice_event_t local_event;
event = handler->is_threadsafe ?
fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
if (event == NULL) {
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
return FLUID_FAILED; // Buffer full...
}
event->method = method;
event->object = object;
event->intparam = intparam;
event->realparams[0] = realparam;
if (handler->is_threadsafe)
handler->queue_stored++;
else
fluid_rvoice_event_dispatch(event);
return FLUID_OK;
}
int
fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t* handler,
void* method, void* object, void* ptr)
{
fluid_rvoice_event_t* event;
fluid_rvoice_event_t local_event;
event = handler->is_threadsafe ?
fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
if (event == NULL) {
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
return FLUID_FAILED; // Buffer full...
}
event->method = method;
event->object = object;
event->ptr = ptr;
if (handler->is_threadsafe)
handler->queue_stored++;
else
fluid_rvoice_event_dispatch(event);
return FLUID_OK;
}
int
fluid_rvoice_eventhandler_push5(fluid_rvoice_eventhandler_t* handler,
void* method, void* object, int intparam,
fluid_real_t r1, fluid_real_t r2,
fluid_real_t r3, fluid_real_t r4, fluid_real_t r5)
{
fluid_rvoice_event_t* event;
fluid_rvoice_event_t local_event;
event = handler->is_threadsafe ?
fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
if (event == NULL) {
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
return FLUID_FAILED; // Buffer full...
}
event->method = method;
event->object = object;
event->intparam = intparam;
event->realparams[0] = r1;
event->realparams[1] = r2;
event->realparams[2] = r3;
event->realparams[3] = r4;
event->realparams[4] = r5;
if (handler->is_threadsafe)
handler->queue_stored++;
else
fluid_rvoice_event_dispatch(event);
return FLUID_OK;
}
static void
finished_voice_callback(void* userdata, fluid_rvoice_t* rvoice)
{
fluid_rvoice_eventhandler_t* eventhandler = userdata;
fluid_rvoice_t** vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
if (vptr == NULL)
return; // Buffer full
*vptr = rvoice;
fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
}
fluid_rvoice_eventhandler_t*
new_fluid_rvoice_eventhandler(int is_threadsafe, int queuesize,
int finished_voices_size, int bufs, int fx_bufs, fluid_real_t sample_rate)
{
fluid_rvoice_eventhandler_t* eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
if (eventhandler == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
eventhandler->mixer = NULL;
eventhandler->queue = NULL;
eventhandler->finished_voices = NULL;
eventhandler->is_threadsafe = is_threadsafe;
eventhandler->queue_stored = 0;
eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
sizeof(fluid_rvoice_t*));
if (eventhandler->finished_voices == NULL)
goto error_recovery;
eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t));
if (eventhandler->queue == NULL)
goto error_recovery;
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate);
if (eventhandler->mixer == NULL)
goto error_recovery;
fluid_rvoice_mixer_set_finished_voices_callback(eventhandler->mixer,
finished_voice_callback, eventhandler);
return eventhandler;
error_recovery:
delete_fluid_rvoice_eventhandler(eventhandler);
return NULL;
}
int
fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t* handler)
{
return fluid_ringbuffer_get_count(handler->queue);
}
/**
* Call fluid_rvoice_event_dispatch for all events in queue
* @return number of events dispatched
*/
int
fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t* handler)
{
fluid_rvoice_event_t* event;
int result = 0;
while (NULL != (event = fluid_ringbuffer_get_outptr(handler->queue))) {
fluid_rvoice_event_dispatch(event);
result++;
fluid_ringbuffer_next_outptr(handler->queue);
}
return result;
}
void
delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t* handler)
{
if (handler == NULL) return;
delete_fluid_rvoice_mixer(handler->mixer);
delete_fluid_ringbuffer(handler->queue);
delete_fluid_ringbuffer(handler->finished_voices);
FLUID_FREE(handler);
}

View File

@ -0,0 +1,115 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_RVOICE_EVENT_H
#define _FLUID_RVOICE_EVENT_H
#include "fluidsynth_priv.h"
#include "fluid_rvoice_mixer.h"
#include "fluid_ringbuffer.h"
#define EVENT_REAL_PARAMS (5)
typedef struct _fluid_rvoice_event_t fluid_rvoice_event_t;
typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t;
struct _fluid_rvoice_event_t {
void* method;
void* object;
void* ptr;
int intparam;
fluid_real_t realparams[EVENT_REAL_PARAMS];
};
void fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event);
/**
* Bridge between the renderer thread and the midi state thread.
* If is_threadsafe is true, that means fluid_rvoice_eventhandler_fetch_all
* can be called in parallell with fluid_rvoice_eventhandler_push/flush
*/
struct _fluid_rvoice_eventhandler_t {
int is_threadsafe; /* False for optimal performance, true for atomic operations */
fluid_ringbuffer_t* queue; /**< List of fluid_rvoice_event_t */
int queue_stored; /**< Extras pushed but not flushed */
fluid_ringbuffer_t* finished_voices; /**< return queue from handler, list of fluid_rvoice_t* */
fluid_rvoice_mixer_t* mixer;
};
fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
int is_threadsafe, int queuesize, int finished_voices_size, int bufs,
int fx_bufs, fluid_real_t sample_rate);
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t*);
int fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t*);
int fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t*);
static FLUID_INLINE void
fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t* handler)
{
if (handler->queue_stored > 0) {
fluid_ringbuffer_next_inptr(handler->queue, handler->queue_stored);
handler->queue_stored = 0;
}
}
/**
* @return next finished voice, or NULL if nothing in queue
*/
static FLUID_INLINE fluid_rvoice_t*
fluid_rvoice_eventhandler_get_finished_voice(fluid_rvoice_eventhandler_t* handler)
{
void* result = fluid_ringbuffer_get_outptr(handler->finished_voices);
if (result == NULL) return NULL;
result = * (fluid_rvoice_t**) result;
fluid_ringbuffer_next_outptr(handler->finished_voices);
return result;
}
int fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t* handler,
void* method, void* object, int intparam,
fluid_real_t realparam);
int fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t* handler,
void* method, void* object, void* ptr);
int fluid_rvoice_eventhandler_push5(fluid_rvoice_eventhandler_t* handler,
void* method, void* object, int intparam,
fluid_real_t r1, fluid_real_t r2,
fluid_real_t r3, fluid_real_t r4, fluid_real_t r5);
static FLUID_INLINE void
fluid_rvoice_eventhandler_add_rvoice(fluid_rvoice_eventhandler_t* handler,
fluid_rvoice_t* rvoice)
{
if (handler->is_threadsafe)
fluid_rvoice_eventhandler_push_ptr(handler, fluid_rvoice_mixer_add_voice,
handler->mixer, rvoice);
else
fluid_rvoice_mixer_add_voice(handler->mixer, rvoice);
}
#endif

View File

@ -0,0 +1,974 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_rvoice_mixer.h"
#include "fluid_rvoice.h"
#include "fluid_sys.h"
#include "fluid_rev.h"
#include "fluid_chorus.h"
#include "fluidsynth_priv.h"
//#include "fluid_ladspa.h"
#define SYNTH_REVERB_CHANNEL 0
#define SYNTH_CHORUS_CHANNEL 1
#define ENABLE_MIXER_THREADS 1
// If less than x voices, the thread overhead is larger than the gain,
// so don't activate the thread(s).
#define VOICES_PER_THREAD 8
typedef struct _fluid_mixer_buffers_t fluid_mixer_buffers_t;
struct _fluid_mixer_buffers_t {
fluid_rvoice_mixer_t* mixer; /**< Owner of object */
#ifdef ENABLE_MIXER_THREADS
fluid_thread_t* thread; /**< Thread object */
#endif
fluid_rvoice_t** finished_voices; /* List of voices who have finished */
int finished_voice_count;
int ready; /**< Atomic: buffers are ready for mixing */
int buf_blocks; /**< Number of blocks allocated in the buffers */
int buf_count;
fluid_real_t** left_buf;
fluid_real_t** right_buf;
int fx_buf_count;
fluid_real_t** fx_left_buf;
fluid_real_t** fx_right_buf;
};
typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t;
struct _fluid_mixer_fx_t {
fluid_revmodel_t* reverb; /**< Reverb unit */
fluid_chorus_t* chorus; /**< Chorus unit */
int with_reverb; /**< Should the synth use the built-in reverb unit? */
int with_chorus; /**< Should the synth use the built-in chorus unit? */
int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
};
struct _fluid_rvoice_mixer_t {
fluid_mixer_fx_t fx;
fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
void (*remove_voice_callback)(void*, fluid_rvoice_t*); /**< Used by mixer only: Receive this callback every time a voice is removed */
void* remove_voice_callback_userdata;
fluid_rvoice_t** rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
int polyphony; /**< Read-only: Length of voices array */
int active_voices; /**< Read-only: Number of non-null voices */
int current_blockcount; /**< Read-only: how many blocks to process this time */
#ifdef LADSPA
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
#endif
#ifdef ENABLE_MIXER_THREADS
// int sleeping_threads; /**< Atomic: number of threads currently asleep */
// int active_threads; /**< Atomic: number of threads in the thread loop */
int threads_should_terminate; /**< Atomic: Set to TRUE when threads should terminate */
int current_rvoice; /**< Atomic: for the threads to know next voice to */
fluid_cond_t* wakeup_threads; /**< Signalled when the threads should wake up */
fluid_cond_mutex_t* wakeup_threads_m; /**< wakeup_threads mutex companion */
fluid_cond_t* thread_ready; /**< Signalled from thread, when the thread has a buffer ready for mixing */
fluid_cond_mutex_t* thread_ready_m; /**< thread_ready mutex companion */
int thread_count; /**< Number of extra mixer threads for multi-core rendering */
fluid_mixer_buffers_t* threads; /**< Array of mixer threads (thread_count in length) */
#endif
};
static FLUID_INLINE void
fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
{
int i;
fluid_profile_ref_var(prof_ref);
if (mixer->fx.with_reverb) {
if (mixer->fx.mix_fx_to_out) {
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
fluid_revmodel_processmix(mixer->fx.reverb,
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
&mixer->buffers.left_buf[0][i],
&mixer->buffers.right_buf[0][i]);
}
else {
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
fluid_revmodel_processreplace(mixer->fx.reverb,
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
&mixer->buffers.fx_right_buf[SYNTH_REVERB_CHANNEL][i]);
}
fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref);
}
if (mixer->fx.with_chorus) {
if (mixer->fx.mix_fx_to_out) {
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
fluid_chorus_processmix(mixer->fx.chorus,
&mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
&mixer->buffers.left_buf[0][i],
&mixer->buffers.right_buf[0][i]);
}
else {
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
fluid_chorus_processreplace(mixer->fx.chorus,
&mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
&mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
&mixer->buffers.fx_right_buf[SYNTH_CHORUS_CHANNEL][i]);
}
fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref);
}
#ifdef LADSPA
/* Run the signal through the LADSPA Fx unit */
if (mixer->LADSPA_FxUnit) {
int j;
FLUID_DECLARE_VLA(fluid_real_t*, left_buf, mixer->buffers.buf_count);
FLUID_DECLARE_VLA(fluid_real_t*, right_buf, mixer->buffers.buf_count);
FLUID_DECLARE_VLA(fluid_real_t*, fx_left_buf, mixer->buffers.fx_buf_count);
FLUID_DECLARE_VLA(fluid_real_t*, fx_right_buf, mixer->buffers.fx_buf_count);
for (j=0; j < mixer->buffers.buf_count; j++) {
left_buf[j] = mixer->buffers.left_buf[j];
right_buf[j] = mixer->buffers.right_buf[j];
}
for (j=0; j < mixer->buffers.fx_buf_count; j++) {
fx_left_buf[j] = mixer->buffers.fx_left_buf[j];
fx_right_buf[j] = mixer->buffers.fx_right_buf[j];
}
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE) {
fluid_LADSPA_run(mixer->LADSPA_FxUnit, left_buf, right_buf, fx_left_buf,
fx_right_buf);
for (j=0; j < mixer->buffers.buf_count; j++) {
left_buf[j] += FLUID_BUFSIZE;
right_buf[j] += FLUID_BUFSIZE;
}
for (j=0; j < mixer->buffers.fx_buf_count; j++) {
fx_left_buf[j] += FLUID_BUFSIZE;
fx_right_buf[j] += FLUID_BUFSIZE;
}
}
fluid_check_fpe("LADSPA");
}
#endif
}
/**
* During rendering, rvoices might be finished. Set this callback
* for getting a callback any time the rvoice is finished.
*/
void fluid_rvoice_mixer_set_finished_voices_callback(
fluid_rvoice_mixer_t* mixer,
void (*func)(void*, fluid_rvoice_t*),
void* userdata)
{
mixer->remove_voice_callback_userdata = userdata;
mixer->remove_voice_callback = func;
}
/**
* Synthesize one voice and add to buffer.
* NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
* voice has been finished, removed and possibly replaced with another voice.
* @return Number of samples written
*/
static int
fluid_mix_one(fluid_rvoice_t* rvoice, fluid_real_t** bufs, unsigned int bufcount, int blockcount)
{
int i, result = 0;
FLUID_DECLARE_VLA(fluid_real_t, local_buf, FLUID_BUFSIZE*blockcount);
for (i=0; i < blockcount; i++) {
int s = fluid_rvoice_write(rvoice, &local_buf[FLUID_BUFSIZE*i]);
if (s == -1) {
s = FLUID_BUFSIZE; /* Voice is quiet, TODO: optimize away memset/mix */
FLUID_MEMSET(&local_buf[FLUID_BUFSIZE*i], 0, FLUID_BUFSIZE*sizeof(fluid_real_t));
}
result += s;
if (s < FLUID_BUFSIZE) {
break;
}
}
fluid_rvoice_buffers_mix(&rvoice->buffers, local_buf, result, bufs, bufcount);
return result;
}
/**
* Glue to get fluid_rvoice_buffers_mix what it wants
* Note: Make sure outbufs has 2 * (buf_count + fx_buf_count) elements before calling
*/
static FLUID_INLINE int
fluid_mixer_buffers_prepare(fluid_mixer_buffers_t* buffers, fluid_real_t** outbufs)
{
fluid_real_t* reverb_buf, *chorus_buf;
int i;
/* Set up the reverb / chorus buffers only, when the effect is
* enabled on synth level. Nonexisting buffers are detected in the
* DSP loop. Not sending the reverb / chorus signal saves some time
* in that case. */
reverb_buf = buffers->mixer->fx.with_reverb ? buffers->fx_left_buf[SYNTH_REVERB_CHANNEL] : NULL;
chorus_buf = buffers->mixer->fx.with_chorus ? buffers->fx_left_buf[SYNTH_CHORUS_CHANNEL] : NULL;
outbufs[buffers->buf_count*2 + SYNTH_REVERB_CHANNEL] = reverb_buf;
outbufs[buffers->buf_count*2 + SYNTH_CHORUS_CHANNEL] = chorus_buf;
/* The output associated with a MIDI channel is wrapped around
* using the number of audio groups as modulo divider. This is
* typically the number of output channels on the 'sound card',
* as long as the LADSPA Fx unit is not used. In case of LADSPA
* unit, think of it as subgroups on a mixer.
*
* For example: Assume that the number of groups is set to 2.
* Then MIDI channel 1, 3, 5, 7 etc. go to output 1, channels 2,
* 4, 6, 8 etc to output 2. Or assume 3 groups: Then MIDI
* channels 1, 4, 7, 10 etc go to output 1; 2, 5, 8, 11 etc to
* output 2, 3, 6, 9, 12 etc to output 3.
*/
for (i = 0; i < buffers->buf_count; i++) {
outbufs[i*2] = buffers->left_buf[i];
outbufs[i*2+1] = buffers->right_buf[i];
}
return buffers->buf_count*2 + 2;
}
static FLUID_INLINE void
fluid_finish_rvoice(fluid_mixer_buffers_t* buffers, fluid_rvoice_t* rvoice)
{
if (buffers->finished_voice_count < buffers->mixer->polyphony)
buffers->finished_voices[buffers->finished_voice_count++] = rvoice;
else
FLUID_LOG(FLUID_ERR, "Exceeded finished voices array, try increasing polyphony");
}
static void
fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t* buffers)
{
int i,j;
for (i=0; i < buffers->finished_voice_count; i++) {
fluid_rvoice_t* v = buffers->finished_voices[i];
int* av = &buffers->mixer->active_voices;
for (j=0; j < *av; j++) {
if (v == buffers->mixer->rvoices[j]) {
(*av)--;
/* Pack the array */
if (j < *av)
buffers->mixer->rvoices[j] = buffers->mixer->rvoices[*av];
}
}
if (buffers->mixer->remove_voice_callback)
buffers->mixer->remove_voice_callback(
buffers->mixer->remove_voice_callback_userdata, v);
}
buffers->finished_voice_count = 0;
}
static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice_mixer_t* mixer)
{
#ifdef ENABLE_MIXER_THREADS
int i;
for (i=0; i < mixer->thread_count; i++)
fluid_mixer_buffer_process_finished_voices(&mixer->threads[i]);
#endif
fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
}
static FLUID_INLINE void
fluid_mixer_buffers_render_one(fluid_mixer_buffers_t* buffers,
fluid_rvoice_t* voice, fluid_real_t** bufs,
unsigned int bufcount)
{
int s = fluid_mix_one(voice, bufs, bufcount, buffers->mixer->current_blockcount);
if (s < buffers->mixer->current_blockcount * FLUID_BUFSIZE) {
fluid_finish_rvoice(buffers, voice);
}
}
/*
static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
fluid_rvoice_t* voice)
{
int i, retval=0;
int fvc = buffers->finished_voice_count;
for (i=0; i < fvc; i++)
if (buffers->finished_voices[i] == voice) {
fvc--;
if (i < fvc)
buffers->finished_voices[i] = buffers->finished_voices[fvc];
retval++;
}
fvc = buffers->finished_voice_count;
return retval;
}
*/
int
fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice)
{
int i;
if (mixer->active_voices < mixer->polyphony) {
mixer->rvoices[mixer->active_voices++] = voice;
return FLUID_OK;
}
/* See if any voices just finished, if so, take its place.
This can happen in voice overflow conditions. */
for (i=0; i < mixer->active_voices; i++) {
if (mixer->rvoices[i] == voice) {
FLUID_LOG(FLUID_ERR, "Internal error: Trying to replace an existing rvoice in fluid_rvoice_mixer_add_voice?!");
return FLUID_FAILED;
}
if (mixer->rvoices[i]->envlfo.volenv.section == FLUID_VOICE_ENVFINISHED) {
fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]);
mixer->rvoices[i] = voice;
return FLUID_OK;
}
}
/* This should never happen */
FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
return FLUID_FAILED;
}
static int
fluid_mixer_buffers_update_polyphony(fluid_mixer_buffers_t* buffers, int value)
{
void* newptr;
if (buffers->finished_voice_count > value)
return FLUID_FAILED;
newptr = FLUID_REALLOC(buffers->finished_voices, value * sizeof(fluid_rvoice_t*));
if (newptr == NULL && value > 0)
return FLUID_FAILED;
buffers->finished_voices = newptr;
return FLUID_OK;
}
/**
* Update polyphony - max number of voices (NOTE: not hard real-time capable)
* @return FLUID_OK or FLUID_FAILED
*/
int
fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value)
{
void* newptr;
if (handler->active_voices > value)
return FLUID_FAILED;
newptr = FLUID_REALLOC(handler->rvoices, value * sizeof(fluid_rvoice_t*));
if (newptr == NULL)
return FLUID_FAILED;
handler->rvoices = newptr;
if (fluid_mixer_buffers_update_polyphony(&handler->buffers, value)
== FLUID_FAILED)
return FLUID_FAILED;
#ifdef ENABLE_MIXER_THREADS
{
int i;
for (i=0; i < handler->thread_count; i++)
if (fluid_mixer_buffers_update_polyphony(&handler->threads[i], value)
== FLUID_FAILED)
return FLUID_FAILED;
}
#endif
handler->polyphony = value;
return FLUID_OK;
}
static void
fluid_render_loop_singlethread(fluid_rvoice_mixer_t* mixer)
{
int i;
FLUID_DECLARE_VLA(fluid_real_t*, bufs,
mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
int bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
fluid_profile_ref_var(prof_ref);
for (i=0; i < mixer->active_voices; i++) {
fluid_mixer_buffers_render_one(&mixer->buffers, mixer->rvoices[i], bufs,
bufcount);
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref);
}
}
static FLUID_INLINE void
fluid_mixer_buffers_zero(fluid_mixer_buffers_t* buffers)
{
int i;
int size = buffers->mixer->current_blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t);
/* TODO: Optimize by only zero out the buffers we actually use later on. */
for (i=0; i < buffers->buf_count; i++) {
FLUID_MEMSET(buffers->left_buf[i], 0, size);
FLUID_MEMSET(buffers->right_buf[i], 0, size);
}
for (i=0; i < buffers->fx_buf_count; i++) {
FLUID_MEMSET(buffers->fx_left_buf[i], 0, size);
FLUID_MEMSET(buffers->fx_right_buf[i], 0, size);
}
}
static int
fluid_mixer_buffers_init(fluid_mixer_buffers_t* buffers, fluid_rvoice_mixer_t* mixer)
{
int i, samplecount;
buffers->mixer = mixer;
buffers->buf_count = buffers->mixer->buffers.buf_count;
buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
buffers->buf_blocks = buffers->mixer->buffers.buf_blocks;
samplecount = FLUID_BUFSIZE * buffers->buf_blocks;
/* Left and right audio buffers */
buffers->left_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
buffers->right_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
if ((buffers->left_buf == NULL) || (buffers->right_buf == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return 0;
}
FLUID_MEMSET(buffers->left_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
FLUID_MEMSET(buffers->right_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
for (i = 0; i < buffers->buf_count; i++) {
buffers->left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
buffers->right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
if ((buffers->left_buf[i] == NULL) || (buffers->right_buf[i] == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return 0;
}
}
/* Effects audio buffers */
buffers->fx_left_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
buffers->fx_right_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
if ((buffers->fx_left_buf == NULL) || (buffers->fx_right_buf == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return 0;
}
FLUID_MEMSET(buffers->fx_left_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
FLUID_MEMSET(buffers->fx_right_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
for (i = 0; i < buffers->fx_buf_count; i++) {
buffers->fx_left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
buffers->fx_right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
if ((buffers->fx_left_buf[i] == NULL) || (buffers->fx_right_buf[i] == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return 0;
}
}
buffers->finished_voices = NULL;
if (fluid_mixer_buffers_update_polyphony(buffers, mixer->polyphony)
== FLUID_FAILED) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return 0;
}
return 1;
}
/**
* Note: Not hard real-time capable (calls malloc)
*/
void
fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate)
{
int i;
if (mixer->fx.chorus)
delete_fluid_chorus(mixer->fx.chorus);
mixer->fx.chorus = new_fluid_chorus(samplerate);
if (mixer->fx.reverb)
fluid_revmodel_samplerate_change(mixer->fx.reverb, samplerate);
for (i=0; i < mixer->active_voices; i++)
fluid_rvoice_set_output_rate(mixer->rvoices[i], samplerate);
}
/**
* @param buf_count number of primary stereo buffers
* @param fx_buf_count number of stereo effect buffers
*/
fluid_rvoice_mixer_t*
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate)
{
fluid_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
if (mixer == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
mixer->buffers.buf_count = buf_count;
mixer->buffers.fx_buf_count = fx_buf_count;
mixer->buffers.buf_blocks = FLUID_MIXER_MAX_BUFFERS_DEFAULT;
/* allocate the reverb module */
mixer->fx.reverb = new_fluid_revmodel(sample_rate);
mixer->fx.chorus = new_fluid_chorus(sample_rate);
if (mixer->fx.reverb == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
delete_fluid_rvoice_mixer(mixer);
return NULL;
}
if (!fluid_mixer_buffers_init(&mixer->buffers, mixer)) {
delete_fluid_rvoice_mixer(mixer);
return NULL;
}
#ifdef ENABLE_MIXER_THREADS
mixer->thread_ready = new_fluid_cond();
mixer->wakeup_threads = new_fluid_cond();
mixer->thread_ready_m = new_fluid_cond_mutex();
mixer->wakeup_threads_m = new_fluid_cond_mutex();
if (!mixer->thread_ready || !mixer->wakeup_threads ||
!mixer->thread_ready_m || !mixer->wakeup_threads_m) {
delete_fluid_rvoice_mixer(mixer);
return NULL;
}
#endif
return mixer;
}
static void
fluid_mixer_buffers_free(fluid_mixer_buffers_t* buffers)
{
int i;
FLUID_FREE(buffers->finished_voices);
/* free all the sample buffers */
if (buffers->left_buf != NULL) {
for (i = 0; i < buffers->buf_count; i++) {
if (buffers->left_buf[i] != NULL) {
FLUID_FREE(buffers->left_buf[i]);
}
}
FLUID_FREE(buffers->left_buf);
}
if (buffers->right_buf != NULL) {
for (i = 0; i < buffers->buf_count; i++) {
if (buffers->right_buf[i] != NULL) {
FLUID_FREE(buffers->right_buf[i]);
}
}
FLUID_FREE(buffers->right_buf);
}
if (buffers->fx_left_buf != NULL) {
for (i = 0; i < buffers->fx_buf_count; i++) {
if (buffers->fx_left_buf[i] != NULL) {
FLUID_FREE(buffers->fx_left_buf[i]);
}
}
FLUID_FREE(buffers->fx_left_buf);
}
if (buffers->fx_right_buf != NULL) {
for (i = 0; i < buffers->fx_buf_count; i++) {
if (buffers->fx_right_buf[i] != NULL) {
FLUID_FREE(buffers->fx_right_buf[i]);
}
}
FLUID_FREE(buffers->fx_right_buf);
}
}
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t* mixer)
{
if (!mixer)
return;
fluid_rvoice_mixer_set_threads(mixer, 0, 0);
#ifdef ENABLE_MIXER_THREADS
if (mixer->thread_ready)
delete_fluid_cond(mixer->thread_ready);
if (mixer->wakeup_threads)
delete_fluid_cond(mixer->wakeup_threads);
if (mixer->thread_ready_m)
delete_fluid_cond_mutex(mixer->thread_ready_m);
if (mixer->wakeup_threads_m)
delete_fluid_cond_mutex(mixer->wakeup_threads_m);
#endif
fluid_mixer_buffers_free(&mixer->buffers);
if (mixer->fx.reverb)
delete_fluid_revmodel(mixer->fx.reverb);
if (mixer->fx.chorus)
delete_fluid_chorus(mixer->fx.chorus);
FLUID_FREE(mixer->rvoices);
FLUID_FREE(mixer);
}
#ifdef LADSPA
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
fluid_LADSPA_FxUnit_t* ladspa)
{
mixer->LADSPA_FxUnit = ladspa;
}
#endif
void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on)
{
mixer->fx.with_reverb = on;
}
void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on)
{
mixer->fx.with_chorus = on;
}
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on)
{
mixer->fx.mix_fx_to_out = on;
}
void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
int nr, double level, double speed,
double depth_ms, int type)
{
fluid_chorus_set(mixer->fx.chorus, set, nr, level, speed, depth_ms, type);
}
void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
double roomsize, double damping,
double width, double level)
{
fluid_revmodel_set(mixer->fx.reverb, set, roomsize, damping, width, level);
}
void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer)
{
fluid_revmodel_reset(mixer->fx.reverb);
fluid_chorus_reset(mixer->fx.chorus);
}
void fluid_rvoice_mixer_reset_reverb(fluid_rvoice_mixer_t* mixer)
{
fluid_revmodel_reset(mixer->fx.reverb);
}
void fluid_rvoice_mixer_reset_chorus(fluid_rvoice_mixer_t* mixer)
{
fluid_chorus_reset(mixer->fx.chorus);
}
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
fluid_real_t*** left, fluid_real_t*** right)
{
*left = mixer->buffers.left_buf;
*right = mixer->buffers.right_buf;
return mixer->buffers.buf_count;
}
#ifdef ENABLE_MIXER_THREADS
static FLUID_INLINE fluid_rvoice_t*
fluid_mixer_get_mt_rvoice(fluid_rvoice_mixer_t* mixer)
{
int i = fluid_atomic_int_exchange_and_add(&mixer->current_rvoice, 1);
if (i >= mixer->active_voices)
return NULL;
return mixer->rvoices[i];
}
#define THREAD_BUF_PROCESSING 0
#define THREAD_BUF_VALID 1
#define THREAD_BUF_NODATA 2
#define THREAD_BUF_TERMINATE 3
/* Core thread function (processes voices in parallel to primary synthesis thread) */
static void
fluid_mixer_thread_func (void* data)
{
fluid_mixer_buffers_t* buffers = data;
fluid_rvoice_mixer_t* mixer = buffers->mixer;
int hasValidData = 0;
FLUID_DECLARE_VLA(fluid_real_t*, bufs, buffers->buf_count*2 + buffers->fx_buf_count*2);
int bufcount = 0;
while (!fluid_atomic_int_get(&mixer->threads_should_terminate)) {
fluid_rvoice_t* rvoice = fluid_mixer_get_mt_rvoice(mixer);
if (rvoice == NULL) {
// if no voices: signal rendered buffers, sleep
fluid_atomic_int_set(&buffers->ready, hasValidData ? THREAD_BUF_VALID : THREAD_BUF_NODATA);
fluid_cond_mutex_lock(mixer->thread_ready_m);
fluid_cond_signal(mixer->thread_ready);
fluid_cond_mutex_unlock(mixer->thread_ready_m);
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
while (1) {
int j = fluid_atomic_int_get(&buffers->ready);
if (j == THREAD_BUF_PROCESSING || j == THREAD_BUF_TERMINATE)
break;
fluid_cond_wait(mixer->wakeup_threads, mixer->wakeup_threads_m);
}
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
hasValidData = 0;
}
else {
// else: if buffer is not zeroed, zero buffers
if (!hasValidData) {
fluid_mixer_buffers_zero(buffers);
bufcount = fluid_mixer_buffers_prepare(buffers, bufs);
hasValidData = 1;
}
// then render voice to buffers
fluid_mixer_buffers_render_one(buffers, rvoice, bufs, bufcount);
}
}
}
static void
fluid_mixer_buffers_mix(fluid_mixer_buffers_t* dest, fluid_mixer_buffers_t* src)
{
int i,j;
int scount = dest->mixer->current_blockcount * FLUID_BUFSIZE;
int minbuf;
minbuf = dest->buf_count;
if (minbuf > src->buf_count)
minbuf = src->buf_count;
for (i=0; i < minbuf; i++) {
for (j=0; j < scount; j++) {
dest->left_buf[i][j] += src->left_buf[i][j];
dest->right_buf[i][j] += src->right_buf[i][j];
}
}
minbuf = dest->fx_buf_count;
if (minbuf > src->fx_buf_count)
minbuf = src->fx_buf_count;
for (i=0; i < minbuf; i++) {
for (j=0; j < scount; j++) {
dest->fx_left_buf[i][j] += src->fx_left_buf[i][j];
dest->fx_right_buf[i][j] += src->fx_right_buf[i][j];
}
}
}
/**
* Go through all threads and see if someone is finished for mixing
*/
static FLUID_INLINE int
fluid_mixer_mix_in(fluid_rvoice_mixer_t* mixer, int extra_threads)
{
int i, result, hasmixed;
do {
hasmixed = 0;
result = 0;
for (i=0; i < extra_threads; i++) {
int j = fluid_atomic_int_get(&mixer->threads[i].ready);
switch (j) {
case THREAD_BUF_PROCESSING:
result = 1;
break;
case THREAD_BUF_VALID:
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_NODATA);
fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i]);
hasmixed = 1;
break;
}
}
} while (hasmixed);
return result;
}
static void
fluid_render_loop_multithread(fluid_rvoice_mixer_t* mixer)
{
int i, bufcount;
//int scount = mixer->current_blockcount * FLUID_BUFSIZE;
FLUID_DECLARE_VLA(fluid_real_t*, bufs,
mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
// How many threads should we start this time?
int extra_threads = mixer->active_voices / VOICES_PER_THREAD;
if (extra_threads > mixer->thread_count)
extra_threads = mixer->thread_count;
if (extra_threads == 0) {
// No extra threads? No thread overhead!
fluid_render_loop_singlethread(mixer);
return;
}
bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
// Prepare voice list
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
fluid_atomic_int_set(&mixer->current_rvoice, 0);
for (i=0; i < extra_threads; i++)
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_PROCESSING);
// Signal threads to wake up
fluid_cond_broadcast(mixer->wakeup_threads);
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
// If thread is finished, mix it in
while (fluid_mixer_mix_in(mixer, extra_threads)) {
// Otherwise get a voice and render it
fluid_rvoice_t* rvoice = fluid_mixer_get_mt_rvoice(mixer);
if (rvoice != NULL) {
fluid_profile_ref_var(prof_ref);
fluid_mixer_buffers_render_one(&mixer->buffers, rvoice, bufs, bufcount);
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref);
//test++;
}
else {
// If no voices, wait for mixes. Make sure one is still processing to avoid deadlock
int is_processing = 0;
//waits++;
fluid_cond_mutex_lock(mixer->thread_ready_m);
for (i=0; i < extra_threads; i++)
if (fluid_atomic_int_get(&mixer->threads[i].ready) ==
THREAD_BUF_PROCESSING)
is_processing = 1;
if (is_processing)
fluid_cond_wait(mixer->thread_ready, mixer->thread_ready_m);
fluid_cond_mutex_unlock(mixer->thread_ready_m);
}
}
//FLUID_LOG(FLUID_DBG, "Blockcount: %d, mixed %d of %d voices myself, waits = %d",
// mixer->current_blockcount, test, mixer->active_voices, waits);
}
#endif
/**
* Update amount of extra mixer threads.
* @param thread_count Number of extra mixer threads for multi-core rendering
* @param prio_level real-time prio level for the extra mixer threads
*/
void
fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count,
int prio_level)
{
#ifdef ENABLE_MIXER_THREADS
char name[16];
int i;
// Kill all existing threads first
if (mixer->thread_count) {
fluid_atomic_int_set(&mixer->threads_should_terminate, 1);
// Signal threads to wake up
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
for (i=0; i < mixer->thread_count; i++)
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE);
fluid_cond_broadcast(mixer->wakeup_threads);
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
for (i=0; i < mixer->thread_count; i++) {
if (mixer->threads[i].thread) {
fluid_thread_join(mixer->threads[i].thread);
delete_fluid_thread(mixer->threads[i].thread);
}
fluid_mixer_buffers_free(&mixer->threads[i]);
}
FLUID_FREE(mixer->threads);
mixer->thread_count = 0;
mixer->threads = NULL;
}
if (thread_count == 0)
return;
// Now prepare the new threads
fluid_atomic_int_set(&mixer->threads_should_terminate, 0);
mixer->threads = FLUID_ARRAY(fluid_mixer_buffers_t, thread_count);
if (mixer->threads == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return;
}
FLUID_MEMSET(mixer->threads, 0, thread_count*sizeof(fluid_mixer_buffers_t));
mixer->thread_count = thread_count;
for (i=0; i < thread_count; i++) {
fluid_mixer_buffers_t* b = &mixer->threads[i];
if (!fluid_mixer_buffers_init(b, mixer))
return;
fluid_atomic_int_set(&b->ready, THREAD_BUF_NODATA);
g_snprintf (name, sizeof (name), "mixer%d", i);
b->thread = new_fluid_thread(name, fluid_mixer_thread_func, b, prio_level, 0);
if (!b->thread)
return;
}
#endif
}
/**
* Synthesize audio into buffers
* @param blockcount number of blocks to render, each having FLUID_BUFSIZE samples
* @return number of blocks rendered
*/
int
fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
{
fluid_profile_ref_var(prof_ref);
mixer->current_blockcount = blockcount > mixer->buffers.buf_blocks ?
mixer->buffers.buf_blocks : blockcount;
// Zero buffers
fluid_mixer_buffers_zero(&mixer->buffers);
fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref);
#ifdef ENABLE_MIXER_THREADS
if (mixer->thread_count > 0)
fluid_render_loop_multithread(mixer);
else
#endif
fluid_render_loop_singlethread(mixer);
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref);
// Process reverb & chorus
fluid_rvoice_mixer_process_fx(mixer);
// Call the callback and pack active voice array
fluid_rvoice_mixer_process_finished_voices(mixer);
return mixer->current_blockcount;
}

View File

@ -0,0 +1,74 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_RVOICE_MIXER_H
#define _FLUID_RVOICE_MIXER_H
#include "fluidsynth_priv.h"
#include "fluid_rvoice.h"
//#include "fluid_ladspa.h"
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE)
void fluid_rvoice_mixer_set_finished_voices_callback(
fluid_rvoice_mixer_t* mixer,
void (*func)(void*, fluid_rvoice_t*),
void* userdata);
int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount);
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
fluid_real_t*** left, fluid_real_t*** right);
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count,
fluid_real_t sample_rate);
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
void fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate);
void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on);
void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on);
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on);
int fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value);
int fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice);
void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
int nr, double level, double speed,
double depth_ms, int type);
void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
double roomsize, double damping,
double width, double level);
void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer);
void fluid_rvoice_mixer_reset_reverb(fluid_rvoice_mixer_t* mixer);
void fluid_rvoice_mixer_reset_chorus(fluid_rvoice_mixer_t* mixer);
void fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count,
int prio_level);
#ifdef LADSPA
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
fluid_LADSPA_FxUnit_t* ladspa);
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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, const char* name, const char* s);
/** returns 1 if the option was added, 0 otherwise */
int fluid_settings_remove_option(fluid_settings_t* settings, const char* name, const char* s);
typedef int (*fluid_num_update_t)(void* data, const char* name, double value);
typedef int (*fluid_str_update_t)(void* data, const char* name, const char* value);
typedef int (*fluid_int_update_t)(void* data, const char* name, int value);
/** returns 0 if the value has been registered 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 registered correctly, non-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);
/** returns 0 if the value has been registered correctly, non-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);
#endif /* _FLUID_SETTINGS_H */

View File

@ -0,0 +1,68 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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 */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_SYNTH_H
#define _FLUID_SYNTH_H
/***************************************************************
*
* INCLUDES
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "fluidsynth_priv.h"
#include "fluid_event_queue.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"
#include "fluid_rvoice_event.h"
/***************************************************************
*
* DEFINES
*/
#define FLUID_NUM_PROGRAMS 128
#define DRUM_INST_BANK 128
#define FLUID_UNSET_PROGRAM 128 /* Program number used to unset a preset */
#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
};*/
/**
* Bank Select MIDI message styles. Default style is GS.
*/
enum fluid_midi_bank_select
{
FLUID_BANK_STYLE_GM, /**< GM style, bank = 0 always (CC0/MSB and CC32/LSB ignored) */
FLUID_BANK_STYLE_GS, /**< GS style, bank = CC0/MSB (CC32/LSB ignored) */
FLUID_BANK_STYLE_XG, /**< XG style, bank = CC32/LSB (CC0/MSB ignored) */
FLUID_BANK_STYLE_MMA /**< MMA style bank = 128*MSB+LSB */
};
enum fluid_synth_status
{
FLUID_SYNTH_CLEAN,
FLUID_SYNTH_PLAYING,
FLUID_SYNTH_QUIET,
FLUID_SYNTH_STOPPED
};
#define SYNTH_REVERB_CHANNEL 0
#define SYNTH_CHORUS_CHANNEL 1
/**
* Structure used for sfont_info field in #fluid_synth_t for each loaded
* SoundFont with the SoundFont instance and additional fields.
*/
typedef struct _fluid_sfont_info_t {
fluid_sfont_t *sfont; /**< Loaded SoundFont */
fluid_synth_t *synth; /**< Parent synth */
int refcount; /**< SoundFont reference count (0 if no presets referencing it) */
int bankofs; /**< Bank offset */
} fluid_sfont_info_t;
/*
* fluid_synth_t
*
* Mutual exclusion notes (as of 1.1.2):
*
* All variables are considered belongning to the "public API" thread,
* which processes all MIDI, except for:
*
* ticks_since_start - atomic, set by rendering thread only
* cpu_load - atomic, set by rendering thread only
* cur, curmax, dither_index - used by rendering thread only
* LADSPA_FxUnit - same instance copied in rendering thread. Synchronising handled internally (I think...?).
*
*/
struct _fluid_synth_t
{
fluid_rec_mutex_t mutex; /**< Lock for public API */
int use_mutex; /**< Use mutex for all public API functions? */
int public_api_count; /**< How many times the mutex is currently locked */
fluid_settings_t* settings; /**< the synthesizer settings */
int device_id; /**< Device ID used for SYSEX messages */
int polyphony; /**< Maximum polyphony */
int with_reverb; /**< Should the synth use the built-in reverb unit? */
int with_chorus; /**< Should the synth use the built-in chorus unit? */
int verbose; /**< Turn verbose mode on? */
int 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 bank_select; /**< the style of Bank Select MIDI messages */
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) */
int state; /**< the synthesizer state */
unsigned int ticks_since_start; /**< the number of audio samples since the start */
unsigned int start; /**< the start in msec, as returned by system clock */
fluid_overflow_prio_t overflow; /**< parameters for overflow priority (aka voice-stealing) */
fluid_list_t *loaders; /**< the SoundFont loaders */
fluid_list_t *sfont_info; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
fluid_hashtable_t *sfont_hash; /**< Hash of fluid_sfont_t->fluid_sfont_info_t (remains until SoundFont is deleted) */
unsigned int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
float gain; /**< master gain */
fluid_channel_t** channel; /**< the channels */
int nvoice; /**< the length of the synthesis process array (max polyphony allowed) */
fluid_voice_t** voice; /**< the synthesis voices */
int active_voice_count; /**< count of active voices */
unsigned int noteid; /**< the id is incremented for every new note. it's used for noteoff's */
unsigned int storeid;
fluid_rvoice_eventhandler_t* eventhandler;
float reverb_roomsize; /**< Shadow of reverb roomsize */
float reverb_damping; /**< Shadow of reverb damping */
float reverb_width; /**< Shadow of reverb width */
float reverb_level; /**< Shadow of reverb level */
int chorus_nr; /**< Shadow of chorus number */
float chorus_level; /**< Shadow of chorus level */
float chorus_speed; /**< Shadow of chorus speed */
float chorus_depth; /**< Shadow of chorus depth */
int chorus_type; /**< Shadow of chorus type */
int cur; /**< the current sample in the audio buffers to be output */
int curmax; /**< current amount of samples present in the audio buffers */
int dither_index; /**< current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
char outbuf[256]; /**< buffer for message output */
float cpu_load; /**< CPU load in percent (CPU time required / audio synthesized time * 100) */
fluid_tuning_t*** tuning; /**< 128 banks of 128 programs for the tunings */
fluid_private_t tuning_iter; /**< Tuning iterators per each thread */
fluid_midi_router_t* midi_router; /**< The midi router. Could be done nicer. */
fluid_sample_timer_t* sample_timers; /**< List of timers triggered before a block is processed */
unsigned int min_note_length_ticks; /**< If note-offs are triggered just after a note-on, they will be delayed */
int cores; /**< Number of CPU cores (1 by default) */
#ifdef LADSPA
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Effects unit for LADSPA support */
#endif
};
int fluid_synth_setstr(fluid_synth_t* synth, const char* name, const char* str);
int fluid_synth_dupstr(fluid_synth_t* synth, const char* name, char** str);
int fluid_synth_setnum(fluid_synth_t* synth, const char* name, double val);
int fluid_synth_getnum(fluid_synth_t* synth, const char* name, double* val);
int fluid_synth_setint(fluid_synth_t* synth, const char* name, int val);
int fluid_synth_getint(fluid_synth_t* synth, const char* name, int* val);
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
unsigned int banknum,
unsigned int prognum);
void fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont);
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_kill_voice(fluid_synth_t* synth, fluid_voice_t * voice);
void fluid_synth_print_voice(fluid_synth_t* synth);
void fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
void* lout, int loff, int lincr,
void* rout, int roff, int rincr);
int fluid_synth_reset_reverb(fluid_synth_t* synth);
int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num);
int fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
double damping, double width, double level);
int fluid_synth_reset_chorus(fluid_synth_t* synth);
int fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
double speed, double depth_ms, int type);
fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data);
int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer);
void fluid_synth_api_enter(fluid_synth_t* synth);
void fluid_synth_api_exit(fluid_synth_t* synth);
void fluid_synth_process_event_queue(fluid_synth_t* synth);
/*
* misc
*/
void fluid_synth_settings(fluid_settings_t* settings);
#endif /* _FLUID_SYNTH_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,448 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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 <glib.h>
#include "fluidsynth_priv.h"
/**
* Macro used for safely accessing a message from a GError and using a default
* message if it is NULL.
* @param err Pointer to a GError to access the message field of.
* @return Message string
*/
#define fluid_gerror_message(err) ((err) ? err->message : "No error details")
void fluid_sys_config(void);
void fluid_log_config(void);
void fluid_time_config(void);
/* Misc */
#define fluid_return_val_if_fail g_return_val_if_fail
#define fluid_return_if_fail g_return_if_fail
#define FLUID_INLINE inline
#define FLUID_POINTER_TO_UINT GPOINTER_TO_UINT
#define FLUID_UINT_TO_POINTER GUINT_TO_POINTER
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
#define FLUID_N_ELEMENTS(struct) (sizeof (struct) / sizeof (struct[0]))
#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)
/*
* Utility functions
*/
char *fluid_strtok (char **str, char *delim);
/**
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
#if defined(__OS2__)
#define INCL_DOS
#include <os2.h>
typedef int socklen_t;
#endif
unsigned int fluid_curtime(void);
double fluid_utime(void);
/**
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 high_priority);
int delete_fluid_timer(fluid_timer_t* timer);
int fluid_timer_join(fluid_timer_t* timer);
int fluid_timer_stop(fluid_timer_t* timer);
// Macros to use for pre-processor if statements to test which Glib thread API we have (pre or post 2.32)
#define NEW_GLIB_THREAD_API (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 32))
#define OLD_GLIB_THREAD_API (GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 32))
/* Muteces */
#if NEW_GLIB_THREAD_API
/* glib 2.32 and newer */
/* Regular mutex */
typedef GMutex fluid_mutex_t;
#define FLUID_MUTEX_INIT { 0 }
#define fluid_mutex_init(_m) g_mutex_init (&(_m))
#define fluid_mutex_destroy(_m) g_mutex_clear (&(_m))
#define fluid_mutex_lock(_m) g_mutex_lock(&(_m))
#define fluid_mutex_unlock(_m) g_mutex_unlock(&(_m))
/* Recursive lock capable mutex */
typedef GRecMutex fluid_rec_mutex_t;
#define fluid_rec_mutex_init(_m) g_rec_mutex_init(&(_m))
#define fluid_rec_mutex_destroy(_m) g_rec_mutex_clear(&(_m))
#define fluid_rec_mutex_lock(_m) g_rec_mutex_lock(&(_m))
#define fluid_rec_mutex_unlock(_m) g_rec_mutex_unlock(&(_m))
/* Dynamically allocated mutex suitable for fluid_cond_t use */
typedef GMutex fluid_cond_mutex_t;
#define fluid_cond_mutex_lock(m) g_mutex_lock(m)
#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)
static FLUID_INLINE fluid_cond_mutex_t *
new_fluid_cond_mutex (void)
{
GMutex *mutex;
mutex = g_new (GMutex, 1);
g_mutex_init (mutex);
return (mutex);
}
static FLUID_INLINE void
delete_fluid_cond_mutex (fluid_cond_mutex_t *m)
{
g_mutex_clear (m);
g_free (m);
}
/* Thread condition signaling */
typedef GCond fluid_cond_t;
#define fluid_cond_signal(cond) g_cond_signal(cond)
#define fluid_cond_broadcast(cond) g_cond_broadcast(cond)
#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex)
static FLUID_INLINE fluid_cond_t *
new_fluid_cond (void)
{
GCond *cond;
cond = g_new (GCond, 1);
g_cond_init (cond);
return (cond);
}
static FLUID_INLINE void
delete_fluid_cond (fluid_cond_t *cond)
{
g_cond_clear (cond);
g_free (cond);
}
/* Thread private data */
typedef GPrivate fluid_private_t;
#define fluid_private_init(_priv) memset (&_priv, 0, sizeof (_priv))
#define fluid_private_free(_priv)
#define fluid_private_get(_priv) g_private_get(&(_priv))
#define fluid_private_set(_priv, _data) g_private_set(&(_priv), _data)
#else
/* glib prior to 2.32 */
/* Regular mutex */
typedef GStaticMutex fluid_mutex_t;
#define FLUID_MUTEX_INIT G_STATIC_MUTEX_INIT
#define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m))
#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))
#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m))
#define fluid_mutex_init(_m) G_STMT_START { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_mutex_init (&(_m)); \
} G_STMT_END;
/* Recursive lock capable mutex */
typedef GStaticRecMutex fluid_rec_mutex_t;
#define fluid_rec_mutex_destroy(_m) g_static_rec_mutex_free(&(_m))
#define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))
#define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))
#define fluid_rec_mutex_init(_m) G_STMT_START { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_rec_mutex_init (&(_m)); \
} G_STMT_END;
/* Dynamically allocated mutex suitable for fluid_cond_t use */
typedef GMutex fluid_cond_mutex_t;
#define delete_fluid_cond_mutex(m) g_mutex_free(m)
#define fluid_cond_mutex_lock(m) g_mutex_lock(m)
#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)
static FLUID_INLINE fluid_cond_mutex_t *
new_fluid_cond_mutex (void)
{
if (!g_thread_supported ()) g_thread_init (NULL);
return g_mutex_new ();
}
/* Thread condition signaling */
typedef GCond fluid_cond_t;
fluid_cond_t *new_fluid_cond (void);
#define delete_fluid_cond(cond) g_cond_free(cond)
#define fluid_cond_signal(cond) g_cond_signal(cond)
#define fluid_cond_broadcast(cond) g_cond_broadcast(cond)
#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex)
/* Thread private data */
typedef GStaticPrivate fluid_private_t;
#define fluid_private_get(_priv) g_static_private_get(&(_priv))
#define fluid_private_set(_priv, _data) g_static_private_set(&(_priv), _data, NULL)
#define fluid_private_free(_priv) g_static_private_free(&(_priv))
#define fluid_private_init(_priv) G_STMT_START { \
if (!g_thread_supported ()) g_thread_init (NULL); \
g_static_private_init (&(_priv)); \
} G_STMT_END;
#endif
/* Atomic operations */
#define fluid_atomic_int_inc(_pi) g_atomic_int_inc(_pi)
#define fluid_atomic_int_add(_pi, _val) g_atomic_int_add(_pi, _val)
#define fluid_atomic_int_get(_pi) g_atomic_int_get(_pi)
#define fluid_atomic_int_set(_pi, _val) g_atomic_int_set(_pi, _val)
#define fluid_atomic_int_dec_and_test(_pi) g_atomic_int_dec_and_test(_pi)
#define fluid_atomic_int_compare_and_exchange(_pi, _old, _new) \
g_atomic_int_compare_and_exchange(_pi, _old, _new)
#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 30)
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
g_atomic_int_add(_pi, _add)
#else
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
g_atomic_int_exchange_and_add(_pi, _add)
#endif
#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp)
#define fluid_atomic_pointer_set(_pp, val) g_atomic_pointer_set(_pp, val)
#define fluid_atomic_pointer_compare_and_exchange(_pp, _old, _new) \
g_atomic_pointer_compare_and_exchange(_pp, _old, _new)
static FLUID_INLINE void
fluid_atomic_float_set(volatile float *fptr, float val)
{
sint32 ival;
memcpy (&ival, &val, 4);
fluid_atomic_int_set ((volatile int *)fptr, ival);
}
static FLUID_INLINE float
fluid_atomic_float_get(volatile float *fptr)
{
sint32 ival;
float fval;
ival = fluid_atomic_int_get ((volatile int *)fptr);
memcpy (&fval, &ival, 4);
return fval;
}
/* Threads */
typedef GThread fluid_thread_t;
typedef void (*fluid_thread_func_t)(void* data);
#define FLUID_THREAD_ID_NULL NULL /* A NULL "ID" value */
#define fluid_thread_id_t GThread * /* Data type for a thread ID */
#define fluid_thread_get_id() g_thread_self() /* Get unique "ID" for current thread */
fluid_thread_t* new_fluid_thread(const char *name, fluid_thread_func_t func, void *data,
int prio_level, int detach);
void delete_fluid_thread(fluid_thread_t* thread);
void fluid_thread_self_set_prio (int prio_level);
int fluid_thread_join(fluid_thread_t* thread);
/* Sockets and I/O */
fluid_istream_t fluid_get_stdin (void);
fluid_ostream_t fluid_get_stdout (void);
int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char* prompt, char* buf, int len);
int fluid_ostream_printf (fluid_ostream_t out, char* format, ...);
/* 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);
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,
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 create a variable and assign the current reference time for profiling.
* So we don't get unused variable warnings when profiling is disabled. */
#define fluid_profile_ref_var(name) double name = 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_ref_var(name)
#define fluid_profile(_num,_ref)
#endif
/**
Memory locking
Memory locking is used to avoid swapping of the large block of
sample data.
*/
#if defined(HAVE_SYS_MMAN_H) && !defined(__OS2__)
#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.
*/
#ifdef FPE_CHECK
#define fluid_check_fpe(expl) fluid_check_fpe_i386(expl)
#define fluid_clear_fpe() fluid_clear_fpe_i386()
#else
#define fluid_check_fpe(expl)
#define fluid_clear_fpe()
#endif
unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe);
void fluid_clear_fpe_i386(void);
#endif /* _FLUID_SYS_H */

View File

@ -0,0 +1,174 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_tuning.h"
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
fluid_tuning_t* new_fluid_tuning(const 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;
}
tuning->refcount = 1; /* Start with a refcount of 1 */
return tuning;
}
/* Duplicate a tuning */
fluid_tuning_t *
fluid_tuning_duplicate (fluid_tuning_t *tuning)
{
fluid_tuning_t *new_tuning;
int i;
new_tuning = FLUID_NEW (fluid_tuning_t);
if (!new_tuning) {
FLUID_LOG (FLUID_PANIC, "Out of memory");
return NULL;
}
if (tuning->name)
{
new_tuning->name = FLUID_STRDUP (tuning->name);
if (!new_tuning->name)
{
FLUID_FREE (new_tuning);
FLUID_LOG (FLUID_PANIC, "Out of memory");
return NULL;
}
}
else new_tuning->name = NULL;
new_tuning->bank = tuning->bank;
new_tuning->prog = tuning->prog;
for (i = 0; i < 128; i++)
new_tuning->pitch[i] = tuning->pitch[i];
new_tuning->refcount = 1; /* Start with a refcount of 1 */
return new_tuning;
}
void
delete_fluid_tuning (fluid_tuning_t *tuning)
{
if (tuning->name) FLUID_FREE (tuning->name);
FLUID_FREE (tuning);
}
/* Add a reference to a tuning object */
void
fluid_tuning_ref (fluid_tuning_t *tuning)
{
fluid_return_if_fail (tuning != NULL);
fluid_atomic_int_inc (&tuning->refcount);
}
/* Unref a tuning object, when it reaches 0 it is deleted, returns TRUE if deleted */
int
fluid_tuning_unref (fluid_tuning_t *tuning, int count)
{
fluid_return_val_if_fail (tuning != NULL, FALSE);
/* Add and compare are separate, but that is OK, since refcount will only
* reach 0 when there are no references and therefore no possibility of
* another thread adding a reference in between */
fluid_atomic_int_add (&tuning->refcount, -count);
/* Delete when refcount reaches 0 */
if (!fluid_atomic_int_get (&tuning->refcount))
{
delete_fluid_tuning (tuning);
return TRUE;
}
else return FALSE;
}
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;
}
static 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, const 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, const 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;
}
}

View File

@ -0,0 +1,68 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, 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 */
int refcount; /* Tuning reference count */
};
fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog);
void delete_fluid_tuning (fluid_tuning_t *tuning);
fluid_tuning_t *fluid_tuning_duplicate (fluid_tuning_t *tuning);
void fluid_tuning_ref (fluid_tuning_t *tuning);
int fluid_tuning_unref (fluid_tuning_t *tuning, int count);
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, const double* pitch_deriv);
void fluid_tuning_set_all(fluid_tuning_t* tuning, const 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

View File

@ -0,0 +1,228 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_VOICE_H
#define _FLUID_VOICE_H
#include "fluid_phase.h"
#include "fluid_gen.h"
#include "fluid_mod.h"
#include "fluid_iir_filter.h"
#include "fluid_adsr_env.h"
#include "fluid_lfo.h"
#include "fluid_rvoice.h"
#include "fluid_sys.h"
#define NO_CHANNEL 0xff
typedef struct _fluid_overflow_prio_t fluid_overflow_prio_t;
struct _fluid_overflow_prio_t
{
fluid_real_t percussion; /**< Is this voice on the drum channel? Then add this score */
fluid_real_t released; /**< Is this voice in release stage? Then add this score (usually negative) */
fluid_real_t sustained; /**< Is this voice sustained? Then add this score (usually negative) */
fluid_real_t volume; /**< Multiply current (or future) volume (a value between 0 and 1) */
fluid_real_t age; /**< This score will be divided by the number of seconds the voice has lasted */
};
enum fluid_voice_status
{
FLUID_VOICE_CLEAN,
FLUID_VOICE_ON,
FLUID_VOICE_SUSTAINED, /* Sustained by Sustain pedal */
FLUID_VOICE_HELD_BY_SOSTENUTO, /* Sustained by Sostenuto pedal */
FLUID_VOICE_OFF
};
/*
* 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 access 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;
fluid_sample_t* sample; /* Pointer to sample (dupe in rvoice) */
int has_noteoff; /* Flag set when noteoff has been sent */
/* basic parameters */
fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
unsigned int start_time;
fluid_adsr_env_t volenv; /* Volume envelope (dupe in rvoice) */
/* basic parameters */
fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
fluid_real_t root_pitch;
/* master gain (dupe in rvoice) */
fluid_real_t synth_gain;
/* 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;
/* rvoice control */
fluid_rvoice_t* rvoice;
fluid_rvoice_t* overflow_rvoice; /* Used temporarily and only in overflow situations */
int can_access_rvoice; /* False if rvoice is being rendered in separate thread */
int can_access_overflow_rvoice; /* False if overflow_rvoice is being rendered in separate thread */
/* 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);
void fluid_voice_calculate_gen_pitch(fluid_voice_t* voice);
int fluid_voice_write (fluid_voice_t* voice, fluid_real_t *dsp_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);
int fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value);
/** 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);
/** fluid_voice_release
Force the voice into release stage. Usefuf anywhere a voice
needs to be damped even if pedals (sustain sostenuto) are depressed.
See fluid_synth_damp_voices_LOCAL(), fluid_synth_damp_voices_by_sostenuto_LOCAL,
fluid_voice_noteoff(), fluid_synth_stop_LOCAL().
*/
void fluid_voice_release(fluid_voice_t* voice);
int fluid_voice_noteoff(fluid_voice_t* voice);
int fluid_voice_off(fluid_voice_t* voice);
void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice);
void fluid_voice_mix (fluid_voice_t *voice, int count, fluid_real_t* dsp_buf,
fluid_real_t* left_buf, fluid_real_t* right_buf,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
int fluid_voice_kill_excl(fluid_voice_t* voice);
fluid_real_t fluid_voice_get_overflow_prio(fluid_voice_t* voice,
fluid_overflow_prio_t* score,
unsigned int cur_time);
#define OVERFLOW_PRIO_CANNOT_KILL 999999.
/**
* Locks the rvoice for rendering, so it can't be modified directly
*/
static FLUID_INLINE fluid_rvoice_t*
fluid_voice_lock_rvoice(fluid_voice_t* voice)
{
voice->can_access_rvoice = 0;
return voice->rvoice;
}
/**
* Unlocks the rvoice for rendering, so it can be modified directly
*/
static FLUID_INLINE void
fluid_voice_unlock_rvoice(fluid_voice_t* voice)
{
voice->can_access_rvoice = 1;
}
#define fluid_voice_get_channel(voice) ((voice)->channel)
#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) || \
_SUSTAINED(voice) || \
_HELD_BY_SOSTENUTO(voice) )
/* 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->has_noteoff)
#define _SUSTAINED(voice) ((voice)->status == FLUID_VOICE_SUSTAINED)
#define _HELD_BY_SOSTENUTO(voice) ((voice)->status == FLUID_VOICE_HELD_BY_SOSTENUTO)
#define _AVAILABLE(voice) ((voice)->can_access_rvoice && \
(((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)
/* FIXME - This doesn't seem to be used anywhere - JG */
fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
#define fluid_voice_get_loudness(voice) (fluid_adsr_env_get_max_val(&voice->volenv))
#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)
/* defined in fluid_dsp_float.c */
void fluid_dsp_float_config (void);
int fluid_dsp_float_interpolate_none (fluid_voice_t *voice);
int fluid_dsp_float_interpolate_linear (fluid_voice_t *voice);
int fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice);
int fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice);
#endif /* _FLUID_VOICE_H */

View File

@ -0,0 +1,267 @@
/* 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
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_PRIV_H
#define _FLUIDSYNTH_PRIV_H
#include <glib.h>
#if HAVE_CONFIG_H
#include "config.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 <winsock2.h>
#include <ws2tcpip.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
#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
#if defined(WIN32)
typedef SOCKET fluid_socket_t;
#else
typedef int fluid_socket_t;
#define INVALID_SOCKET -1
#endif
#if defined(SUPPORTS_VLA)
# define FLUID_DECLARE_VLA(_type, _name, _len) \
_type _name[_len]
#else
# define FLUID_DECLARE_VLA(_type, _name, _len) \
_type* _name = g_newa(_type, (_len))
#endif
/** Integer types */
//typedef gint8 sint8;
typedef guint8 uint8;
//typedef gint16 sint16;
//typedef guint16 uint16;
typedef gint32 sint32;
typedef guint32 uint32;
//typedef gint64 sint64;
//typedef guint64 uint64;
/***************************************************************
*
* 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;
typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
/***************************************************************
*
* CONSTANTS
*/
#define FLUID_BUFSIZE 64 /**< FluidSynth internal buffer size (in samples) */
#define FLUID_MAX_EVENTS_PER_BUFSIZE 1024 /**< Maximum queued MIDI events per #FLUID_BUFSIZE */
#define FLUID_MAX_RETURN_EVENTS 1024 /**< Maximum queued synthesis thread return events */
#define FLUID_MAX_EVENT_QUEUES 16 /**< Maximum number of unique threads queuing events */
#define FLUID_DEFAULT_AUDIO_RT_PRIO 60 /**< Default setting for audio.realtime-prio */
#define FLUID_DEFAULT_MIDI_RT_PRIO 50 /**< Default setting for midi.realtime-prio */
#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_STRNCPY(_dst,_src,_n) strncpy(_dst,_src,_n)
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
#define FLUID_STRRCHR(_s,_c) strrchr(_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)); }
#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 */

79
libs/fluidsynth/wscript Normal file
View File

@ -0,0 +1,79 @@
#!/usr/bin/env python
from waflib.extras import autowaf as autowaf
from waflib import TaskGen
import os
import sys
# Version of this package (even if built as a child)
MAJOR = '1'
MINOR = '6'
MICRO = '0'
LIBFLUIDSYNTH_VERSION = "%s.%s.%s" % (MAJOR, MINOR, MICRO)
# Library version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
LIBLTC_LIB_VERSION = '1.1.1'
# Variables for 'waf dist'
APPNAME = 'libltc'
VERSION = LIBFLUIDSYNTH_VERSION
I18N_PACKAGE = 'libfluidsynth'
# Mandatory variables
top = '.'
out = 'build'
def options(opt):
autowaf.set_options(opt)
def configure(conf):
if conf.is_defined('USE_EXTERNAL_LIBS'):
autowaf.check_pkg(conf, 'fluidsynth', uselib_store='LIBFLUIDSYNTH', atleast_version=LIBFLUIDSYNTH_LIB_VERSION, mandatory=True)
else:
conf.load('compiler_c')
autowaf.configure(conf)
def build(bld):
if bld.is_defined('USE_EXTERNAL_LIBS'):
return
bld (export_includes = ['fluidsynth'],
name = 'libfluidsynth_includes'
)
bld.stlib (source = [
'src/fluid_midi.c',
'src/fluid_adsr_env.c',
'src/fluid_chorus.c',
'src/fluid_iir_filter.c',
'src/fluid_lfo.c',
'src/fluid_rev.c',
'src/fluid_rvoice.c',
'src/fluid_rvoice_dsp.c',
'src/fluid_rvoice_event.c',
'src/fluid_rvoice_mixer.c',
'src/fluid_defsfont.c',
'src/fluid_chan.c',
'src/fluid_event.c',
'src/fluid_gen.c',
'src/fluid_mod.c',
'src/fluid_synth.c',
'src/fluid_tuning.c',
'src/fluid_voice.c',
'src/fluid_conv.c',
'src/fluid_hash.c',
'src/fluid_list.c',
'src/fluid_ringbuffer.c',
'src/fluid_settings.c',
'src/fluid_sys.c'
],
cflags = [ '-fPIC', '-fvisibility=hidden' ],
includes = ['.', 'src/' ],
target = 'libfluidsynth',
use = 'libfluidsynth_includes',
uselib = 'GLIB',
defines = [ 'HAVE_CONFIG_H', 'DEFAULT_SOUNDFONT=""' ]
)
def shutdown():
autowaf.shutdown()

View File

@ -0,0 +1,252 @@
diff --git a/libs/fluidsynth/src/fluid_defsfont.c b/libs/fluidsynth/src/fluid_defsfont.c
index 3eea95c..c395218 100644
--- a/libs/fluidsynth/src/fluid_defsfont.c
+++ b/libs/fluidsynth/src/fluid_defsfont.c
@@ -109,11 +109,13 @@ char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont)
return fluid_defsfont_get_name((fluid_defsfont_t*) sfont->data);
}
+#if 0
fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s)
{
/* This function is here just to avoid an ABI/SONAME bump, see ticket #98. Should never be used. */
return NULL;
}
+#endif
fluid_preset_t*
fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum)
diff --git a/libs/fluidsynth/src/fluid_hash.c b/libs/fluidsynth/src/fluid_hash.c
index a063e29..9d5a920 100644
--- a/libs/fluidsynth/src/fluid_hash.c
+++ b/libs/fluidsynth/src/fluid_hash.c
@@ -93,7 +93,7 @@ static const guint primes[] =
static const unsigned int nprimes = sizeof (primes) / sizeof (primes[0]);
-unsigned int
+static unsigned int
spaced_primes_closest (unsigned int num)
{
unsigned int i;
@@ -984,6 +984,7 @@ fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
return deleted;
}
+#if 0
/**
* fluid_hashtable_foreach_remove:
* @hashtable: a #fluid_hashtable_t.
@@ -1001,7 +1002,7 @@ fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
*
* Return value: the number of key/value pairs removed.
**/
-unsigned int
+static unsigned int
fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
fluid_hr_func_t func, void *user_data)
{
@@ -1010,6 +1011,7 @@ fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
return fluid_hashtable_foreach_remove_or_steal (hashtable, func, user_data, TRUE);
}
+#endif
/**
* fluid_hashtable_foreach_steal:
diff --git a/libs/fluidsynth/src/fluid_midi.c b/libs/fluidsynth/src/fluid_midi.c
index 5ceab01..1ee3dd2 100644
--- a/libs/fluidsynth/src/fluid_midi.c
+++ b/libs/fluidsynth/src/fluid_midi.c
@@ -1115,10 +1115,11 @@ fluid_track_get_duration(fluid_track_t *track)
return time;
}
+#if 0
/*
* fluid_track_count_events
*/
-int
+static int
fluid_track_count_events(fluid_track_t *track, int *on, int *off)
{
fluid_midi_event_t *evt = track->first;
@@ -1132,6 +1133,7 @@ fluid_track_count_events(fluid_track_t *track, int *on, int *off)
}
return FLUID_OK;
}
+#endif
/*
* fluid_track_add_event
@@ -1533,7 +1535,7 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
return FLUID_OK;
}
-void
+static void
fluid_player_advancefile(fluid_player_t *player)
{
if (player->playlist == NULL) {
@@ -1553,7 +1555,7 @@ fluid_player_advancefile(fluid_player_t *player)
}
}
-void
+static void
fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
{
fluid_playlist_item* current_playitem;
diff --git a/libs/fluidsynth/src/fluid_rev.c b/libs/fluidsynth/src/fluid_rev.c
index 51b0e79..166007d 100644
--- a/libs/fluidsynth/src/fluid_rev.c
+++ b/libs/fluidsynth/src/fluid_rev.c
@@ -75,7 +75,7 @@ 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
+static void
fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
{
allpass->bufidx = 0;
@@ -83,7 +83,7 @@ fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
allpass->bufsize = size;
}
-void
+static void
fluid_allpass_release(fluid_allpass* allpass)
{
FLUID_FREE(allpass->buffer);
diff --git a/libs/fluidsynth/src/fluid_rvoice_mixer.c b/libs/fluidsynth/src/fluid_rvoice_mixer.c
index 4672cb8..cc633f5 100644
--- a/libs/fluidsynth/src/fluid_rvoice_mixer.c
+++ b/libs/fluidsynth/src/fluid_rvoice_mixer.c
@@ -24,7 +24,7 @@
#include "fluid_rev.h"
#include "fluid_chorus.h"
#include "fluidsynth_priv.h"
-#include "fluid_ladspa.h"
+//#include "fluid_ladspa.h"
#define SYNTH_REVERB_CHANNEL 0
#define SYNTH_CHORUS_CHANNEL 1
diff --git a/libs/fluidsynth/src/fluid_rvoice_mixer.h b/libs/fluidsynth/src/fluid_rvoice_mixer.h
index eeb49ec..d4e41ca 100644
--- a/libs/fluidsynth/src/fluid_rvoice_mixer.h
+++ b/libs/fluidsynth/src/fluid_rvoice_mixer.h
@@ -24,7 +24,7 @@
#include "fluidsynth_priv.h"
#include "fluid_rvoice.h"
-#include "fluid_ladspa.h"
+//#include "fluid_ladspa.h"
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
diff --git a/libs/fluidsynth/src/fluid_settings.c b/libs/fluidsynth/src/fluid_settings.c
index 78725fb..2061c90 100644
--- a/libs/fluidsynth/src/fluid_settings.c
+++ b/libs/fluidsynth/src/fluid_settings.c
@@ -22,9 +22,9 @@
#include "fluid_sys.h"
#include "fluid_hash.h"
#include "fluid_synth.h"
-#include "fluid_cmd.h"
-#include "fluid_adriver.h"
-#include "fluid_mdriver.h"
+//#include "fluid_cmd.h"
+//#include "fluid_adriver.h"
+//#include "fluid_mdriver.h"
#include "fluid_settings.h"
#include "fluid_midi.h"
@@ -294,11 +294,13 @@ fluid_settings_init(fluid_settings_t* settings)
fluid_return_if_fail (settings != NULL);
fluid_synth_settings(settings);
- fluid_shell_settings(settings);
+ //fluid_shell_settings(settings);
fluid_player_settings(settings);
+#if 0
fluid_file_renderer_settings(settings);
fluid_audio_driver_settings(settings);
fluid_midi_driver_settings(settings);
+#endif
}
static int
diff --git a/libs/fluidsynth/src/fluid_synth.c b/libs/fluidsynth/src/fluid_synth.c
index 84ee289..a12260c 100644
--- a/libs/fluidsynth/src/fluid_synth.c
+++ b/libs/fluidsynth/src/fluid_synth.c
@@ -471,7 +471,7 @@ struct _fluid_sample_timer_t
/*
* fluid_sample_timer_process - called when synth->ticks is updated
*/
-void fluid_sample_timer_process(fluid_synth_t* synth)
+static void fluid_sample_timer_process(fluid_synth_t* synth)
{
fluid_sample_timer_t* st;
long msec;
diff --git a/libs/fluidsynth/src/fluid_synth.h b/libs/fluidsynth/src/fluid_synth.h
index 3af336d..019a8e0 100644
--- a/libs/fluidsynth/src/fluid_synth.h
+++ b/libs/fluidsynth/src/fluid_synth.h
@@ -37,8 +37,8 @@
#include "fluid_rev.h"
#include "fluid_voice.h"
#include "fluid_chorus.h"
-#include "fluid_ladspa.h"
-#include "fluid_midi_router.h"
+//#include "fluid_ladspa.h"
+//#include "fluid_midi_router.h"
#include "fluid_sys.h"
#include "fluid_rvoice_event.h"
diff --git a/libs/fluidsynth/src/fluid_sys.c b/libs/fluidsynth/src/fluid_sys.c
index ee7d8d9..600b04e 100644
--- a/libs/fluidsynth/src/fluid_sys.c
+++ b/libs/fluidsynth/src/fluid_sys.c
@@ -686,7 +686,7 @@ fluid_thread_join(fluid_thread_t* thread)
}
-void
+static void
fluid_timer_run (void *data)
{
fluid_timer_t *timer;
diff --git a/libs/fluidsynth/src/fluid_tuning.c b/libs/fluidsynth/src/fluid_tuning.c
index cc440aa..8977ed6 100644
--- a/libs/fluidsynth/src/fluid_tuning.c
+++ b/libs/fluidsynth/src/fluid_tuning.c
@@ -143,7 +143,7 @@ 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)
+static void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
{
tuning->pitch[key] = pitch;
}
diff --git a/libs/fluidsynth/src/fluidsynth_priv.h b/libs/fluidsynth/src/fluidsynth_priv.h
index faf2772..74b9f4b 100644
--- a/libs/fluidsynth/src/fluidsynth_priv.h
+++ b/libs/fluidsynth/src/fluidsynth_priv.h
@@ -28,14 +28,6 @@
#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

99
tools/update_fluidsynth.sh Executable file
View File

@ -0,0 +1,99 @@
#!/bin/sh
if ! test -f wscript || ! test -d gtk2_ardour || ! test -d libs/fluidsynth/;then
echo "This script needs to run from ardour's top-level src tree"
exit 1
fi
if test -z "`which rsync`" -o -z "`which git`"; then
echo "this script needs rsync and git"
exit 1
fi
ASRC=`pwd`
set -e
TMP=`mktemp -d`
test -d "$TMP"
echo $TMP
trap "rm -rf $TMP" EXIT
cd $TMP
git clone git://git.code.sf.net/p/fluidsynth/code-git fs-git
FSR=fs-git/fluidsynth/
rsync -auc --info=progress2 \
${FSR}src/midi/fluid_midi.c \
${FSR}src/midi/fluid_midi.h \
${FSR}src/rvoice/fluid_adsr_env.c \
${FSR}src/rvoice/fluid_adsr_env.h \
${FSR}src/rvoice/fluid_chorus.c \
${FSR}src/rvoice/fluid_chorus.h \
${FSR}src/rvoice/fluid_iir_filter.c \
${FSR}src/rvoice/fluid_iir_filter.h \
${FSR}src/rvoice/fluid_lfo.c \
${FSR}src/rvoice/fluid_lfo.h \
${FSR}src/rvoice/fluid_phase.h \
${FSR}src/rvoice/fluid_rev.c \
${FSR}src/rvoice/fluid_rev.h \
${FSR}src/rvoice/fluid_rvoice.c \
${FSR}src/rvoice/fluid_rvoice_dsp.c \
${FSR}src/rvoice/fluid_rvoice_event.c \
${FSR}src/rvoice/fluid_rvoice_event.h \
${FSR}src/rvoice/fluid_rvoice.h \
${FSR}src/rvoice/fluid_rvoice_mixer.c \
${FSR}src/rvoice/fluid_rvoice_mixer.h \
${FSR}src/sfloader/fluid_defsfont.c \
${FSR}src/sfloader/fluid_defsfont.h \
${FSR}src/sfloader/fluid_sfont.h \
${FSR}src/synth/fluid_chan.c \
${FSR}src/synth/fluid_chan.h \
${FSR}src/synth/fluid_event.c \
${FSR}src/synth/fluid_event_priv.h \
${FSR}src/synth/fluid_event_queue.h \
${FSR}src/synth/fluid_gen.c \
${FSR}src/synth/fluid_gen.h \
${FSR}src/synth/fluid_mod.c \
${FSR}src/synth/fluid_mod.h \
${FSR}src/synth/fluid_synth.c \
${FSR}src/synth/fluid_synth.h \
${FSR}src/synth/fluid_tuning.c \
${FSR}src/synth/fluid_tuning.h \
${FSR}src/synth/fluid_voice.c \
${FSR}src/synth/fluid_voice.h \
${FSR}src/utils/fluid_conv.c \
${FSR}src/utils/fluid_conv.h \
${FSR}src/utils/fluid_hash.c \
${FSR}src/utils/fluid_hash.h \
${FSR}src/utils/fluid_list.c \
${FSR}src/utils/fluid_list.h \
${FSR}src/utils/fluid_ringbuffer.c \
${FSR}src/utils/fluid_ringbuffer.h \
${FSR}src/utils/fluid_settings.c \
${FSR}src/utils/fluid_settings.h \
${FSR}src/utils/fluidsynth_priv.h \
${FSR}src/utils/fluid_sys.c \
${FSR}src/utils/fluid_sys.h \
\
"$ASRC/libs/fluidsynth/src/"
rsync -auc --info=progress2 \
--exclude fluidsynth.h \
${FSR}include/fluidsynth/event.h \
${FSR}include/fluidsynth/gen.h \
${FSR}include/fluidsynth/log.h \
${FSR}include/fluidsynth/midi.h \
${FSR}include/fluidsynth/misc.h \
${FSR}include/fluidsynth/mod.h \
${FSR}include/fluidsynth/settings.h \
${FSR}include/fluidsynth/sfont.h \
${FSR}include/fluidsynth/synth.h \
${FSR}include/fluidsynth/types.h \
${FSR}include/fluidsynth/voice.h \
\
"$ASRC/libs/fluidsynth/fluidsynth/"
cd "$ASRC"
patch -p1 < tools/ardour_fluidsynth.diff

View File

@ -204,6 +204,7 @@ children = [
'libs/qm-dsp',
'libs/vamp-plugins',
'libs/libltc',
'libs/fluidsynth',
'libs/lua',
'libs/ptformat',
# core ardour libraries