Import libfluidsynth into the Ardour codebase
This commit is contained in:
parent
ac8617017a
commit
ac05f05023
|
@ -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.
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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];
|
||||
}
|
|
@ -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
|
@ -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 */
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 */
|
||||
|
|
@ -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");
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 */
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 */
|
|
@ -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
|
@ -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
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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 */
|
|
@ -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 */
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue