Update to fluidsynth-2.2
This commit is contained in:
parent
dd060b04dc
commit
71788ecfe4
|
@ -1,7 +1,7 @@
|
|||
This is a stripped down version of fluidsynth (library only)
|
||||
|
||||
from git://github.com/FluidSynth/fluidsynth.git
|
||||
rev. v2.1.0-1-gb266cf2ab
|
||||
rev. v2.2.0-41-gf55bc799
|
||||
|
||||
fluidsynth is licensed in terms of the LGPL-2+, see individual source
|
||||
files for (C) holders.
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
#define CONFIG_H
|
||||
|
||||
#define FLUIDSYNTH_VERSION_MAJOR 2
|
||||
#define FLUIDSYNTH_VERSION_MINOR 0
|
||||
#define FLUIDSYNTH_VERSION_MICRO 6
|
||||
#define FLUIDSYNTH_VERSION "2.0.6"
|
||||
#define FLUIDSYNTH_VERSION_MINOR 2
|
||||
#define FLUIDSYNTH_VERSION_MICRO 0
|
||||
#define FLUIDSYNTH_VERSION "2.2.0"
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.2.0"
|
||||
|
||||
/* Define to enable ALSA driver */
|
||||
/* #undef ALSA_SUPPORT */
|
||||
|
@ -35,9 +38,6 @@
|
|||
# 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
|
||||
|
||||
|
@ -47,42 +47,39 @@
|
|||
/* 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 */
|
||||
/* Define to 1 if you have the <io.h> header file. */
|
||||
/* #undef HAVE_IO_H */
|
||||
|
||||
/* 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 if systemd support is enabled */
|
||||
/* #undef SYSTEMD_SUPPORT */
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/soundcard.h> header file. */
|
||||
/* #undef HAVE_LINUX_SOUNDCARD_H */
|
||||
|
||||
/* 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 if compiling the mixer with multi-thread support */
|
||||
/* #undef ENABLE_MIXER_THREADS */
|
||||
|
||||
/* Define if compiling with openMP to enable parallel audio rendering */
|
||||
/* #undef HAVE_OPENMP */
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file. */
|
||||
#define HAVE_PTHREAD_H 1
|
||||
|
||||
|
@ -143,12 +140,27 @@
|
|||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
/* #undef HAVE_GETOPT_H */
|
||||
|
||||
/* Define to 1 if you have the inet_ntop() function. */
|
||||
/* #undef HAVE_INETNTOP */
|
||||
|
||||
/* Define to enable JACK driver */
|
||||
/* #undef JACK_SUPPORT */
|
||||
|
||||
/* Include the LADSPA Fx unit */
|
||||
/* #undef LADSPA */
|
||||
|
||||
/* Define to enable IPV6 support */
|
||||
/* #undef IPV6_SUPPORT */
|
||||
|
||||
/* Define to enable network support */
|
||||
/* #undef NETWORK_SUPPORT */
|
||||
|
||||
/* Defined when fluidsynth is build in an automated environment, where no MSVC++ Runtime Debug Assertion dialogs should pop up */
|
||||
/* #undef NO_GUI */
|
||||
|
||||
/* libinstpatch for DLS and GIG */
|
||||
/* #undef LIBINSTPATCH_SUPPORT */
|
||||
|
||||
/* libsndfile has ogg vorbis support */
|
||||
/* #undef LIBSNDFILE_HASVORBIS */
|
||||
|
||||
|
@ -161,12 +173,15 @@
|
|||
/* 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 */
|
||||
|
||||
/* Define to enable OPENSLES driver */
|
||||
/* #undef OPENSLES_SUPPORT */
|
||||
|
||||
/* Define to enable Oboe driver */
|
||||
/* #undef OBOE_SUPPORT */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "fluidsynth"
|
||||
|
||||
|
@ -190,6 +205,20 @@
|
|||
|
||||
/* Define to enable PulseAudio driver */
|
||||
/* #undef PULSE_SUPPORT */
|
||||
/* Define to enable DirectSound driver */
|
||||
/* #undef DSOUND_SUPPORT */
|
||||
|
||||
/* Define to enable Windows WASAPI driver */
|
||||
/* #undef WASAPI_SUPPORT */
|
||||
|
||||
/* Define to enable Windows WaveOut driver */
|
||||
/* #undef WAVEOUT_SUPPORT */
|
||||
|
||||
/* Define to enable Windows MIDI driver */
|
||||
/* #undef WINMIDI_SUPPORT */
|
||||
|
||||
/* Define to enable SDL2 audio driver */
|
||||
/* #undef SDL2_SUPPORT */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
@ -197,9 +226,6 @@
|
|||
/* Define to enable SIGFPE assertions */
|
||||
/* #undef TRAP_ON_FPE */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.0.6"
|
||||
|
||||
/* Define to do all DSP in single floating point precision */
|
||||
#ifdef __arm__
|
||||
# define WITH_FLOAT
|
||||
|
@ -234,4 +260,22 @@
|
|||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the sinf() function. */
|
||||
/* #undef HAVE_SINF */
|
||||
|
||||
/* Define to 1 if you have the cosf() function. */
|
||||
/* #undef HAVE_COSF */
|
||||
|
||||
/* Define to 1 if you have the fabsf() function. */
|
||||
/* #undef HAVE_FABSF */
|
||||
|
||||
/* Define to 1 if you have the powf() function. */
|
||||
/* #undef HAVE_POWF */
|
||||
|
||||
/* Define to 1 if you have the sqrtf() function. */
|
||||
/* #undef HAVE_SQRTF */
|
||||
|
||||
/* Define to 1 if you have the logf() function. */
|
||||
/* #undef HAVE_LOGF */
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
|
|
@ -26,10 +26,12 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @file event.h
|
||||
* @brief Sequencer event functions and defines.
|
||||
* @defgroup sequencer_events Sequencer Events
|
||||
* @ingroup sequencer
|
||||
*
|
||||
* Functions and constants for creating/processing sequencer events.
|
||||
* Create, modify, query and destroy sequencer events.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -46,7 +48,7 @@ enum fluid_seq_event_type
|
|||
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
|
||||
FLUID_SEQ_PROGRAMSELECT, /**< Program select message */
|
||||
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
|
||||
FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was mispelled previously */
|
||||
FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was misspelled previously */
|
||||
FLUID_SEQ_MODULATION, /**< Modulation controller event */
|
||||
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
|
||||
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
|
||||
|
@ -55,19 +57,21 @@ enum fluid_seq_event_type
|
|||
FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
|
||||
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
|
||||
FLUID_SEQ_TIMER, /**< Timer event (useful for giving a callback at a certain time) */
|
||||
FLUID_SEQ_ANYCONTROLCHANGE, /**< Any control change message (only internally used for remove_events) */
|
||||
FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
|
||||
FLUID_SEQ_KEYPRESSURE, /**< Polyphonic aftertouch event @since 2.0.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 */
|
||||
#ifndef __DOXYGEN__
|
||||
FLUID_SEQ_LASTEVENT /**< @internal Defines the count of events enums @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
#endif
|
||||
FLUID_SEQ_SCALE, /**< Sets a new time scale for the sequencer @since 2.2.0 */
|
||||
FLUID_SEQ_LASTEVENT /**< @internal Defines the count of events enums @warning This symbol
|
||||
is not part of the public API and ABI stability guarantee and
|
||||
may change at any time! */
|
||||
};
|
||||
|
||||
/* Event alloc/free */
|
||||
/** @startlifecycle{Sequencer Event} */
|
||||
FLUIDSYNTH_API fluid_event_t *new_fluid_event(void);
|
||||
FLUIDSYNTH_API void delete_fluid_event(fluid_event_t *evt);
|
||||
/** @endlifecycle */
|
||||
|
||||
/* Initializing events */
|
||||
FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src);
|
||||
|
@ -88,34 +92,32 @@ 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_change(fluid_event_t *evt, int channel, int 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);
|
||||
void fluid_event_control_change(fluid_event_t *evt, int channel, short control, int 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_pitch_wheelsens(fluid_event_t *evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t *evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t *evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_pan(fluid_event_t *evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_volume(fluid_event_t *evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t *evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t *evt, int channel, int val);
|
||||
|
||||
FLUIDSYNTH_API void fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, short val);
|
||||
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, int val);
|
||||
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t *evt, int channel, int 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);
|
||||
|
||||
FLUIDSYNTH_API void fluid_event_scale(fluid_event_t *evt, double new_scale);
|
||||
|
||||
/* Accessing event data */
|
||||
FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt);
|
||||
|
@ -124,13 +126,15 @@ 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 int fluid_event_get_value(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API int 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 double fluid_event_get_scale(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t *evt);
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -26,8 +26,12 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @file gen.h
|
||||
* @brief Functions and defines for SoundFont generator effects.
|
||||
* @defgroup generators SoundFont Generators
|
||||
* @ingroup soundfonts
|
||||
*
|
||||
* Functions and defines for SoundFont generator effects.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -96,7 +100,7 @@ enum fluid_gen_type
|
|||
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
|
||||
|
||||
/**
|
||||
* @brief Initial Pitch
|
||||
* Initial Pitch
|
||||
*
|
||||
* @note This is not "standard" SoundFont generator, because it is not
|
||||
* mentioned in the list of generators in the SF2 specifications.
|
||||
|
@ -117,11 +121,11 @@ enum fluid_gen_type
|
|||
GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */
|
||||
GEN_CUSTOM_FILTERQ, /**< Custom filter Q */
|
||||
|
||||
#ifndef __DOXYGEN__
|
||||
GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
#endif
|
||||
GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type)
|
||||
@warning This symbol is not part of the public API and ABI
|
||||
stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -28,25 +28,31 @@ extern "C" {
|
|||
|
||||
|
||||
/**
|
||||
* @file log.h
|
||||
* @brief Logging interface
|
||||
* @defgroup logging Logging
|
||||
*
|
||||
* The default logging function of the fluidsynth prints its messages
|
||||
* to the stderr. The synthesizer uses five level of messages: #FLUID_PANIC,
|
||||
* 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:
|
||||
* 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);
|
||||
* 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
|
||||
*
|
||||
* @note The logging configuration is global and not tied to a specific
|
||||
* synthesizer instance. That means that all synthesizer instances created in
|
||||
* the same process share the same logging configuration.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -59,13 +65,13 @@ enum fluid_log_level
|
|||
FLUID_WARN, /**< Warning */
|
||||
FLUID_INFO, /**< Verbose informational messages */
|
||||
FLUID_DBG, /**< Debugging messages */
|
||||
#ifndef __DOXYGEN__
|
||||
LAST_LOG_LEVEL /**< @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
#endif
|
||||
LAST_LOG_LEVEL /**< @internal This symbol is not part of the public API and ABI
|
||||
stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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().
|
||||
|
@ -82,7 +88,7 @@ FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...)
|
|||
__attribute__ ((format (printf, 2, 3)))
|
||||
#endif
|
||||
;
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -26,12 +26,92 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @file midi.h
|
||||
* @brief Functions for MIDI events, drivers and MIDI file playback.
|
||||
* @defgroup midi_input MIDI Input
|
||||
*
|
||||
* MIDI Input Subsystem
|
||||
*
|
||||
* There are multiple ways to send MIDI events to the synthesizer. They can come
|
||||
* from MIDI files, from external MIDI sequencers or raw MIDI event sources,
|
||||
* can be modified via MIDI routers and also generated manually.
|
||||
*
|
||||
* The interface connecting all sources and sinks of MIDI events in libfluidsynth
|
||||
* is \ref handle_midi_event_func_t.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generic callback function for MIDI event handler.
|
||||
*
|
||||
* @param data User defined data pointer
|
||||
* @param event The MIDI event
|
||||
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*
|
||||
* This callback is used to pass MIDI events
|
||||
* - from \ref midi_player, \ref midi_router or \ref midi_driver
|
||||
* - to \ref midi_router via fluid_midi_router_handle_midi_event()
|
||||
* - or to \ref synth via fluid_synth_handle_midi_event().
|
||||
*
|
||||
* Additionally, there is a translation layer to pass MIDI events to
|
||||
* a \ref sequencer via fluid_sequencer_add_midi_event_to_buffer().
|
||||
*/
|
||||
typedef int (*handle_midi_event_func_t)(void *data, fluid_midi_event_t *event);
|
||||
|
||||
/**
|
||||
* Generic callback function fired once by MIDI tick change.
|
||||
*
|
||||
* @param data User defined data pointer
|
||||
* @param tick The current (zero-based) tick, which triggered the callback
|
||||
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*
|
||||
* This callback is fired at a constant rate depending on the current BPM and PPQ.
|
||||
* e.g. for PPQ = 192 and BPM = 140 the callback is fired 192 * 140 times per minute (448/sec).
|
||||
*
|
||||
* It can be used to sync external elements with the beat,
|
||||
* or stop / loop the song on a given tick.
|
||||
* Ticks being BPM-dependent, you can manipulate values such as bars or beats,
|
||||
* without having to care about BPM.
|
||||
*
|
||||
* For example, this callback loops the song whenever it reaches the 5th bar :
|
||||
*
|
||||
* @code{.cpp}
|
||||
int handle_tick(void *data, int tick)
|
||||
{
|
||||
fluid_player_t *player = (fluid_player_t *)data;
|
||||
int ppq = 192; // From MIDI header
|
||||
int beatsPerBar = 4; // From the song's time signature
|
||||
int loopBar = 5;
|
||||
int loopTick = (loopBar - 1) * ppq * beatsPerBar;
|
||||
|
||||
if (tick == loopTick)
|
||||
{
|
||||
return fluid_player_seek(player, 0);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
* @endcode
|
||||
*/
|
||||
typedef int (*handle_midi_tick_func_t)(void *data, int tick);
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* @defgroup midi_events MIDI Events
|
||||
* @ingroup midi_input
|
||||
*
|
||||
* Functions to create, modify, query and delete MIDI events.
|
||||
*
|
||||
* These functions are intended to be used in MIDI routers and other filtering
|
||||
* and processing functions in the MIDI event path. If you want to simply
|
||||
* send MIDI messages to the synthesizer, you can use the more convenient
|
||||
* \ref midi_messages interface.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/** @startlifecycle{MIDI Event} */
|
||||
FLUIDSYNTH_API fluid_midi_event_t *new_fluid_midi_event(void);
|
||||
FLUIDSYNTH_API void delete_fluid_midi_event(fluid_midi_event_t *event);
|
||||
/** @endlifecycle */
|
||||
|
||||
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);
|
||||
|
@ -59,9 +139,20 @@ FLUIDSYNTH_API int fluid_midi_event_set_lyrics(fluid_midi_event_t *evt,
|
|||
void *data, int size, int dynamic);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt,
|
||||
void **data, int *size);
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* @defgroup midi_router MIDI Router
|
||||
* @ingroup midi_input
|
||||
*
|
||||
* Rule based tranformation and filtering of MIDI events.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* MIDI router rule type.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
typedef enum
|
||||
|
@ -72,35 +163,30 @@ typedef enum
|
|||
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 */
|
||||
#ifndef __DOXYGEN__
|
||||
FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time!*/
|
||||
#endif
|
||||
FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types. This symbol
|
||||
is not part of the public API and ABI stability
|
||||
guarantee and may change at any time!*/
|
||||
} 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);
|
||||
|
||||
/** @startlifecycle{MIDI Router} */
|
||||
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 void delete_fluid_midi_router(fluid_midi_router_t *handler);
|
||||
/** @endlifecycle */
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/** @startlifecycle{MIDI Router Rule} */
|
||||
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);
|
||||
/** @endlifecycle */
|
||||
|
||||
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,
|
||||
|
@ -110,38 +196,88 @@ FLUIDSYNTH_API void fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *
|
|||
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);
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* @defgroup midi_driver MIDI Driver
|
||||
* @ingroup midi_input
|
||||
*
|
||||
* Functions for managing MIDI drivers.
|
||||
*
|
||||
* The available MIDI drivers depend on your platform. See \ref settings_midi for all
|
||||
* available configuration options.
|
||||
*
|
||||
* To create a MIDI driver, you need to specify a source for the MIDI events to be
|
||||
* forwarded to via the \ref fluid_midi_event_t callback. Normally this will be
|
||||
* either a \ref midi_router via fluid_midi_router_handle_midi_event() or the synthesizer
|
||||
* via fluid_synth_handle_midi_event().
|
||||
*
|
||||
* But you can also write your own handler function that preprocesses the events and
|
||||
* forwards them on to the router or synthesizer instead.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @startlifecycle{MIDI Driver} */
|
||||
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);
|
||||
/** @endlifecycle */
|
||||
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* MIDI player status enum.
|
||||
* @defgroup midi_player MIDI File Player
|
||||
* @ingroup midi_input
|
||||
*
|
||||
* Parse standard MIDI files and emit MIDI events.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* MIDI File 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_STOPPING, /**< Player is stopping, but hasn't finished yet */
|
||||
FLUID_PLAYER_DONE /**< Player is finished playing */
|
||||
};
|
||||
|
||||
/**
|
||||
* MIDI File Player tempo enum.
|
||||
* @since 2.2.0
|
||||
*/
|
||||
enum fluid_player_set_tempo_type
|
||||
{
|
||||
FLUID_PLAYER_TEMPO_INTERNAL, /**< Use midi file tempo set in midi file (120 bpm by default). Multiplied by a factor */
|
||||
FLUID_PLAYER_TEMPO_EXTERNAL_BPM, /**< Set player tempo in bpm, supersede midi file tempo */
|
||||
FLUID_PLAYER_TEMPO_EXTERNAL_MIDI, /**< Set player tempo in us per quarter note, supersede midi file tempo */
|
||||
FLUID_PLAYER_TEMPO_NBR /**< @internal Value defines the count of player tempo type (#fluid_player_set_tempo_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
/** @startlifecycle{MIDI File Player} */
|
||||
FLUIDSYNTH_API fluid_player_t *new_fluid_player(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API void delete_fluid_player(fluid_player_t *player);
|
||||
/** @endlifecycle */
|
||||
|
||||
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_set_tempo(fluid_player_t *player, int tempo_type, double tempo);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t *player, int bpm);
|
||||
FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t *player, handle_midi_event_func_t handler, void *handler_data);
|
||||
FLUIDSYNTH_API int fluid_player_set_tick_callback(fluid_player_t *player, handle_midi_tick_func_t handler, void *handler_data);
|
||||
|
||||
FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_get_current_tick(fluid_player_t *player);
|
||||
|
@ -149,8 +285,7 @@ FLUIDSYNTH_API int fluid_player_get_total_ticks(fluid_player_t *player);
|
|||
FLUIDSYNTH_API int fluid_player_get_bpm(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_get_midi_tempo(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_seek(fluid_player_t *player, int ticks);
|
||||
|
||||
///
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -28,13 +28,15 @@ extern "C" {
|
|||
|
||||
|
||||
/**
|
||||
* @file misc.h
|
||||
* @brief Miscellaneous utility functions and defines
|
||||
* @defgroup misc Miscellaneous
|
||||
*
|
||||
* 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
|
||||
|
@ -48,14 +50,17 @@ extern "C" {
|
|||
* #define FLUID_FAILED (-1)
|
||||
* #endif
|
||||
* @endcode
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
#define FLUID_OK (0)
|
||||
|
||||
/**
|
||||
* Value that indicates failure, used by most libfluidsynth functions.
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @note See #FLUID_OK for more details.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
#define FLUID_FAILED (-1)
|
||||
|
||||
|
@ -63,7 +68,7 @@ extern "C" {
|
|||
FLUIDSYNTH_API int fluid_is_soundfont(const char *filename);
|
||||
FLUIDSYNTH_API int fluid_is_midifile(const char *filename);
|
||||
FLUIDSYNTH_API void fluid_free(void* ptr);
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -26,11 +26,14 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @file mod.h
|
||||
* @brief SoundFont modulator functions and constants.
|
||||
* @defgroup modulators SoundFont Modulators
|
||||
* @ingroup soundfonts
|
||||
*
|
||||
* SoundFont modulator functions and constants.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Flags defining the polarity, mapping function and type of a modulator source.
|
||||
* Compare with SoundFont 2.04 PDF section 8.2.
|
||||
|
@ -69,8 +72,11 @@ enum fluid_mod_src
|
|||
FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */
|
||||
};
|
||||
|
||||
/** @startlifecycle{Modulator} */
|
||||
FLUIDSYNTH_API fluid_mod_t *new_fluid_mod(void);
|
||||
FLUIDSYNTH_API void delete_fluid_mod(fluid_mod_t *mod);
|
||||
/** @endlifecycle */
|
||||
|
||||
FLUIDSYNTH_API size_t fluid_mod_sizeof(void);
|
||||
|
||||
FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags);
|
||||
|
@ -90,6 +96,7 @@ FLUIDSYNTH_API int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl
|
|||
FLUIDSYNTH_API int fluid_mod_has_dest(const fluid_mod_t *mod, int gen);
|
||||
|
||||
FLUIDSYNTH_API void fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src);
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @file settings.h
|
||||
* @brief Synthesizer settings
|
||||
* @defgroup SettingsFunctions Functions for settings management
|
||||
* @defgroup settings Settings
|
||||
*
|
||||
* 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.
|
||||
|
@ -49,6 +49,8 @@ extern "C" {
|
|||
* }
|
||||
* @endcode
|
||||
* @sa @ref CreatingSettings
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -97,9 +99,10 @@ enum fluid_types_enum
|
|||
FLUID_SET_TYPE /**< Set of values */
|
||||
};
|
||||
|
||||
|
||||
/** @startlifecycle{Settings} */
|
||||
FLUIDSYNTH_API fluid_settings_t *new_fluid_settings(void);
|
||||
FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t *settings);
|
||||
/** @endlifecycle */
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_get_type(fluid_settings_t *settings, const char *name);
|
||||
|
@ -120,7 +123,7 @@ FLUIDSYNTH_API
|
|||
int fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def);
|
||||
int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char const **def);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *value);
|
||||
|
@ -153,6 +156,7 @@ int fluid_settings_getint_range(fluid_settings_t *settings, const char *name,
|
|||
|
||||
/**
|
||||
* 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)
|
||||
|
@ -171,6 +175,7 @@ FLUIDSYNTH_API char *fluid_settings_option_concat(fluid_settings_t *settings,
|
|||
|
||||
/**
|
||||
* 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)
|
||||
|
@ -180,6 +185,7 @@ typedef void (*fluid_settings_foreach_t)(void *data, const char *name, int type)
|
|||
FLUIDSYNTH_API
|
||||
void fluid_settings_foreach(fluid_settings_t *settings, void *data,
|
||||
fluid_settings_foreach_t func);
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -25,10 +25,21 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup soundfonts SountFonts
|
||||
*
|
||||
* SoundFont related functions
|
||||
*
|
||||
* This part of the API contains functions, defines and types that are mostly
|
||||
* only used by internal or custom SoundFont loaders or client code that
|
||||
* modifies loaded presets, SoundFonts or voices directly.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sfont.h
|
||||
* @brief SoundFont plugins
|
||||
* @defgroup soundfont_loader SoundFont Loader
|
||||
* @ingroup soundfonts
|
||||
*
|
||||
* Create custom SoundFont loaders
|
||||
*
|
||||
* It is possible to add new SoundFont loaders to the
|
||||
* synthesizer. This API allows for virtual SoundFont files to be loaded
|
||||
|
@ -59,6 +70,8 @@ extern "C" {
|
|||
* 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.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -68,52 +81,65 @@ enum
|
|||
{
|
||||
FLUID_PRESET_SELECTED, /**< Preset selected notify */
|
||||
FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
|
||||
FLUID_SAMPLE_DONE /**< Sample no longer needed notify */
|
||||
FLUID_SAMPLE_DONE, /**< Sample no longer needed notify */
|
||||
FLUID_PRESET_PIN, /**< Request to pin preset samples to cache */
|
||||
FLUID_PRESET_UNPIN /**< Request to unpin preset samples from cache */
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates the type of a sample used by the _fluid_sample_t::sampletype field.
|
||||
*
|
||||
* This enum corresponds to the \c SFSampleLink enum in the SoundFont spec.
|
||||
* One \c flag may be bit-wise OR-ed with one \c value.
|
||||
*/
|
||||
enum fluid_sample_type
|
||||
{
|
||||
FLUID_SAMPLETYPE_MONO = 0x1, /**< Used for mono samples */
|
||||
FLUID_SAMPLETYPE_RIGHT = 0x2, /**< Used for right samples of a stereo pair */
|
||||
FLUID_SAMPLETYPE_LEFT = 0x4, /**< Used for left samples of a stereo pair */
|
||||
FLUID_SAMPLETYPE_LINKED = 0x8, /**< Currently not used */
|
||||
FLUID_SAMPLETYPE_OGG_VORBIS = 0x10, /**< Used for Ogg Vorbis compressed samples @since 1.1.7 */
|
||||
FLUID_SAMPLETYPE_ROM = 0x8000 /**< Indicates ROM samples, causes sample to be ignored */
|
||||
FLUID_SAMPLETYPE_MONO = 0x1, /**< Value used for mono samples */
|
||||
FLUID_SAMPLETYPE_RIGHT = 0x2, /**< Value used for right samples of a stereo pair */
|
||||
FLUID_SAMPLETYPE_LEFT = 0x4, /**< Value used for left samples of a stereo pair */
|
||||
FLUID_SAMPLETYPE_LINKED = 0x8, /**< Value used for linked sample, which is currently not supported */
|
||||
FLUID_SAMPLETYPE_OGG_VORBIS = 0x10, /**< Flag used for Ogg Vorbis compressed samples (non-standard compliant extension) as found in the program "sftools" developed by Werner Schweer from MuseScore @since 1.1.7 */
|
||||
FLUID_SAMPLETYPE_ROM = 0x8000 /**< Flag that indicates ROM samples, causing the sample to be ignored */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return The loaded instrument file (SoundFont) or NULL if an error occurred.
|
||||
*/
|
||||
typedef fluid_sfont_t *(*fluid_sfloader_load_t)(fluid_sfloader_t *loader, const char *filename);
|
||||
|
||||
/**
|
||||
* The free method should free the memory allocated for a fluid_sfloader_t instance in
|
||||
* addition to any private data. Any custom user provided cleanup function must ultimately call
|
||||
* addition to any private data.
|
||||
*
|
||||
* @param loader SoundFont loader
|
||||
*
|
||||
* Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_sfloader() to ensure proper cleanup of the #fluid_sfloader_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_sfloader() is sufficient.
|
||||
* @param loader SoundFont loader
|
||||
*
|
||||
*/
|
||||
typedef void (*fluid_sfloader_free_t)(fluid_sfloader_t *loader);
|
||||
|
||||
|
||||
/** @startlifecycle{SoundFont Loader} */
|
||||
FLUIDSYNTH_API fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free);
|
||||
FLUIDSYNTH_API void delete_fluid_sfloader(fluid_sfloader_t *loader);
|
||||
|
||||
FLUIDSYNTH_API fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings);
|
||||
/** @endlifecycle */
|
||||
|
||||
/**
|
||||
* Opens the file or memory indicated by \c filename in binary read mode.
|
||||
* \c filename matches the string provided during the fluid_synth_sfload() call.
|
||||
*
|
||||
* @return returns a file handle on success, NULL otherwise
|
||||
*
|
||||
* \c filename matches the string provided during the fluid_synth_sfload() call.
|
||||
*/
|
||||
typedef void *(* fluid_sfloader_callback_open_t)(const char *filename);
|
||||
|
||||
|
@ -122,26 +148,25 @@ typedef void *(* fluid_sfloader_callback_open_t)(const char *filename);
|
|||
*
|
||||
* @return returns #FLUID_OK if exactly \c count bytes were successfully read, else returns #FLUID_FAILED and leaves \a buf unmodified.
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_read_t)(void *buf, int count, void *handle);
|
||||
typedef int (* fluid_sfloader_callback_read_t)(void *buf, fluid_long_long_t count, void *handle);
|
||||
|
||||
/**
|
||||
* Same purpose and behaviour as fseek.
|
||||
*
|
||||
* @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
|
||||
*
|
||||
* @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_seek_t)(void *handle, long offset, int origin);
|
||||
typedef int (* fluid_sfloader_callback_seek_t)(void *handle, fluid_long_long_t offset, int origin);
|
||||
|
||||
/**
|
||||
* Closes the handle returned by #fluid_sfloader_callback_open_t and frees used ressources.
|
||||
* Closes the handle returned by #fluid_sfloader_callback_open_t and frees used resources.
|
||||
*
|
||||
* @return returns #FLUID_OK on success, #FLUID_FAILED on error
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_close_t)(void *handle);
|
||||
|
||||
/** @return returns current file offset or #FLUID_FAILED on error */
|
||||
typedef long (* fluid_sfloader_callback_tell_t)(void *handle);
|
||||
typedef fluid_long_long_t (* fluid_sfloader_callback_tell_t)(void *handle);
|
||||
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
|
||||
|
@ -158,6 +183,7 @@ FLUIDSYNTH_API void *fluid_sfloader_get_data(fluid_sfloader_t *loader);
|
|||
|
||||
/**
|
||||
* Method to return the name of a virtual SoundFont.
|
||||
*
|
||||
* @param sfont Virtual SoundFont
|
||||
* @return The name of the virtual SoundFont.
|
||||
*/
|
||||
|
@ -165,6 +191,7 @@ typedef const char *(*fluid_sfont_get_name_t)(fluid_sfont_t *sfont);
|
|||
|
||||
/**
|
||||
* Get a virtual SoundFont preset by bank and program numbers.
|
||||
*
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param bank MIDI bank number (0-16383)
|
||||
* @param prenum MIDI preset number (0-127)
|
||||
|
@ -175,6 +202,7 @@ typedef fluid_preset_t *(*fluid_sfont_get_preset_t)(fluid_sfont_t *sfont, int ba
|
|||
|
||||
/**
|
||||
* Start virtual SoundFont preset iteration method.
|
||||
*
|
||||
* @param sfont Virtual SoundFont
|
||||
*
|
||||
* Starts/re-starts virtual preset iteration in a SoundFont.
|
||||
|
@ -183,6 +211,7 @@ typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t *sfont);
|
|||
|
||||
/**
|
||||
* Virtual SoundFont preset iteration function.
|
||||
*
|
||||
* @param sfont Virtual SoundFont
|
||||
* @return NULL when no more presets are available, otherwise the a pointer to the current preset
|
||||
*
|
||||
|
@ -192,17 +221,21 @@ typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t *sfont);
|
|||
typedef fluid_preset_t *(*fluid_sfont_iteration_next_t)(fluid_sfont_t *sfont);
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont bank. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_sfont() to ensure proper cleanup of the #fluid_sfont_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_sfont() is sufficient.
|
||||
* 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.
|
||||
*
|
||||
* Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_sfont() to ensure proper cleanup of the #fluid_sfont_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_sfont() is sufficient.
|
||||
*/
|
||||
typedef int (*fluid_sfont_free_t)(fluid_sfont_t *sfont);
|
||||
|
||||
|
||||
/** @startlifecycle{SoundFont} */
|
||||
FLUIDSYNTH_API fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name,
|
||||
fluid_sfont_get_preset_t get_preset,
|
||||
fluid_sfont_iteration_start_t iter_start,
|
||||
|
@ -210,6 +243,7 @@ FLUIDSYNTH_API fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name,
|
|||
fluid_sfont_free_t free);
|
||||
|
||||
FLUIDSYNTH_API int delete_fluid_sfont(fluid_sfont_t *sfont);
|
||||
/** @endlifecycle */
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data);
|
||||
FLUIDSYNTH_API void *fluid_sfont_get_data(fluid_sfont_t *sfont);
|
||||
|
@ -222,6 +256,7 @@ FLUIDSYNTH_API fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont);
|
|||
|
||||
/**
|
||||
* 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
|
||||
|
@ -231,6 +266,7 @@ typedef const char *(*fluid_preset_get_name_t)(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
|
||||
*/
|
||||
|
@ -238,6 +274,7 @@ typedef int (*fluid_preset_get_banknum_t)(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
|
||||
*/
|
||||
|
@ -245,6 +282,7 @@ typedef int (*fluid_preset_get_num_t)(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
|
||||
|
@ -268,14 +306,18 @@ typedef int (*fluid_preset_get_num_t)(fluid_preset_t *preset);
|
|||
typedef int (*fluid_preset_noteon_t)(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel);
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont preset. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_preset() to ensure proper cleanup of the #fluid_preset_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_preset() is sufficient.
|
||||
* Method to free a virtual SoundFont preset.
|
||||
*
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return 0
|
||||
*
|
||||
* Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_preset() to ensure proper cleanup of the #fluid_preset_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_preset() is sufficient.
|
||||
*/
|
||||
typedef void (*fluid_preset_free_t)(fluid_preset_t *preset);
|
||||
|
||||
/** @startlifecycle{Preset} */
|
||||
FLUIDSYNTH_API fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont,
|
||||
fluid_preset_get_name_t get_name,
|
||||
fluid_preset_get_banknum_t get_bank,
|
||||
|
@ -283,6 +325,7 @@ FLUIDSYNTH_API fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont,
|
|||
fluid_preset_noteon_t noteon,
|
||||
fluid_preset_free_t free);
|
||||
FLUIDSYNTH_API void delete_fluid_preset(fluid_preset_t *preset);
|
||||
/** @endlifecycle */
|
||||
|
||||
FLUIDSYNTH_API int fluid_preset_set_data(fluid_preset_t *preset, void *data);
|
||||
FLUIDSYNTH_API void *fluid_preset_get_data(fluid_preset_t *preset);
|
||||
|
@ -292,8 +335,11 @@ FLUIDSYNTH_API int fluid_preset_get_banknum(fluid_preset_t *preset);
|
|||
FLUIDSYNTH_API int fluid_preset_get_num(fluid_preset_t *preset);
|
||||
FLUIDSYNTH_API fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset);
|
||||
|
||||
/** @startlifecycle{Sample} */
|
||||
FLUIDSYNTH_API fluid_sample_t *new_fluid_sample(void);
|
||||
FLUIDSYNTH_API void delete_fluid_sample(fluid_sample_t *sample);
|
||||
/** @endlifecycle */
|
||||
|
||||
FLUIDSYNTH_API size_t fluid_sample_sizeof(void);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t *sample, const char *name);
|
||||
|
@ -307,6 +353,8 @@ FLUIDSYNTH_API int fluid_sample_set_sound_data(fluid_sample_t *sample,
|
|||
FLUIDSYNTH_API int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end);
|
||||
FLUIDSYNTH_API int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune);
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifndef _FLUIDSYNTH_SYNTH_H
|
||||
#define _FLUIDSYNTH_SYNTH_H
|
||||
|
||||
#define FLUID_DEPRECATED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -28,8 +29,9 @@ extern "C" {
|
|||
|
||||
|
||||
/**
|
||||
* @file synth.h
|
||||
* @brief Embeddable SoundFont synthesizer
|
||||
* @defgroup synth Synthesizer
|
||||
*
|
||||
* SoundFont synthesizer
|
||||
*
|
||||
* You create a new synthesizer with new_fluid_synth() and you destroy
|
||||
* it with delete_fluid_synth(). Use the fluid_settings_t structure to specify
|
||||
|
@ -43,15 +45,29 @@ extern "C" {
|
|||
*
|
||||
* The API for sending MIDI events is probably what you expect:
|
||||
* fluid_synth_noteon(), fluid_synth_noteoff(), ...
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/** @startlifecycle{Synthesizer} */
|
||||
FLUIDSYNTH_API fluid_synth_t *new_fluid_synth(fluid_settings_t *settings);
|
||||
FLUIDSYNTH_API void delete_fluid_synth(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API fluid_settings_t *fluid_synth_get_settings(fluid_synth_t *synth);
|
||||
/** @endlifecycle */
|
||||
|
||||
/* MIDI channel messages */
|
||||
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API const char *fluid_synth_error(fluid_synth_t *synth);
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* @defgroup midi_messages MIDI Channel Messages
|
||||
* @ingroup synth
|
||||
*
|
||||
* The MIDI channel message functions are mostly directly named after their
|
||||
* counterpart MIDI messages. They are a high-level interface to controlling
|
||||
* the synthesizer, playing notes and changing note and channel parameters.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
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);
|
||||
|
@ -84,28 +100,42 @@ 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);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_gen(fluid_synth_t *synth, int chan,
|
||||
int param, float value);
|
||||
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param);
|
||||
/* @} MIDI Channel Messages */
|
||||
|
||||
|
||||
/**
|
||||
* The midi channel type used by fluid_synth_set_channel_type()
|
||||
* @defgroup voice_control Synthesis Voice Control
|
||||
* @ingroup synth
|
||||
*
|
||||
* Low-level access to synthesis voices.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
enum fluid_midi_channel_type
|
||||
{
|
||||
CHANNEL_TYPE_MELODIC = 0, /**< Melodic midi channel */
|
||||
CHANNEL_TYPE_DRUM = 1 /**< Drum midi channel */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API 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);
|
||||
|
||||
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);
|
||||
/* @} Voice Control */
|
||||
|
||||
/* SoundFont management */
|
||||
|
||||
/**
|
||||
* @defgroup soundfont_management SoundFont Management
|
||||
* @ingroup synth
|
||||
*
|
||||
* Functions to load and unload SoundFonts.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
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, int id);
|
||||
|
@ -119,26 +149,52 @@ 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);
|
||||
/* @} Soundfont Management */
|
||||
|
||||
|
||||
/* Reverb */
|
||||
/**
|
||||
* @defgroup reverb_effect Effect - Reverb
|
||||
* @ingroup synth
|
||||
*
|
||||
* Functions for configuring the built-in reverb effect
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on);
|
||||
FLUIDSYNTH_API int fluid_synth_reverb_on(fluid_synth_t *synth, int fx_group, int on);
|
||||
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize,
|
||||
double damping, double width, double level);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level);
|
||||
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t *synth);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double roomsize);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_group_damp(fluid_synth_t *synth, int fx_group, double damping);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_group_width(fluid_synth_t *synth, int fx_group, double width);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_group_level(fluid_synth_t *synth, int fx_group, double level);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_get_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double *roomsize);
|
||||
FLUIDSYNTH_API int fluid_synth_get_reverb_group_damp(fluid_synth_t *synth, int fx_group, double *damping);
|
||||
FLUIDSYNTH_API int fluid_synth_get_reverb_group_width(fluid_synth_t *synth, int fx_group, double *width);
|
||||
FLUIDSYNTH_API int fluid_synth_get_reverb_group_level(fluid_synth_t *synth, int fx_group, double *level);
|
||||
/* @} Reverb */
|
||||
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize,
|
||||
double damping, double width, double level);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, 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);
|
||||
|
||||
|
||||
/* Chorus */
|
||||
/**
|
||||
* @defgroup chorus_effect Effect - Chorus
|
||||
* @ingroup synth
|
||||
*
|
||||
* Functions for configuring the built-in chorus effect
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Chorus modulation waveform type.
|
||||
|
@ -149,34 +205,53 @@ enum fluid_chorus_mod
|
|||
FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level,
|
||||
double speed, double depth_ms, int type);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, 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(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on);
|
||||
FLUIDSYNTH_API int fluid_synth_chorus_on(fluid_synth_t *synth, int fx_group, int on);
|
||||
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level,
|
||||
double speed, double depth_ms, int type);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type);
|
||||
|
||||
/* Audio and MIDI channels */
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_speed(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth);
|
||||
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_group_nr(fluid_synth_t *synth, int fx_group, int nr);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_group_level(fluid_synth_t *synth, int fx_group, double level);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_group_speed(fluid_synth_t *synth, int fx_group, double speed);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_group_depth(fluid_synth_t *synth, int fx_group, double depth_ms);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_group_type(fluid_synth_t *synth, int fx_group, int type);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_group_nr(fluid_synth_t *synth, int fx_group, int *nr);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_group_level(fluid_synth_t *synth, int fx_group, double *level);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_group_speed(fluid_synth_t *synth, int fx_group, double *speed);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_group_depth(fluid_synth_t *synth, int fx_group, double *depth_ms);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_group_type(fluid_synth_t *synth, int fx_group, int *type);
|
||||
/* @} Chorus */
|
||||
|
||||
/**
|
||||
* @defgroup synthesis_params Synthesis Parameters
|
||||
* @ingroup synth
|
||||
*
|
||||
* Functions to control and query synthesis parameters like gain and
|
||||
* polyphony count.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
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);
|
||||
FLUIDSYNTH_API int fluid_synth_count_effects_groups(fluid_synth_t *synth);
|
||||
|
||||
|
||||
/* Synthesis parameters */
|
||||
|
||||
FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate);
|
||||
FLUID_DEPRECATED 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);
|
||||
|
@ -201,15 +276,28 @@ enum fluid_interp
|
|||
FLUID_INTERP_HIGHEST = FLUID_INTERP_7THORDER, /**< Highest interpolation method */
|
||||
};
|
||||
|
||||
/* Generator interface */
|
||||
/**
|
||||
* Enum used with fluid_synth_add_default_mod() to specify how to handle duplicate modulators.
|
||||
*/
|
||||
enum fluid_synth_add_mod
|
||||
{
|
||||
FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */
|
||||
FLUID_SYNTH_ADD, /**< Sum up modulator amounts */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_gen(fluid_synth_t *synth, int chan,
|
||||
int param, float value);
|
||||
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param);
|
||||
FLUIDSYNTH_API int fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode);
|
||||
FLUIDSYNTH_API int fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod);
|
||||
/* @} Synthesis Parameters */
|
||||
|
||||
|
||||
/* Tuning */
|
||||
|
||||
/**
|
||||
* @defgroup tuning MIDI Tuning
|
||||
* @ingroup synth
|
||||
*
|
||||
* The functions in this section implement the MIDI Tuning Standard interface.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_activate_key_tuning(fluid_synth_t *synth, int bank, int prog,
|
||||
const char *name, const double *pitch, int apply);
|
||||
|
@ -229,60 +317,46 @@ 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);
|
||||
/* @} MIDI Tuning */
|
||||
|
||||
/* Misc */
|
||||
|
||||
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t *synth);
|
||||
const char *fluid_synth_error(fluid_synth_t *synth);
|
||||
|
||||
|
||||
/* Default modulators */
|
||||
|
||||
/**
|
||||
* Enum used with fluid_synth_add_default_mod() to specify how to handle duplicate modulators.
|
||||
*/
|
||||
enum fluid_synth_add_mod
|
||||
{
|
||||
FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */
|
||||
FLUID_SYNTH_ADD, /**< Sum up modulator amounts */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode);
|
||||
FLUIDSYNTH_API int fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod);
|
||||
|
||||
|
||||
/*
|
||||
* Synthesizer plugin
|
||||
* @defgroup audio_rendering Audio Rendering
|
||||
* @ingroup synth
|
||||
*
|
||||
* 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.
|
||||
* The functions in this section can be used to render audio directly to
|
||||
* memory buffers. They are used internally by the \ref audio_driver and \ref file_renderer,
|
||||
* but can also be used manually for custom processing of the rendered audio.
|
||||
*
|
||||
* @note Please note that all following functions block during rendering. If your goal is to
|
||||
* render real-time audio, ensure that you call these functions from a high-priority
|
||||
* thread with little to no other duties other than calling the rendering functions.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
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,
|
||||
FLUID_DEPRECATED 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 nfx, float *fx[],
|
||||
int nout, float *out[]);
|
||||
/* @} Audio Rendering */
|
||||
|
||||
|
||||
/* 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);
|
||||
/**
|
||||
* @defgroup iir_filter Effect - IIR Filter
|
||||
* @ingroup synth
|
||||
*
|
||||
* Functions for configuring the built-in IIR filter effect
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Specifies the type of filter to use for the custom IIR filter
|
||||
|
@ -306,19 +380,43 @@ enum fluid_iir_filter_flags
|
|||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int flags);
|
||||
/* @} IIR Filter */
|
||||
|
||||
|
||||
/* LADSPA */
|
||||
|
||||
#ifdef LADSPA
|
||||
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
|
||||
#endif
|
||||
|
||||
|
||||
/* API: Poly mono mode */
|
||||
|
||||
/** Interface to poly/mono mode variables
|
||||
/**
|
||||
* @defgroup channel_setup MIDI Channel Setup
|
||||
* @ingroup synth
|
||||
*
|
||||
* The functions in this section provide interfaces to change the channel type
|
||||
* and to configure basic channels, legato and portamento setups.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @name Channel Type
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* The midi channel type used by fluid_synth_set_channel_type()
|
||||
*/
|
||||
enum fluid_midi_channel_type
|
||||
{
|
||||
CHANNEL_TYPE_MELODIC = 0, /**< Melodic midi channel */
|
||||
CHANNEL_TYPE_DRUM = 1 /**< Drum midi channel */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type);
|
||||
/** @} Channel Type */
|
||||
|
||||
|
||||
/** @name Basic Channel Mode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Channel mode bits OR-ed together so that it matches with the midi spec: poly omnion (0), mono omnion (1), poly omnioff (2), mono omnioff (3)
|
||||
*/
|
||||
enum fluid_channel_mode_flags
|
||||
|
@ -327,15 +425,9 @@ enum fluid_channel_mode_flags
|
|||
FLUID_CHANNEL_OMNI_OFF = 0x02, /**< if flag is set, the basic channel is in omni off state, if not set omni is on */
|
||||
};
|
||||
|
||||
/** Indicates the breath mode a channel is set to */
|
||||
enum fluid_channel_breath_flags
|
||||
{
|
||||
FLUID_CHANNEL_BREATH_POLY = 0x10, /**< when channel is poly, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath to initial attenuation modulator */
|
||||
FLUID_CHANNEL_BREATH_MONO = 0x20, /**< when channel is mono, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath modulator */
|
||||
FLUID_CHANNEL_BREATH_SYNC = 0x40, /**< when channel is mono, this flag indicates that the breath controler(MSB)triggers noteon/noteoff on the running note */
|
||||
};
|
||||
|
||||
/** Indicates the mode a basic channel is set to */
|
||||
/**
|
||||
* Indicates the mode a basic channel is set to
|
||||
*/
|
||||
enum fluid_basic_channel_modes
|
||||
{
|
||||
FLUID_CHANNEL_MODE_MASK = (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< Mask Poly and Omni bits of #fluid_channel_mode_flags, usually only used internally */
|
||||
|
@ -354,8 +446,13 @@ FLUIDSYNTH_API int fluid_synth_get_basic_channel(fluid_synth_t *synth, int chan
|
|||
int *basic_val_out);
|
||||
FLUIDSYNTH_API int fluid_synth_set_basic_channel(fluid_synth_t *synth, int chan, int mode, int val);
|
||||
|
||||
/** Interface to mono legato mode
|
||||
*
|
||||
/** @} Basic Channel Mode */
|
||||
|
||||
/** @name Legato Mode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates the legato mode a channel is set to
|
||||
* n1,n2,n3,.. is a legato passage. n1 is the first note, and n2,n3,n4 are played legato with previous note. */
|
||||
enum fluid_channel_legato_mode
|
||||
|
@ -367,9 +464,13 @@ enum fluid_channel_legato_mode
|
|||
|
||||
FLUIDSYNTH_API int fluid_synth_set_legato_mode(fluid_synth_t *synth, int chan, int legatomode);
|
||||
FLUIDSYNTH_API int fluid_synth_get_legato_mode(fluid_synth_t *synth, int chan, int *legatomode);
|
||||
/** @} Legato Mode */
|
||||
|
||||
/** Interface to portamento mode
|
||||
*
|
||||
/** @name Portamento Mode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates the portamento mode a channel is set to
|
||||
*/
|
||||
enum fluid_channel_portamento_mode
|
||||
|
@ -377,21 +478,64 @@ enum fluid_channel_portamento_mode
|
|||
FLUID_CHANNEL_PORTAMENTO_MODE_EACH_NOTE, /**< Mode 0 - Portamento on each note (staccato or legato) */
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY, /**< Mode 1 - Portamento only on legato note */
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY, /**< Mode 2 - Portamento only on staccato note */
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_LAST /**< @internal Value defines the count of portamento modes (#fluid_channel_portamento_mode) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_LAST /**< @internal Value defines the count of portamento modes
|
||||
@warning This symbol is not part of the public API and ABI
|
||||
stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_portamento_mode(fluid_synth_t *synth,
|
||||
int chan, int portamentomode);
|
||||
FLUIDSYNTH_API int fluid_synth_get_portamento_mode(fluid_synth_t *synth,
|
||||
int chan, int *portamentomode);
|
||||
/** @} Portamento Mode */
|
||||
|
||||
/**@name Breath Mode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates the breath mode a channel is set to
|
||||
*/
|
||||
enum fluid_channel_breath_flags
|
||||
{
|
||||
FLUID_CHANNEL_BREATH_POLY = 0x10, /**< when channel is poly, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath to initial attenuation modulator */
|
||||
FLUID_CHANNEL_BREATH_MONO = 0x20, /**< when channel is mono, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath modulator */
|
||||
FLUID_CHANNEL_BREATH_SYNC = 0x40, /**< when channel is mono, this flag indicates that the breath controller(MSB)triggers noteon/noteoff on the running note */
|
||||
};
|
||||
|
||||
/* Interface to breath mode */
|
||||
FLUIDSYNTH_API int fluid_synth_set_breath_mode(fluid_synth_t *synth,
|
||||
int chan, int breathmode);
|
||||
FLUIDSYNTH_API int fluid_synth_get_breath_mode(fluid_synth_t *synth,
|
||||
int chan, int *breathmode);
|
||||
/** @} Breath Mode */
|
||||
/* @} MIDI Channel Setup */
|
||||
|
||||
|
||||
/** @ingroup settings */
|
||||
FLUIDSYNTH_API fluid_settings_t *fluid_synth_get_settings(fluid_synth_t *synth);
|
||||
|
||||
/** @ingroup soundfont_loader */
|
||||
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t *synth, fluid_sfloader_t *loader);
|
||||
|
||||
/** @ingroup soundfont_loader */
|
||||
FLUIDSYNTH_API fluid_preset_t *fluid_synth_get_channel_preset(fluid_synth_t *synth, int chan);
|
||||
|
||||
/** @ingroup midi_input */
|
||||
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void *data, fluid_midi_event_t *event);
|
||||
|
||||
/** @ingroup soundfonts */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_pin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num);
|
||||
|
||||
/** @ingroup soundfonts */
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_unpin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num);
|
||||
|
||||
#ifdef LADSPA
|
||||
/** @ingroup ladspa */
|
||||
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,8 +29,10 @@ extern "C" {
|
|||
|
||||
|
||||
/**
|
||||
* @file types.h
|
||||
* @defgroup Types Types
|
||||
* @brief Type declarations
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct _fluid_hashtable_t fluid_settings_t; /**< Configuration settings instance */
|
||||
|
@ -66,6 +68,18 @@ typedef int fluid_ostream_t; /**< Output stream descriptor */
|
|||
|
||||
typedef short fluid_seq_id_t; /**< Unique client IDs used by the sequencer and #fluid_event_t, obtained by fluid_sequencer_register_client() and fluid_sequencer_register_fluidsynth() */
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1800)
|
||||
typedef __int64 fluid_long_long_t; // even on 32bit windows
|
||||
#else
|
||||
/**
|
||||
* A typedef for C99's type long long, which is at least 64-bit wide, as guaranteed by the C99.
|
||||
* @p __int64 will be used as replacement for VisualStudio 2010 and older.
|
||||
*/
|
||||
typedef long long fluid_long_long_t;
|
||||
#endif
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -26,16 +26,21 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @file voice.h
|
||||
* @brief Synthesis voice manipulation functions.
|
||||
* @defgroup voices Voice Manipulation
|
||||
* @ingroup soundfonts
|
||||
*
|
||||
* Synthesis voice manipulation functions.
|
||||
*
|
||||
* The interface to the synthesizer's voices.
|
||||
* Examples on using them can be found in fluid_defsfont.c.
|
||||
* Examples on using them can be found in the source code of the default SoundFont
|
||||
* loader (fluid_defsfont.c).
|
||||
*
|
||||
* Most of these functions should only be called from within synthesis context,
|
||||
* such as the SoundFont loader's noteon method.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Enum used with fluid_voice_add_mod() to specify how to handle duplicate modulators.
|
||||
*/
|
||||
|
@ -63,7 +68,7 @@ FLUIDSYNTH_API int fluid_voice_is_sustained(const fluid_voice_t *voice);
|
|||
FLUIDSYNTH_API int fluid_voice_is_sostenuto(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t *s);
|
||||
FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t *voice, int gen);
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ fluid_channel_init(fluid_channel_t *chan)
|
|||
|
||||
/*
|
||||
@param is_all_ctrl_off if nonzero, only resets some controllers, according to
|
||||
http://www.midi.org/techspecs/rp15.php
|
||||
https://www.midi.org/techspecs/rp15.php
|
||||
*/
|
||||
void
|
||||
fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off)
|
||||
|
@ -211,7 +211,7 @@ fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off)
|
|||
/* 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 */
|
||||
See https://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,6 @@ delete_fluid_channel(fluid_channel_t *chan)
|
|||
FLUID_FREE(chan);
|
||||
}
|
||||
|
||||
/* FIXME - Calls fluid_channel_init() potentially in synthesis context */
|
||||
void
|
||||
fluid_channel_reset(fluid_channel_t *chan)
|
||||
{
|
||||
|
@ -324,7 +323,7 @@ fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb)
|
|||
{
|
||||
/* 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 */
|
||||
reference: https://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
|
||||
chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
|
||||
return;
|
||||
}
|
||||
|
@ -413,7 +412,7 @@ fluid_channel_update_legato_staccato_state(fluid_channel_t *chan)
|
|||
* prev_note keeps a trace of the note prior i_last note.
|
||||
* FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing state.
|
||||
*
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
* More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
*/
|
||||
void
|
||||
fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key,
|
||||
|
@ -523,7 +522,7 @@ fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_p
|
|||
* - prev_note keeps a trace of the note removed if it is i_last.
|
||||
* - FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing state.
|
||||
*
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
* More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
*/
|
||||
void
|
||||
fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev)
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
* The delay i is controlled by a sine or triangle modulation i ( 1 <= i <= n).
|
||||
*
|
||||
* The chorus unit process a monophonic input signal and produces stereo output
|
||||
* controled by WIDTH macro.
|
||||
* controlled by WIDTH macro.
|
||||
* Actually WIDTH is fixed to maximum value. But in the future, we could add a
|
||||
* setting (e.g "synth.chorus.width") allowing the user to get a gradually stereo
|
||||
* effect from minimum (monophonic) to maximum stereo effect.
|
||||
|
@ -79,7 +79,7 @@
|
|||
* The advantages are:
|
||||
* - Avoiding a lost of 608272 memory bytes when lfo speed is low (0.3Hz).
|
||||
* - Allows to diminish the lfo speed lower limit to 0.1Hz instead of 0.3Hz.
|
||||
* A speed of 0.1 is interresting for chorus. Using a lookuptable for 0.1Hz
|
||||
* A speed of 0.1 is interesting for chorus. Using a lookuptable for 0.1Hz
|
||||
* would require too much memory (1824816 bytes).
|
||||
* - Interpolation make use of first order all-pass interpolator instead of
|
||||
* bandlimited interpolation.
|
||||
|
@ -244,7 +244,7 @@ struct _fluid_chorus_t
|
|||
static void set_sinus_frequency(sinus_modulator *mod,
|
||||
float freq, float sample_rate, float phase)
|
||||
{
|
||||
fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* intial angle */
|
||||
fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* initial angle */
|
||||
fluid_real_t a;
|
||||
|
||||
mod->a1 = 2 * FLUID_COS(w);
|
||||
|
@ -261,7 +261,7 @@ static void set_sinus_frequency(sinus_modulator *mod,
|
|||
y(n) = a1 . y(n-1) - y(n-2)
|
||||
out = a1 . buffer1 - buffer2
|
||||
|
||||
@param pointer on modulator structure.
|
||||
@param mod pointer on modulator structure.
|
||||
@return current value of the modulator sine wave.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod)
|
||||
|
@ -293,6 +293,11 @@ static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod)
|
|||
in the period relative to the beginning of the period.
|
||||
For example: 0 is the beginning of the period, 1/4 is at 1/4 of the period
|
||||
relative to the beginning.
|
||||
|
||||
@param mod pointer on modulator structure.
|
||||
@param freq frequency of the oscillator in Hz.
|
||||
@param sample_rate sample rate on audio output in Hz.
|
||||
@param frac_phase initial phase (see comment above).
|
||||
-----------------------------------------------------------------------------*/
|
||||
static void set_triangle_frequency(triang_modulator *mod, float freq,
|
||||
float sample_rate, float frac_phase)
|
||||
|
@ -313,7 +318,7 @@ static void set_triangle_frequency(triang_modulator *mod, float freq,
|
|||
mod->inc = 4 / ns_period; /* positive slope */
|
||||
|
||||
/* The initial value and the sign of the slope depend of initial phase:
|
||||
intial value = = (ns_period * frac_phase) * slope
|
||||
initial value = = (ns_period * frac_phase) * slope
|
||||
*/
|
||||
mod->val = ns_period * frac_phase * mod->inc;
|
||||
|
||||
|
@ -333,6 +338,9 @@ static void set_triangle_frequency(triang_modulator *mod, float freq,
|
|||
/*-----------------------------------------------------------------------------
|
||||
Get current value of triangular oscillator
|
||||
y(n) = y(n-1) + dy
|
||||
|
||||
@param mod pointer on triang_modulator structure.
|
||||
@return current value.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static FLUID_INLINE fluid_real_t get_mod_triang(triang_modulator *mod)
|
||||
{
|
||||
|
@ -354,18 +362,20 @@ static FLUID_INLINE fluid_real_t get_mod_triang(triang_modulator *mod)
|
|||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
Reads the sample value out of the modulated delay line.
|
||||
@param mdl, pointer on modulated delay line.
|
||||
@return the sample value.
|
||||
|
||||
@param chorus pointer on chorus unit.
|
||||
@param mod pointer on modulator structure.
|
||||
@return current value.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus,
|
||||
modulator *mod)
|
||||
modulator *mod)
|
||||
{
|
||||
fluid_real_t out_index; /* new modulated index position */
|
||||
int int_out_index; /* integer part of out_index */
|
||||
fluid_real_t out; /* value to return */
|
||||
|
||||
/* Checks if the modulator must be updated (every mod_rate samples). */
|
||||
/* Important: center_pos_mod must be used immediatly for the
|
||||
/* Important: center_pos_mod must be used immediately for the
|
||||
first sample. So, mdl->index_rate must be initialized
|
||||
to mdl->mod_rate (new_mod_delay_line()) */
|
||||
|
||||
|
@ -421,7 +431,7 @@ static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus,
|
|||
mod->line_out -= chorus->size;
|
||||
}
|
||||
|
||||
/* Fractional interpolation beetween next sample (at next position) and
|
||||
/* Fractional interpolation between next sample (at next position) and
|
||||
previous output added to current sample.
|
||||
*/
|
||||
out += mod->frac_pos_mod * (chorus->line[mod->line_out] - mod->buffer);
|
||||
|
@ -431,6 +441,9 @@ static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus,
|
|||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Push a sample val into the delay line
|
||||
|
||||
@param dl delay line to push value into.
|
||||
@param val the value to push into dl.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#define push_in_delay_line(dl, val) \
|
||||
{\
|
||||
|
@ -444,13 +457,15 @@ static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus,
|
|||
|
||||
center_pos_mod is initialized so that the delay between center_pos_mod and
|
||||
line_in is: mod_depth + INTERP_SAMPLES_NBR.
|
||||
|
||||
@param chorus pointer on chorus unit.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static void set_center_position(fluid_chorus_t *chorus)
|
||||
{
|
||||
int center;
|
||||
|
||||
/* Sets the modulation rate. This rate defines how often
|
||||
the center position (center_pos_mod ) is modulated .
|
||||
the center position (center_pos_mod ) is modulated .
|
||||
The value is expressed in samples. The default value is 1 that means that
|
||||
center_pos_mod is updated at every sample.
|
||||
For example with a value of 2, the center position position will be
|
||||
|
@ -479,11 +494,68 @@ static void set_center_position(fluid_chorus_t *chorus)
|
|||
chorus->center_pos_mod = (fluid_real_t)center;
|
||||
|
||||
/* index rate to control when to update center_pos_mod */
|
||||
/* Important: must be set to get center_pos_mod immediatly used for the
|
||||
/* Important: must be set to get center_pos_mod immediately used for the
|
||||
reading of first sample (see get_mod_delay()) */
|
||||
chorus->index_rate = chorus->mod_rate;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Update internal parameters dependent of sample rate.
|
||||
- mod_depth.
|
||||
- mod_rate, center_pos_mod, and index rate.
|
||||
- modulators frequency.
|
||||
|
||||
@param chorus, pointer on chorus unit.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static void update_parameters_from_sample_rate(fluid_chorus_t *chorus)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* initialize modulation depth (peak to peak) (in samples) */
|
||||
/* convert modulation depth in ms to sample number */
|
||||
chorus->mod_depth = (int)(chorus->depth_ms / 1000.0
|
||||
* chorus->sample_rate);
|
||||
|
||||
/* the delay line is fixed. So we reduce mod_depth (if necessary) */
|
||||
if(chorus->mod_depth > MAX_SAMPLES)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).",
|
||||
MAX_SAMPLES);
|
||||
chorus->mod_depth = MAX_SAMPLES;
|
||||
/* set depth_ms to maximum to avoid spamming console with above warning */
|
||||
chorus->depth_ms = (chorus->mod_depth * 1000) / chorus->sample_rate;
|
||||
}
|
||||
|
||||
chorus->mod_depth /= 2; /* amplitude is peak to peek / 2 */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("depth_ms:%f, depth_samples/2:%d\n", chorus->depth_ms, chorus->mod_depth);
|
||||
#endif
|
||||
|
||||
/* Initializes the modulated center position:
|
||||
mod_rate, center_pos_mod, and index rate.
|
||||
*/
|
||||
set_center_position(chorus); /* must be called before set_xxxx_frequency() */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("mod_rate:%d\n", chorus->mod_rate);
|
||||
#endif
|
||||
|
||||
/* initialize modulator frequency */
|
||||
for(i = 0; i < chorus->number_blocks; i++)
|
||||
{
|
||||
set_sinus_frequency(&chorus->mod[i].sinus,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)((360.0f / (float) chorus->number_blocks) * i));
|
||||
|
||||
set_triangle_frequency(&chorus->mod[i].triang,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)i / chorus->number_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Modulated delay line initialization.
|
||||
|
||||
|
@ -491,7 +563,7 @@ static void set_center_position(fluid_chorus_t *chorus)
|
|||
Remark: the function sets the internal size accordling to the length delay_length.
|
||||
The size is augmented by INTERP_SAMPLES_NBR to take account of interpolation.
|
||||
|
||||
@param chorus, pointer chorus unit.
|
||||
@param chorus, pointer on chorus unit.
|
||||
@param delay_length the length of the delay line in samples.
|
||||
@return FLUID_OK if success , FLUID_FAILED if memory error.
|
||||
|
||||
|
@ -545,8 +617,11 @@ static int new_mod_delay_line(fluid_chorus_t *chorus, int delay_length)
|
|||
API
|
||||
------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Create the chorus unit.
|
||||
* @sample_rate audio sample rate in Hz.
|
||||
* Create the chorus unit. Once created the chorus have no parameters set, so
|
||||
* fluid_chorus_set() must be called at least one time after calling
|
||||
* new_fluid_chorus().
|
||||
*
|
||||
* @param sample_rate, audio sample rate in Hz.
|
||||
* @return pointer on chorus unit.
|
||||
*/
|
||||
fluid_chorus_t *
|
||||
|
@ -577,15 +652,11 @@ new_fluid_chorus(fluid_real_t sample_rate)
|
|||
|
||||
if(new_mod_delay_line(chorus, MAX_SAMPLES) == FLUID_FAILED)
|
||||
{
|
||||
goto error_recovery;
|
||||
delete_fluid_chorus(chorus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return chorus;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_chorus(chorus);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -628,22 +699,21 @@ fluid_chorus_reset(fluid_chorus_t *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 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.1-5.0)
|
||||
* this value).
|
||||
* @param level Chorus level (0.0-10.0).
|
||||
* @param speed Chorus speed in Hz (0.1-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)
|
||||
* 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, fluid_real_t level,
|
||||
fluid_real_t speed, fluid_real_t depth_ms, int type)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(set & FLUID_CHORUS_SET_NR) /* number of block */
|
||||
{
|
||||
chorus->number_blocks = nr;
|
||||
|
@ -713,45 +783,8 @@ fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
|||
chorus->level = 0.1;
|
||||
}
|
||||
|
||||
/* initialize modulation depth (peak to peak) (in samples)*/
|
||||
chorus->mod_depth = (int)(chorus->depth_ms / 1000.0 /* convert modulation depth in ms to s*/
|
||||
* chorus->sample_rate);
|
||||
|
||||
if(chorus->mod_depth > MAX_SAMPLES)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
|
||||
chorus->mod_depth = MAX_SAMPLES;
|
||||
// set depth to maximum to avoid spamming console with above warning
|
||||
chorus->depth_ms = (chorus->mod_depth * 1000) / chorus->sample_rate;
|
||||
}
|
||||
|
||||
chorus->mod_depth /= 2; /* amplitude is peak to peek / 2 */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("depth_ms:%f, depth_samples/2:%d\n", chorus->depth_ms, chorus->mod_depth);
|
||||
#endif
|
||||
/* Initializes the modulated center position:
|
||||
mod_rate, center_pos_mod, and index rate.
|
||||
*/
|
||||
set_center_position(chorus); /* must be called before set_xxxx_frequency() */
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("mod_rate:%d\n", chorus->mod_rate);
|
||||
#endif
|
||||
|
||||
/* initialize modulator frequency */
|
||||
for(i = 0; i < chorus->number_blocks; i++)
|
||||
{
|
||||
set_sinus_frequency(&chorus->mod[i].sinus,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)((360.0f / (float) chorus->number_blocks) * i));
|
||||
|
||||
set_triangle_frequency(&chorus->mod[i].triang,
|
||||
chorus->speed_Hz * chorus->mod_rate,
|
||||
chorus->sample_rate,
|
||||
/* phase offset between modulators waveform */
|
||||
(float)i / chorus->number_blocks);
|
||||
}
|
||||
/* update parameters dependant of sample rate */
|
||||
update_parameters_from_sample_rate(chorus);
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
printf("lfo type:%d\n", chorus->type);
|
||||
|
@ -800,7 +833,7 @@ fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
|||
|
||||
fluid_real_t wet = chorus->level * SCALE_WET ;
|
||||
|
||||
/* wet1 and wet2 are used by the stereo effect controled by the width setting
|
||||
/* wet1 and wet2 are used by the stereo effect controlled by the width setting
|
||||
for producing a stereo ouptput from a monophonic chorus signal.
|
||||
Please see the note above about a side effect tendency */
|
||||
|
||||
|
@ -859,6 +892,32 @@ fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Applies a sample rate change on the chorus.
|
||||
* Note that while the chorus is used by calling any fluid_chorus_processXXX()
|
||||
* function, calling fluid_chorus_samplerate_change() isn't multi task safe.
|
||||
* To deal properly with this issue follow the steps:
|
||||
* 1) Stop chorus processing (i.e disable calling to any fluid_chorus_processXXX().
|
||||
* chorus functions.
|
||||
* 2) Change sample rate by calling fluid_chorus_samplerate_change().
|
||||
* 3) Restart chorus processing (i.e enabling calling any fluid_chorus_processXXX()
|
||||
* chorus functions.
|
||||
*
|
||||
* Another solution is to substitute step (2):
|
||||
* 2.1) delete the chorus by calling delete_fluid_chorus().
|
||||
* 2.2) create the chorus by calling new_fluid_chorus().
|
||||
*
|
||||
* @param chorus pointer on the chorus.
|
||||
* @param sample_rate new sample rate value.
|
||||
*/
|
||||
void
|
||||
fluid_chorus_samplerate_change(fluid_chorus_t *chorus, fluid_real_t sample_rate)
|
||||
{
|
||||
chorus->sample_rate = sample_rate;
|
||||
|
||||
/* update parameters dependant of sample rate */
|
||||
update_parameters_from_sample_rate(chorus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process chorus by mixing the result in output buffer.
|
||||
|
@ -921,13 +980,17 @@ void fluid_chorus_processmix(fluid_chorus_t *chorus, const fluid_real_t *in,
|
|||
d_out[1] += out ;
|
||||
}
|
||||
|
||||
/* Write the current input sample into the circular buffer.
|
||||
* Note that 'in' may be aliased with 'left_out'. Hence this must be done
|
||||
* before "processing stereo unit" (below). This ensures input buffer
|
||||
* not being overwritten by stereo unit output.
|
||||
*/
|
||||
push_in_delay_line(chorus, in[sample_index]);
|
||||
|
||||
/* process stereo unit */
|
||||
/* Add the chorus stereo unit d_out to left and right output */
|
||||
left_out[sample_index] += d_out[0] * chorus->wet1 + d_out[1] * chorus->wet2;
|
||||
right_out[sample_index] += d_out[1] * chorus->wet1 + d_out[0] * chorus->wet2;
|
||||
|
||||
/* Write the current input sample into the circular buffer */
|
||||
push_in_delay_line(chorus, in[sample_index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -993,12 +1056,16 @@ void fluid_chorus_processreplace(fluid_chorus_t *chorus, const fluid_real_t *in,
|
|||
d_out[1] += out ;
|
||||
}
|
||||
|
||||
/* Write the current input sample into the circular buffer.
|
||||
* Note that 'in' may be aliased with 'left_out'. Hence this must be done
|
||||
* before "processing stereo unit" (below). This ensures input buffer
|
||||
* not being overwritten by stereo unit output.
|
||||
*/
|
||||
push_in_delay_line(chorus, in[sample_index]);
|
||||
|
||||
/* process stereo unit */
|
||||
/* store the chorus stereo unit d_out to left and right output */
|
||||
left_out[sample_index] = d_out[0] * chorus->wet1 + d_out[1] * chorus->wet2;
|
||||
right_out[sample_index] = d_out[1] * chorus->wet1 + d_out[0] * chorus->wet2;
|
||||
|
||||
/* Write the current input sample into the circular buffer */
|
||||
push_in_delay_line(chorus, in[sample_index]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,14 +27,28 @@
|
|||
|
||||
typedef struct _fluid_chorus_t fluid_chorus_t;
|
||||
|
||||
/* enum describing each chorus parameter */
|
||||
enum fluid_chorus_param
|
||||
{
|
||||
FLUID_CHORUS_NR, /**< number of delay line */
|
||||
FLUID_CHORUS_LEVEL, /**< output level */
|
||||
FLUID_CHORUS_SPEED, /**< lfo frequency */
|
||||
FLUID_CHORUS_DEPTH, /**< modulation depth */
|
||||
FLUID_CHORUS_TYPE, /**< type of waveform */
|
||||
FLUID_CHORUS_PARAM_LAST /* number of enum fluid_chorus_param */
|
||||
};
|
||||
|
||||
/* return a bit flag from param: 2^param */
|
||||
#define FLUID_CHORPARAM_TO_SETFLAG(param) (1 << param)
|
||||
|
||||
/** 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_NR = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_NR),
|
||||
FLUID_CHORUS_SET_LEVEL = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_LEVEL),
|
||||
FLUID_CHORUS_SET_SPEED = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_SPEED),
|
||||
FLUID_CHORUS_SET_DEPTH = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_DEPTH),
|
||||
FLUID_CHORUS_SET_TYPE = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_TYPE),
|
||||
|
||||
/** Value for fluid_chorus_set() which sets all chorus parameters. */
|
||||
FLUID_CHORUS_SET_ALL = FLUID_CHORUS_SET_NR
|
||||
|
@ -53,6 +67,8 @@ void fluid_chorus_reset(fluid_chorus_t *chorus);
|
|||
|
||||
void fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
||||
fluid_real_t speed, fluid_real_t depth_ms, int type);
|
||||
void
|
||||
fluid_chorus_samplerate_change(fluid_chorus_t *chorus, fluid_real_t sample_rate);
|
||||
|
||||
void fluid_chorus_processmix(fluid_chorus_t *chorus, const fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "fluid_conv.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_conv_tables.c"
|
||||
#include "fluid_conv_tables.inc.h"
|
||||
|
||||
/*
|
||||
* Converts absolute cents to Hertz
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
Note about usefulness of 24 bits:
|
||||
1)Even fluidsynth is a 24 bit synth, this format is only relevant if
|
||||
the sample format coming from the soundfont is 24 bits and the audio sample format
|
||||
choosen by the application (audio.sample.format) is not 16 bits.
|
||||
chosen by the application (audio.sample.format) is not 16 bits.
|
||||
|
||||
2)When the sample soundfont is 16 bits, the internal 24 bits number have
|
||||
16 bits msb and lsb to 0. Consequently, at the DAC output, the dynamic range of
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#define EMU_ATTENUATION_FACTOR (0.4f)
|
||||
|
||||
/* Dynamic sample loading functions */
|
||||
static int pin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);
|
||||
static int unpin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);
|
||||
static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);
|
||||
static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);
|
||||
static void unload_sample(fluid_sample_t *sample);
|
||||
|
@ -228,6 +230,17 @@ int delete_fluid_defsfont(fluid_defsfont_t *defsfont)
|
|||
|
||||
fluid_return_val_if_fail(defsfont != NULL, FLUID_OK);
|
||||
|
||||
/* If we use dynamic sample loading, make sure we unpin any
|
||||
* pinned presets before removing this soundfont */
|
||||
if(defsfont->dynamic_samples)
|
||||
{
|
||||
for(list = defsfont->preset; list; list = fluid_list_next(list))
|
||||
{
|
||||
preset = (fluid_preset_t *)fluid_list_get(list);
|
||||
unpin_preset_samples(defsfont, preset);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that no samples are currently used */
|
||||
for(list = defsfont->sample; list; list = fluid_list_next(list))
|
||||
{
|
||||
|
@ -336,7 +349,7 @@ int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, f
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/* Ogg Vorbis samples already have loop pointers relative to the invididual decompressed sample,
|
||||
/* Ogg Vorbis samples already have loop pointers relative to the individual decompressed sample,
|
||||
* but SF2 samples are relative to sample chunk start, so they need to be adjusted */
|
||||
if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))
|
||||
{
|
||||
|
@ -361,6 +374,7 @@ int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdat
|
|||
fluid_list_t *list;
|
||||
fluid_sample_t *sample;
|
||||
int sf3_file = (sfdata->version.major == 3);
|
||||
int sample_parsing_result = FLUID_OK;
|
||||
|
||||
/* For SF2 files, we load the sample data in one large block */
|
||||
if(!sf3_file)
|
||||
|
@ -379,6 +393,8 @@ int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdat
|
|||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel
|
||||
#pragma omp single
|
||||
for(list = defsfont->sample; list; list = fluid_list_next(list))
|
||||
{
|
||||
sample = fluid_list_get(list);
|
||||
|
@ -387,26 +403,37 @@ int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdat
|
|||
{
|
||||
/* SF3 samples get loaded individually, as most (or all) of them are in Ogg Vorbis format
|
||||
* anyway */
|
||||
if(fluid_defsfont_load_sampledata(defsfont, sfdata, sample) == FLUID_FAILED)
|
||||
#pragma omp task firstprivate(sample,sfdata,defsfont) shared(sample_parsing_result) default(none)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Failed to load sample '%s'", sample->name);
|
||||
return FLUID_FAILED;
|
||||
if(fluid_defsfont_load_sampledata(defsfont, sfdata, sample) == FLUID_FAILED)
|
||||
{
|
||||
#pragma omp critical
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Failed to load sample '%s'", sample->name);
|
||||
sample_parsing_result = FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));
|
||||
fluid_voice_optimize_sample(sample);
|
||||
}
|
||||
}
|
||||
|
||||
fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Data pointers of SF2 samples point to large sample data block loaded above */
|
||||
sample->data = defsfont->sampledata;
|
||||
sample->data24 = defsfont->sample24data;
|
||||
fluid_sample_sanitize_loop(sample, defsfont->samplesize);
|
||||
#pragma omp task firstprivate(sample, defsfont) default(none)
|
||||
{
|
||||
/* Data pointers of SF2 samples point to large sample data block loaded above */
|
||||
sample->data = defsfont->sampledata;
|
||||
sample->data24 = defsfont->sample24data;
|
||||
fluid_sample_sanitize_loop(sample, defsfont->samplesize);
|
||||
fluid_voice_optimize_sample(sample);
|
||||
}
|
||||
}
|
||||
|
||||
fluid_voice_optimize_sample(sample);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
return sample_parsing_result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -506,7 +533,7 @@ int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t
|
|||
goto err_exit;
|
||||
}
|
||||
|
||||
if(fluid_defpreset_import_sfont(defpreset, sfpreset, defsfont) != FLUID_OK)
|
||||
if(fluid_defpreset_import_sfont(defpreset, sfpreset, defsfont, sfdata) != FLUID_OK)
|
||||
{
|
||||
goto err_exit;
|
||||
}
|
||||
|
@ -535,7 +562,7 @@ err_exit:
|
|||
*/
|
||||
int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample)
|
||||
{
|
||||
defsfont->sample = fluid_list_append(defsfont->sample, sample);
|
||||
defsfont->sample = fluid_list_prepend(defsfont->sample, sample);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
@ -554,16 +581,16 @@ int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *def
|
|||
fluid_defpreset_preset_noteon,
|
||||
fluid_defpreset_preset_delete);
|
||||
|
||||
if(defsfont->dynamic_samples)
|
||||
{
|
||||
preset->notify = dynamic_samples_preset_notify;
|
||||
}
|
||||
|
||||
if(preset == NULL)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if(defsfont->dynamic_samples)
|
||||
{
|
||||
preset->notify = dynamic_samples_preset_notify;
|
||||
}
|
||||
|
||||
fluid_preset_set_data(preset, defpreset);
|
||||
|
||||
defsfont->preset = fluid_list_append(defsfont->preset, preset);
|
||||
|
@ -637,6 +664,7 @@ new_fluid_defpreset(void)
|
|||
defpreset->num = 0;
|
||||
defpreset->global_zone = NULL;
|
||||
defpreset->zone = NULL;
|
||||
defpreset->pinned = FALSE;
|
||||
return defpreset;
|
||||
}
|
||||
|
||||
|
@ -776,7 +804,7 @@ fluid_defpreset_noteon_add_mod_to_voice(fluid_voice_t *voice,
|
|||
/* Although local_mod and global_mod lists was limited to
|
||||
FLUID_NUM_MOD at soundfont loading time, it is possible that
|
||||
local + global modulators exceeds FLUID_NUM_MOD.
|
||||
So, checks if mod_list_count reachs the limit.
|
||||
So, checks if mod_list_count reaches the limit.
|
||||
*/
|
||||
if(mod_list_count >= FLUID_NUM_MOD)
|
||||
{
|
||||
|
@ -805,7 +833,7 @@ fluid_defpreset_noteon_add_mod_to_voice(fluid_voice_t *voice,
|
|||
*/
|
||||
|
||||
/* Restrict identity check to the actual number of voice modulators */
|
||||
/* Acual number of voice modulators : defaults + [instruments] */
|
||||
/* Actual number of voice modulators : defaults + [instruments] */
|
||||
identity_limit_count = voice->mod_count;
|
||||
|
||||
for(i = 0; i < mod_list_count; i++)
|
||||
|
@ -1000,7 +1028,8 @@ fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_
|
|||
int
|
||||
fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset,
|
||||
SFPreset *sfpreset,
|
||||
fluid_defsfont_t *defsfont)
|
||||
fluid_defsfont_t *defsfont,
|
||||
SFData *sfdata)
|
||||
{
|
||||
fluid_list_t *p;
|
||||
SFZone *sfzone;
|
||||
|
@ -1033,7 +1062,7 @@ fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset,
|
|||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if(fluid_preset_zone_import_sfont(zone, sfzone, defsfont) != FLUID_OK)
|
||||
if(fluid_preset_zone_import_sfont(zone, sfzone, defsfont, sfdata) != FLUID_OK)
|
||||
{
|
||||
delete_fluid_preset_zone(zone);
|
||||
return FLUID_FAILED;
|
||||
|
@ -1396,8 +1425,13 @@ fluid_zone_gen_import_sfont(fluid_gen_t *gen, fluid_zone_range_t *range, SFZone
|
|||
gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
|
||||
case GEN_INSTRUMENT:
|
||||
case GEN_SAMPLEID:
|
||||
gen[sfgen->id].val = (fluid_real_t) sfgen->amount.uword;
|
||||
gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* FIXME: some generators have an unsigne word amount value but i don't know which ones */
|
||||
gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
||||
gen[sfgen->id].flags = GEN_SET;
|
||||
break;
|
||||
|
@ -1413,7 +1447,7 @@ fluid_zone_gen_import_sfont(fluid_gen_t *gen, fluid_zone_range_t *range, SFZone
|
|||
* @param src, pointer on destination modulator source.
|
||||
* @param flags, pointer on destination modulator flags.
|
||||
* @param sf_source, soundfont modulator source.
|
||||
* @return return TRUE if success, FALSE if source type is unknow.
|
||||
* @return return TRUE if success, FALSE if source type is unknown.
|
||||
*/
|
||||
static int
|
||||
fluid_zone_mod_source_import_sfont(unsigned char *src, unsigned char *flags, unsigned short sf_source)
|
||||
|
@ -1602,24 +1636,27 @@ fluid_zone_mod_import_sfont(char *zone_name, fluid_mod_t **mod, SFZone *sfzone)
|
|||
* fluid_preset_zone_import_sfont
|
||||
*/
|
||||
int
|
||||
fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
|
||||
fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defsfont, SFData *sfdata)
|
||||
{
|
||||
/* import the generators */
|
||||
fluid_zone_gen_import_sfont(zone->gen, &zone->range, sfzone);
|
||||
|
||||
if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
|
||||
if(zone->gen[GEN_INSTRUMENT].flags == GEN_SET)
|
||||
{
|
||||
SFInst *sfinst = sfzone->instsamp->data;
|
||||
int inst_idx = (int) zone->gen[GEN_INSTRUMENT].val;
|
||||
|
||||
zone->inst = find_inst_by_idx(defsfont, sfinst->idx);
|
||||
zone->inst = find_inst_by_idx(defsfont, inst_idx);
|
||||
|
||||
if(zone->inst == NULL)
|
||||
{
|
||||
zone->inst = fluid_inst_import_sfont(sfinst, defsfont);
|
||||
zone->inst = fluid_inst_import_sfont(inst_idx, defsfont, sfdata);
|
||||
}
|
||||
|
||||
if(zone->inst == NULL)
|
||||
{
|
||||
|
||||
FLUID_LOG(FLUID_ERR, "Preset zone %s: Invalid instrument reference",
|
||||
zone->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
|
@ -1627,6 +1664,9 @@ fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_
|
|||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* We don't need this generator anymore */
|
||||
zone->gen[GEN_INSTRUMENT].flags = GEN_UNUSED;
|
||||
}
|
||||
|
||||
/* Import the modulators (only SF2.1 and higher) */
|
||||
|
@ -1707,15 +1747,30 @@ fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone)
|
|||
* fluid_inst_import_sfont
|
||||
*/
|
||||
fluid_inst_t *
|
||||
fluid_inst_import_sfont(SFInst *sfinst, fluid_defsfont_t *defsfont)
|
||||
fluid_inst_import_sfont(int inst_idx, fluid_defsfont_t *defsfont, SFData *sfdata)
|
||||
{
|
||||
fluid_list_t *p;
|
||||
fluid_list_t *inst_list;
|
||||
fluid_inst_t *inst;
|
||||
SFZone *sfzone;
|
||||
SFInst *sfinst;
|
||||
fluid_inst_zone_t *inst_zone;
|
||||
char zone_name[256];
|
||||
int count;
|
||||
|
||||
for (inst_list = sfdata->inst; inst_list; inst_list = fluid_list_next(inst_list))
|
||||
{
|
||||
sfinst = fluid_list_get(inst_list);
|
||||
if (sfinst->idx == inst_idx)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (inst_list == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inst = (fluid_inst_t *) new_fluid_inst();
|
||||
|
||||
if(inst == NULL)
|
||||
|
@ -1753,7 +1808,7 @@ fluid_inst_import_sfont(SFInst *sfinst, fluid_defsfont_t *defsfont)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if(fluid_inst_zone_import_sfont(inst_zone, sfzone, defsfont) != FLUID_OK)
|
||||
if(fluid_inst_zone_import_sfont(inst_zone, sfzone, defsfont, sfdata) != FLUID_OK)
|
||||
{
|
||||
delete_fluid_inst_zone(inst_zone);
|
||||
return NULL;
|
||||
|
@ -1885,7 +1940,8 @@ fluid_inst_zone_next(fluid_inst_zone_t *zone)
|
|||
* fluid_inst_zone_import_sfont
|
||||
*/
|
||||
int
|
||||
fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
|
||||
fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont,
|
||||
SFData *sfdata)
|
||||
{
|
||||
/* import the generators */
|
||||
fluid_zone_gen_import_sfont(inst_zone->gen, &inst_zone->range, sfzone);
|
||||
|
@ -1895,10 +1951,32 @@ fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid
|
|||
/* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */
|
||||
/* } */
|
||||
|
||||
/* fixup sample pointer */
|
||||
if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
|
||||
if (inst_zone->gen[GEN_SAMPLEID].flags == GEN_SET)
|
||||
{
|
||||
inst_zone->sample = ((SFSample *)(sfzone->instsamp->data))->fluid_sample;
|
||||
fluid_list_t *list;
|
||||
SFSample *sfsample;
|
||||
int sample_idx = (int) inst_zone->gen[GEN_SAMPLEID].val;
|
||||
|
||||
/* find the SFSample by index */
|
||||
for(list = sfdata->sample; list; list = fluid_list_next(list))
|
||||
{
|
||||
sfsample = fluid_list_get(list);
|
||||
if (sfsample->idx == sample_idx)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (list == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Instrument zone '%s': Invalid sample reference",
|
||||
inst_zone->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
inst_zone->sample = sfsample->fluid_sample;
|
||||
|
||||
/* we don't need this generator anymore, mark it as unused */
|
||||
inst_zone->gen[GEN_SAMPLEID].flags = GEN_UNUSED;
|
||||
}
|
||||
|
||||
/* Import the modulators (only SF2.1 and higher) */
|
||||
|
@ -2003,15 +2081,74 @@ static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int
|
|||
{
|
||||
FLUID_LOG(FLUID_DBG, "Selected preset '%s' on channel %d", fluid_preset_get_name(preset), chan);
|
||||
defsfont = fluid_sfont_get_data(preset->sfont);
|
||||
load_preset_samples(defsfont, preset);
|
||||
return load_preset_samples(defsfont, preset);
|
||||
}
|
||||
else if(reason == FLUID_PRESET_UNSELECTED)
|
||||
|
||||
if(reason == FLUID_PRESET_UNSELECTED)
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Deselected preset '%s' from channel %d", fluid_preset_get_name(preset), chan);
|
||||
defsfont = fluid_sfont_get_data(preset->sfont);
|
||||
unload_preset_samples(defsfont, preset);
|
||||
return unload_preset_samples(defsfont, preset);
|
||||
}
|
||||
|
||||
if(reason == FLUID_PRESET_PIN)
|
||||
{
|
||||
defsfont = fluid_sfont_get_data(preset->sfont);
|
||||
return pin_preset_samples(defsfont, preset);
|
||||
}
|
||||
|
||||
if(reason == FLUID_PRESET_UNPIN)
|
||||
{
|
||||
defsfont = fluid_sfont_get_data(preset->sfont);
|
||||
return unpin_preset_samples(defsfont, preset);
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
static int pin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)
|
||||
{
|
||||
fluid_defpreset_t *defpreset;
|
||||
|
||||
defpreset = fluid_preset_get_data(preset);
|
||||
if (defpreset->pinned)
|
||||
{
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Pinning preset '%s'", fluid_preset_get_name(preset));
|
||||
|
||||
if(load_preset_samples(defsfont, preset) == FLUID_FAILED)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
defpreset->pinned = TRUE;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
static int unpin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)
|
||||
{
|
||||
fluid_defpreset_t *defpreset;
|
||||
|
||||
defpreset = fluid_preset_get_data(preset);
|
||||
if (!defpreset->pinned)
|
||||
{
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Unpinning preset '%s'", fluid_preset_get_name(preset));
|
||||
|
||||
if(unload_preset_samples(defsfont, preset) == FLUID_FAILED)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
defpreset->pinned = FALSE;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,12 +148,13 @@ struct _fluid_defpreset_t
|
|||
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 */
|
||||
int pinned; /* preset samples pinned to sample cache? */
|
||||
};
|
||||
|
||||
fluid_defpreset_t *new_fluid_defpreset(void);
|
||||
void delete_fluid_defpreset(fluid_defpreset_t *defpreset);
|
||||
fluid_defpreset_t *fluid_defpreset_next(fluid_defpreset_t *defpreset);
|
||||
int fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset, SFPreset *sfpreset, fluid_defsfont_t *defsfont);
|
||||
int fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset, SFPreset *sfpreset, fluid_defsfont_t *defsfont, SFData *sfdata);
|
||||
int fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone);
|
||||
int fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone);
|
||||
fluid_preset_zone_t *fluid_defpreset_get_zone(fluid_defpreset_t *defpreset);
|
||||
|
@ -181,7 +182,7 @@ fluid_preset_zone_t *new_fluid_preset_zone(char *name);
|
|||
void delete_fluid_list_mod(fluid_mod_t *mod);
|
||||
void delete_fluid_preset_zone(fluid_preset_zone_t *zone);
|
||||
fluid_preset_zone_t *fluid_preset_zone_next(fluid_preset_zone_t *zone);
|
||||
int fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defssfont);
|
||||
int fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defssfont, SFData *sfdata);
|
||||
fluid_inst_t *fluid_preset_zone_get_inst(fluid_preset_zone_t *zone);
|
||||
|
||||
/*
|
||||
|
@ -196,7 +197,7 @@ struct _fluid_inst_t
|
|||
};
|
||||
|
||||
fluid_inst_t *new_fluid_inst(void);
|
||||
fluid_inst_t *fluid_inst_import_sfont(SFInst *sfinst, fluid_defsfont_t *defsfont);
|
||||
fluid_inst_t *fluid_inst_import_sfont(int inst_idx, fluid_defsfont_t *defsfont, SFData *sfdata);
|
||||
void delete_fluid_inst(fluid_inst_t *inst);
|
||||
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);
|
||||
|
@ -220,7 +221,7 @@ struct _fluid_inst_zone_t
|
|||
fluid_inst_zone_t *new_fluid_inst_zone(char *name);
|
||||
void 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 *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont);
|
||||
int fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont, SFData *sfdata);
|
||||
fluid_sample_t *fluid_inst_zone_get_sample(fluid_inst_zone_t *zone);
|
||||
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ fluid_event_clear(fluid_event_t *evt)
|
|||
evt->dest = -1;
|
||||
evt->src = -1;
|
||||
evt->type = -1;
|
||||
evt->id = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,6 +96,12 @@ fluid_event_set_time(fluid_event_t *evt, unsigned int time)
|
|||
evt->time = time;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_event_set_id(fluid_event_t *evt, fluid_note_id_t id)
|
||||
{
|
||||
evt->id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set source of a sequencer event. \c src must be a unique sequencer ID or -1 if not set.
|
||||
* @param evt Sequencer event structure
|
||||
|
@ -161,11 +168,18 @@ fluid_event_noteoff(fluid_event_t *evt, int channel, short key)
|
|||
|
||||
/**
|
||||
* Set a sequencer event to be a note duration event.
|
||||
*
|
||||
* Before fluidsynth 2.2.0, this event type was naively implemented when used in conjunction with fluid_sequencer_register_fluidsynth(),
|
||||
* because it simply enqueued a fluid_event_noteon() and fluid_event_noteoff().
|
||||
* A handling for overlapping notes was not implemented. Starting with 2.2.0, this changes: If a fluid_event_note() is already playing,
|
||||
* while another fluid_event_note() arrives on the same @c channel and @c key, the earlier event will be canceled.
|
||||
* @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 in the time scale used by the sequencer (by default milliseconds)
|
||||
*
|
||||
* @note The application should decide whether to use only Notes with duration, or separate NoteOn and NoteOff events.
|
||||
*/
|
||||
void
|
||||
fluid_event_note(fluid_event_t *evt, int channel, short key, short vel, unsigned int duration)
|
||||
|
@ -222,7 +236,7 @@ fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num)
|
|||
* @param val MIDI program number (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_program_change(fluid_event_t *evt, int channel, short val)
|
||||
fluid_event_program_change(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_PROGRAMCHANGE;
|
||||
evt->channel = channel;
|
||||
|
@ -248,18 +262,6 @@ fluid_event_program_select(fluid_event_t *evt, int channel,
|
|||
evt->control = bank_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be an any control change event (for internal use).
|
||||
* @param evt Sequencer event structure
|
||||
* @param channel MIDI channel number
|
||||
*/
|
||||
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
|
||||
|
@ -292,7 +294,7 @@ fluid_event_pitch_bend(fluid_event_t *evt, int channel, int pitch)
|
|||
* @param value MIDI pitch wheel sensitivity value in semitones
|
||||
*/
|
||||
void
|
||||
fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, short value)
|
||||
fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, int value)
|
||||
{
|
||||
evt->type = FLUID_SEQ_PITCHWHEELSENS;
|
||||
evt->channel = channel;
|
||||
|
@ -306,7 +308,7 @@ fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, short value)
|
|||
* @param val MIDI modulation value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_modulation(fluid_event_t *evt, int channel, short val)
|
||||
fluid_event_modulation(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_MODULATION;
|
||||
evt->channel = channel;
|
||||
|
@ -331,7 +333,7 @@ fluid_event_modulation(fluid_event_t *evt, int channel, short val)
|
|||
* @param val MIDI sustain value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_sustain(fluid_event_t *evt, int channel, short val)
|
||||
fluid_event_sustain(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_SUSTAIN;
|
||||
evt->channel = channel;
|
||||
|
@ -357,7 +359,7 @@ fluid_event_sustain(fluid_event_t *evt, int channel, short val)
|
|||
* @param val MIDI control value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_control_change(fluid_event_t *evt, int channel, short control, short val)
|
||||
fluid_event_control_change(fluid_event_t *evt, int channel, short control, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_CONTROLCHANGE;
|
||||
evt->channel = channel;
|
||||
|
@ -372,7 +374,7 @@ fluid_event_control_change(fluid_event_t *evt, int channel, short control, short
|
|||
* @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)
|
||||
fluid_event_pan(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_PAN;
|
||||
evt->channel = channel;
|
||||
|
@ -397,7 +399,7 @@ fluid_event_pan(fluid_event_t *evt, int channel, short val)
|
|||
* @param val Volume value (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_volume(fluid_event_t *evt, int channel, short val)
|
||||
fluid_event_volume(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_VOLUME;
|
||||
evt->channel = channel;
|
||||
|
@ -422,7 +424,7 @@ fluid_event_volume(fluid_event_t *evt, int channel, short val)
|
|||
* @param val Reverb amount (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_reverb_send(fluid_event_t *evt, int channel, short val)
|
||||
fluid_event_reverb_send(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_REVERBSEND;
|
||||
evt->channel = channel;
|
||||
|
@ -447,7 +449,7 @@ fluid_event_reverb_send(fluid_event_t *evt, int channel, short val)
|
|||
* @param val Chorus amount (0-127)
|
||||
*/
|
||||
void
|
||||
fluid_event_chorus_send(fluid_event_t *evt, int channel, short val)
|
||||
fluid_event_chorus_send(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_CHORUSSEND;
|
||||
evt->channel = channel;
|
||||
|
@ -477,6 +479,20 @@ fluid_event_unregistering(fluid_event_t *evt)
|
|||
evt->type = FLUID_SEQ_UNREGISTERING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a scale change event.
|
||||
* Useful for scheduling tempo changes.
|
||||
* @param evt Sequencer event structure
|
||||
* @param new_scale The new time scale to apply to the sequencer, see fluid_sequencer_set_time_scale()
|
||||
* @since 2.2.0
|
||||
*/
|
||||
void
|
||||
fluid_event_scale(fluid_event_t *evt, double new_scale)
|
||||
{
|
||||
evt->type = FLUID_SEQ_SCALE;
|
||||
evt->scale = new_scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sequencer event to be a channel-wide aftertouch event.
|
||||
* @param evt Sequencer event structure
|
||||
|
@ -485,7 +501,7 @@ fluid_event_unregistering(fluid_event_t *evt)
|
|||
* @since 1.1.0
|
||||
*/
|
||||
void
|
||||
fluid_event_channel_pressure(fluid_event_t *evt, int channel, short val)
|
||||
fluid_event_channel_pressure(fluid_event_t *evt, int channel, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_CHANNELPRESSURE;
|
||||
evt->channel = channel;
|
||||
|
@ -512,7 +528,7 @@ fluid_event_channel_pressure(fluid_event_t *evt, int channel, short val)
|
|||
* @since 2.0.0
|
||||
*/
|
||||
void
|
||||
fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, short val)
|
||||
fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, int val)
|
||||
{
|
||||
evt->type = FLUID_SEQ_KEYPRESSURE;
|
||||
evt->channel = channel;
|
||||
|
@ -579,6 +595,17 @@ unsigned int fluid_event_get_time(fluid_event_t *evt)
|
|||
return evt->time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Get the time field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return Time value
|
||||
*/
|
||||
fluid_note_id_t fluid_event_get_id(fluid_event_t *evt)
|
||||
{
|
||||
return evt->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source sequencer client from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
|
@ -651,7 +678,7 @@ short fluid_event_get_control(fluid_event_t *evt)
|
|||
* #FLUID_SEQ_CONTROLCHANGE, #FLUID_SEQ_PAN, #FLUID_SEQ_VOLUME,
|
||||
* #FLUID_SEQ_REVERBSEND, #FLUID_SEQ_CHORUSSEND.
|
||||
*/
|
||||
short fluid_event_get_value(fluid_event_t *evt)
|
||||
int fluid_event_get_value(fluid_event_t *evt)
|
||||
{
|
||||
return evt->value;
|
||||
}
|
||||
|
@ -713,7 +740,7 @@ int fluid_event_get_pitch(fluid_event_t *evt)
|
|||
* Used by the #FLUID_SEQ_PROGRAMCHANGE and #FLUID_SEQ_PROGRAMSELECT
|
||||
* event types.
|
||||
*/
|
||||
short
|
||||
int
|
||||
fluid_event_get_program(fluid_event_t *evt)
|
||||
{
|
||||
return evt->value;
|
||||
|
@ -732,182 +759,14 @@ fluid_event_get_sfont_id(fluid_event_t *evt)
|
|||
return evt->duration;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************/
|
||||
/* heap management */
|
||||
/********************/
|
||||
|
||||
fluid_evt_heap_t *
|
||||
_fluid_evt_heap_init(int nbEvents)
|
||||
/**
|
||||
* Gets time scale field from a sequencer event structure.
|
||||
* @param evt Sequencer event structure
|
||||
* @return SoundFont identifier value.
|
||||
*
|
||||
* Used by the #FLUID_SEQ_SCALE event type.
|
||||
*/
|
||||
double fluid_event_get_scale(fluid_event_t *evt)
|
||||
{
|
||||
#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
|
||||
return evt->scale;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,12 @@
|
|||
#define _FLUID_EVENT_PRIV_H
|
||||
|
||||
#include "fluidsynth.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int fluid_note_id_t;
|
||||
|
||||
/* Private data for event */
|
||||
/* ?? should be optimized in size, using unions */
|
||||
|
@ -37,51 +42,24 @@ struct _fluid_event_t
|
|||
short key;
|
||||
short vel;
|
||||
short control;
|
||||
short value;
|
||||
short id; //?? unused ?
|
||||
int value;
|
||||
fluid_note_id_t id;
|
||||
int pitch;
|
||||
unsigned int duration;
|
||||
double scale;
|
||||
void *data;
|
||||
};
|
||||
|
||||
unsigned int fluid_event_get_time(fluid_event_t *evt);
|
||||
void fluid_event_set_time(fluid_event_t *evt, unsigned int time);
|
||||
|
||||
fluid_note_id_t fluid_event_get_id(fluid_event_t *evt);
|
||||
void fluid_event_set_id(fluid_event_t *evt, fluid_note_id_t id);
|
||||
|
||||
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;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#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 */
|
||||
|
|
|
@ -23,73 +23,76 @@
|
|||
#include "fluid_chan.h"
|
||||
|
||||
|
||||
#define _GEN(_name) GEN_ ## _name, #_name
|
||||
|
||||
|
||||
/* See SFSpec21 $8.1.3 */
|
||||
static const fluid_gen_info_t fluid_gen_info[] =
|
||||
{
|
||||
/* number/name init nrpn-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 },
|
||||
{ GEN_CUSTOM_BALANCE, 1, 0, -960.0f, 960.0f, 0.0f },
|
||||
{ GEN_CUSTOM_FILTERFC, 1, 2, 0.0f, 22050.0f, 0.0f },
|
||||
{ GEN_CUSTOM_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f }
|
||||
{ _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 },
|
||||
{ _GEN(CUSTOM_BALANCE), 1, 0, -960.0f, 960.0f, 0.0f },
|
||||
{ _GEN(CUSTOM_FILTERFC), 1, 2, 0.0f, 22050.0f, 0.0f },
|
||||
{ _GEN(CUSTOM_FILTERQ), 1, 1, 0.0f, 960.0f, 0.0f }
|
||||
};
|
||||
|
||||
/* fluid_gen_init
|
||||
|
@ -122,3 +125,9 @@ fluid_real_t fluid_gen_scale_nrpn(int gen, int data)
|
|||
fluid_clip(data, -8192, 8192);
|
||||
return (fluid_real_t)(data * fluid_gen_info[gen].nrpn_scale);
|
||||
}
|
||||
|
||||
|
||||
const char *fluid_gen_name(int gen)
|
||||
{
|
||||
return fluid_gen_info[gen].name;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
typedef struct _fluid_gen_info_t
|
||||
{
|
||||
char num; /* Generator number */
|
||||
char const *name;
|
||||
char init; /* Does the generator need to be initialized (not used) */
|
||||
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
|
||||
float min; /* The minimum value */
|
||||
|
@ -60,6 +61,7 @@ enum fluid_gen_flags
|
|||
fluid_real_t fluid_gen_scale(int gen, float value);
|
||||
fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn);
|
||||
void fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel);
|
||||
const char *fluid_gen_name(int gen);
|
||||
|
||||
|
||||
#endif /* _FLUID_GEN_H */
|
||||
|
|
|
@ -129,7 +129,7 @@ spaced_primes_closest(unsigned int num)
|
|||
* the case that the entry is at the head of a chain, this pointer
|
||||
* will be an item in the nodes[] array. In the case that the entry
|
||||
* is not at the head of a chain, this pointer will be the ->next
|
||||
* pointer on the node that preceeds it.
|
||||
* pointer on the node that precedes it.
|
||||
*
|
||||
* In the case that no matching entry exists in the table, a pointer
|
||||
* to a %NULL pointer will be returned. To insert a item, this %NULL
|
||||
|
|
|
@ -319,3 +319,19 @@ fluid_list_str_compare_func(void *a, void *b)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fluid_list_idx(fluid_list_t *list, void *data)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while(list)
|
||||
{
|
||||
if (list->data == data)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ 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_idx(fluid_list_t *list, void *data);
|
||||
int fluid_list_size(fluid_list_t *list);
|
||||
|
||||
#define fluid_list_next(slist) ((slist) ? (((fluid_list_t *)(slist))->next) : NULL)
|
||||
|
|
|
@ -48,18 +48,13 @@ static fluid_midi_event_t *fluid_track_next_event(fluid_track_t *track);
|
|||
static int fluid_track_get_duration(fluid_track_t *track);
|
||||
static int fluid_track_reset(fluid_track_t *track);
|
||||
|
||||
static void fluid_track_send_events(fluid_track_t *track,
|
||||
fluid_synth_t *synth,
|
||||
fluid_player_t *player,
|
||||
unsigned int ticks);
|
||||
|
||||
|
||||
static int fluid_player_add_track(fluid_player_t *player, fluid_track_t *track);
|
||||
static int fluid_player_callback(void *data, unsigned int msec);
|
||||
static int fluid_player_reset(fluid_player_t *player);
|
||||
static int fluid_player_load(fluid_player_t *player, fluid_playlist_item *item);
|
||||
static void fluid_player_advancefile(fluid_player_t *player);
|
||||
static void fluid_player_playlist_load(fluid_player_t *player, unsigned int msec);
|
||||
static void fluid_player_update_tempo(fluid_player_t *player);
|
||||
|
||||
static fluid_midi_file *new_fluid_midi_file(const char *buffer, size_t length);
|
||||
static void delete_fluid_midi_file(fluid_midi_file *mf);
|
||||
|
@ -180,7 +175,7 @@ fluid_file_read_full(fluid_file fp, size_t *length)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "File load: Allocating %lu bytes", buflen);
|
||||
FLUID_LOG(FLUID_DBG, "File load: Allocating %lu bytes", (unsigned long)buflen);
|
||||
buffer = FLUID_MALLOC(buflen);
|
||||
|
||||
if(buffer == NULL)
|
||||
|
@ -193,8 +188,8 @@ fluid_file_read_full(fluid_file fp, size_t *length)
|
|||
|
||||
if(n != buflen)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Only read %lu bytes; expected %lu", n,
|
||||
buflen);
|
||||
FLUID_LOG(FLUID_ERR, "Only read %lu bytes; expected %lu", (unsigned long)n,
|
||||
(unsigned long)buflen);
|
||||
FLUID_FREE(buffer);
|
||||
return NULL;
|
||||
};
|
||||
|
@ -406,8 +401,7 @@ fluid_isasciistring(char *s)
|
|||
/* From ctype.h */
|
||||
#define fluid_isascii(c) (((c) & ~0x7f) == 0)
|
||||
|
||||
int i;
|
||||
int len = (int) FLUID_STRLEN(s);
|
||||
size_t i, len = FLUID_STRLEN(s);
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
|
@ -1458,7 +1452,7 @@ delete_fluid_track(fluid_track_t *track)
|
|||
int
|
||||
fluid_track_set_name(fluid_track_t *track, char *name)
|
||||
{
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
if(track->name != NULL)
|
||||
{
|
||||
|
@ -1553,18 +1547,20 @@ fluid_track_reset(fluid_track_t *track)
|
|||
/*
|
||||
* fluid_track_send_events
|
||||
*/
|
||||
void
|
||||
static void
|
||||
fluid_track_send_events(fluid_track_t *track,
|
||||
fluid_synth_t *synth,
|
||||
fluid_player_t *player,
|
||||
unsigned int ticks)
|
||||
unsigned int ticks,
|
||||
int seek_ticks
|
||||
)
|
||||
{
|
||||
fluid_midi_event_t *event;
|
||||
int seeking = player->seek_ticks >= 0;
|
||||
int seeking = seek_ticks >= 0;
|
||||
|
||||
if(seeking)
|
||||
{
|
||||
ticks = player->seek_ticks; /* update target ticks */
|
||||
ticks = seek_ticks; /* update target ticks */
|
||||
|
||||
if(track->ticks > ticks)
|
||||
{
|
||||
|
@ -1598,8 +1594,9 @@ fluid_track_send_events(fluid_track_t *track,
|
|||
|
||||
if(!player || event->type == MIDI_EOT)
|
||||
{
|
||||
/* don't send EOT events to the callback */
|
||||
}
|
||||
else if(seeking && (event->type == NOTE_ON || event->type == NOTE_OFF))
|
||||
else if(seeking && track->ticks != ticks && (event->type == NOTE_ON || event->type == NOTE_OFF))
|
||||
{
|
||||
/* skip on/off messages */
|
||||
}
|
||||
|
@ -1611,9 +1608,11 @@ fluid_track_send_events(fluid_track_t *track,
|
|||
}
|
||||
}
|
||||
|
||||
if(event->type == MIDI_SET_TEMPO)
|
||||
if(event->type == MIDI_SET_TEMPO && player != NULL)
|
||||
{
|
||||
fluid_player_set_midi_tempo(player, event->param1);
|
||||
/* memorize the tempo change value coming from the MIDI file */
|
||||
fluid_atomic_int_set(&player->miditempo, event->param1);
|
||||
fluid_player_update_tempo(player);
|
||||
}
|
||||
|
||||
fluid_track_next_event(track);
|
||||
|
@ -1652,7 +1651,7 @@ new_fluid_player(fluid_synth_t *synth)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
player->status = FLUID_PLAYER_READY;
|
||||
fluid_atomic_int_set(&player->status, FLUID_PLAYER_READY);
|
||||
player->loop = 1;
|
||||
player->ntracks = 0;
|
||||
|
||||
|
@ -1667,13 +1666,22 @@ new_fluid_player(fluid_synth_t *synth)
|
|||
player->playlist = NULL;
|
||||
player->currentfile = NULL;
|
||||
player->division = 0;
|
||||
player->send_program_change = 1;
|
||||
|
||||
/* internal tempo (from MIDI file) in micro seconds per quarter note */
|
||||
player->sync_mode = 1; /* the player follows internal tempo change */
|
||||
player->miditempo = 500000;
|
||||
/* external tempo in micro seconds per quarter note */
|
||||
player->exttempo = 500000;
|
||||
/* tempo multiplier */
|
||||
player->multempo = 1.0F;
|
||||
|
||||
player->deltatime = 4.0;
|
||||
player->cur_msec = 0;
|
||||
player->cur_ticks = 0;
|
||||
player->seek_ticks = -1;
|
||||
player->last_callback_ticks = -1;
|
||||
fluid_atomic_int_set(&player->seek_ticks, -1);
|
||||
fluid_player_set_playback_callback(player, fluid_synth_handle_midi_event, synth);
|
||||
fluid_player_set_tick_callback(player, NULL, NULL);
|
||||
player->use_system_timer = fluid_settings_str_equal(synth->settings,
|
||||
"player.timing-source", "system");
|
||||
if(player->use_system_timer)
|
||||
|
@ -1723,6 +1731,9 @@ delete_fluid_player(fluid_player_t *player)
|
|||
|
||||
fluid_return_if_fail(player != NULL);
|
||||
|
||||
fluid_settings_callback_int(player->synth->settings, "player.reset-synth",
|
||||
NULL, NULL);
|
||||
|
||||
fluid_player_stop(player);
|
||||
fluid_player_reset(player);
|
||||
|
||||
|
@ -1779,7 +1790,6 @@ fluid_player_reset(fluid_player_t *player)
|
|||
/* player->loop = 1; */
|
||||
player->ntracks = 0;
|
||||
player->division = 0;
|
||||
player->send_program_change = 1;
|
||||
player->miditempo = 500000;
|
||||
player->deltatime = 4.0;
|
||||
return 0;
|
||||
|
@ -1803,16 +1813,18 @@ fluid_player_add_track(fluid_player_t *player, fluid_track_t *track)
|
|||
}
|
||||
|
||||
/**
|
||||
* Change the MIDI callback function. This is usually set to
|
||||
* fluid_synth_handle_midi_event, but can optionally be changed
|
||||
* to a user-defined function instead, for intercepting all MIDI
|
||||
* messages sent to the synth. You can also use a midi router as
|
||||
* the callback function to modify the MIDI messages before sending
|
||||
* them to the synth.
|
||||
* Change the MIDI callback function.
|
||||
*
|
||||
* @param player MIDI player instance
|
||||
* @param handler Pointer to callback function
|
||||
* @param handler_data Parameter sent to the callback function
|
||||
* @returns FLUID_OK
|
||||
*
|
||||
* This is usually set to fluid_synth_handle_midi_event(), but can optionally
|
||||
* be changed to a user-defined function instead, for intercepting all MIDI
|
||||
* messages sent to the synth. You can also use a midi router as the callback
|
||||
* function to modify the MIDI messages before sending them to the synth.
|
||||
*
|
||||
* @since 1.1.4
|
||||
*/
|
||||
int
|
||||
|
@ -1824,6 +1836,28 @@ fluid_player_set_playback_callback(fluid_player_t *player,
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener function for every MIDI tick change.
|
||||
*
|
||||
* @param player MIDI player instance
|
||||
* @param handler Pointer to callback function
|
||||
* @param handler_data Opaque parameter to be sent to the callback function
|
||||
* @returns #FLUID_OK
|
||||
*
|
||||
* This callback is not set by default, but can optionally
|
||||
* be changed to a user-defined function for intercepting all MIDI
|
||||
* tick changes and react to them with precision.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*/
|
||||
int
|
||||
fluid_player_set_tick_callback(fluid_player_t *player, handle_midi_tick_func_t handler, void *handler_data)
|
||||
{
|
||||
player->tick_callback = handler;
|
||||
player->tick_userdata = handler_data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a MIDI file to a player queue.
|
||||
* @param player MIDI player instance
|
||||
|
@ -1944,7 +1978,7 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
|
|||
}
|
||||
|
||||
player->division = fluid_midi_file_get_division(midifile);
|
||||
fluid_player_set_midi_tempo(player, player->miditempo); // Update deltatime
|
||||
fluid_player_update_tempo(player); // Update deltatime
|
||||
/*FLUID_LOG(FLUID_DBG, "quarter note division=%d\n", player->division); */
|
||||
|
||||
if(fluid_midi_file_load_tracks(midifile, player) != FLUID_OK)
|
||||
|
@ -2010,7 +2044,7 @@ fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
|
|||
if(player->currentfile == NULL)
|
||||
{
|
||||
/* Failed to find next song, probably since we're finished */
|
||||
player->status = FLUID_PLAYER_DONE;
|
||||
fluid_atomic_int_set(&player->status, FLUID_PLAYER_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2026,11 +2060,6 @@ fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
|
|||
player->start_ticks = 0;
|
||||
player->cur_ticks = 0;
|
||||
|
||||
if(player->reset_synth_between_songs)
|
||||
{
|
||||
fluid_synth_system_reset(player->synth);
|
||||
}
|
||||
|
||||
for(i = 0; i < player->ntracks; i++)
|
||||
{
|
||||
if(player->track[i] != NULL)
|
||||
|
@ -2056,13 +2085,17 @@ fluid_player_callback(void *data, unsigned int msec)
|
|||
|
||||
loadnextfile = player->currentfile == NULL ? 1 : 0;
|
||||
|
||||
if(player->status == FLUID_PLAYER_DONE)
|
||||
if(fluid_player_get_status(player) != FLUID_PLAYER_PLAYING)
|
||||
{
|
||||
fluid_synth_all_notes_off(synth, -1);
|
||||
fluid_atomic_int_compare_and_exchange(&player->status, FLUID_PLAYER_STOPPING, FLUID_PLAYER_DONE);
|
||||
return 1;
|
||||
}
|
||||
do
|
||||
{
|
||||
float deltatime;
|
||||
int seek_ticks;
|
||||
|
||||
if(loadnextfile)
|
||||
{
|
||||
loadnextfile = 0;
|
||||
|
@ -2075,11 +2108,13 @@ fluid_player_callback(void *data, unsigned int msec)
|
|||
}
|
||||
|
||||
player->cur_msec = msec;
|
||||
deltatime = fluid_atomic_float_get(&player->deltatime);
|
||||
player->cur_ticks = (player->start_ticks
|
||||
+ (int)((double)(player->cur_msec - player->start_msec)
|
||||
/ player->deltatime + 0.5)); /* 0.5 to average overall error when casting */
|
||||
/ deltatime + 0.5)); /* 0.5 to average overall error when casting */
|
||||
|
||||
if(player->seek_ticks >= 0)
|
||||
seek_ticks = fluid_atomic_int_get(&player->seek_ticks);
|
||||
if(seek_ticks >= 0)
|
||||
{
|
||||
fluid_synth_all_sounds_off(synth, -1); /* avoid hanging notes */
|
||||
}
|
||||
|
@ -2089,29 +2124,40 @@ fluid_player_callback(void *data, unsigned int msec)
|
|||
if(!fluid_track_eot(player->track[i]))
|
||||
{
|
||||
status = FLUID_PLAYER_PLAYING;
|
||||
fluid_track_send_events(player->track[i], synth, player, player->cur_ticks);
|
||||
fluid_track_send_events(player->track[i], synth, player, player->cur_ticks, seek_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
if(player->seek_ticks >= 0)
|
||||
if(seek_ticks >= 0)
|
||||
{
|
||||
player->start_ticks = player->seek_ticks; /* tick position of last tempo value (which is now) */
|
||||
player->cur_ticks = player->seek_ticks;
|
||||
player->start_ticks = seek_ticks; /* tick position of last tempo value (which is now) */
|
||||
player->cur_ticks = seek_ticks;
|
||||
player->begin_msec = msec; /* only used to calculate the duration of playing */
|
||||
player->start_msec = msec; /* should be the (synth)-time of the last tempo change */
|
||||
player->seek_ticks = -1; /* clear seek_ticks */
|
||||
fluid_atomic_int_set(&player->seek_ticks, -1); /* clear seek_ticks */
|
||||
}
|
||||
|
||||
if(status == FLUID_PLAYER_DONE)
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "%s: %d: Duration=%.3f sec", __FILE__,
|
||||
__LINE__, (msec - player->begin_msec) / 1000.0);
|
||||
|
||||
if(player->reset_synth_between_songs)
|
||||
{
|
||||
fluid_synth_system_reset(player->synth);
|
||||
}
|
||||
|
||||
loadnextfile = 1;
|
||||
}
|
||||
|
||||
if (player->tick_callback != NULL && player->last_callback_ticks != player->cur_ticks) {
|
||||
player->tick_callback(player->tick_userdata, player->cur_ticks);
|
||||
player->last_callback_ticks = player->cur_ticks;
|
||||
}
|
||||
}
|
||||
while(loadnextfile);
|
||||
|
||||
player->status = status;
|
||||
fluid_atomic_int_compare_and_exchange(&player->status, FLUID_PLAYER_PLAYING, status);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -2124,7 +2170,7 @@ fluid_player_callback(void *data, unsigned int msec)
|
|||
int
|
||||
fluid_player_play(fluid_player_t *player)
|
||||
{
|
||||
if(player->status == FLUID_PLAYER_PLAYING ||
|
||||
if(fluid_player_get_status(player) == FLUID_PLAYER_PLAYING ||
|
||||
player->playlist == NULL)
|
||||
{
|
||||
return FLUID_OK;
|
||||
|
@ -2135,21 +2181,23 @@ fluid_player_play(fluid_player_t *player)
|
|||
fluid_sample_timer_reset(player->synth, player->sample_timer);
|
||||
}
|
||||
|
||||
player->status = FLUID_PLAYER_PLAYING;
|
||||
fluid_atomic_int_set(&player->status, FLUID_PLAYER_PLAYING);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
/**
|
||||
* Pauses the MIDI playback.
|
||||
*
|
||||
* It will not rewind to the beginning of the file, use fluid_player_seek() for this purpose.
|
||||
* @param player MIDI player instance
|
||||
* @return Always returns #FLUID_OK
|
||||
*
|
||||
* It will not rewind to the beginning of the file, use fluid_player_seek() for this purpose.
|
||||
*/
|
||||
int
|
||||
fluid_player_stop(fluid_player_t *player)
|
||||
{
|
||||
player->status = FLUID_PLAYER_DONE;
|
||||
fluid_atomic_int_compare_and_exchange(&player->status, FLUID_PLAYER_READY, FLUID_PLAYER_STOPPING);
|
||||
fluid_atomic_int_compare_and_exchange(&player->status, FLUID_PLAYER_PLAYING, FLUID_PLAYER_STOPPING);
|
||||
fluid_player_seek(player, fluid_player_get_current_tick(player));
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
@ -2163,40 +2211,66 @@ fluid_player_stop(fluid_player_t *player)
|
|||
int
|
||||
fluid_player_get_status(fluid_player_t *player)
|
||||
{
|
||||
return player->status;
|
||||
return fluid_atomic_int_get(&player->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek in the currently playing file.
|
||||
*
|
||||
* @param player MIDI player instance
|
||||
* @param ticks the position to seek to in the current file
|
||||
* @return #FLUID_FAILED if ticks is negative or after the latest tick of the file,
|
||||
* #FLUID_OK otherwise
|
||||
* @since 2.0.0
|
||||
* @return #FLUID_FAILED if ticks is negative or after the latest tick of the file
|
||||
* [or, since 2.1.3, if another seek operation is currently in progress],
|
||||
* #FLUID_OK otherwise.
|
||||
*
|
||||
* The actual seek is performed during the player_callback.
|
||||
* The actual seek will be performed when the synth calls back the player (i.e. a few
|
||||
* levels above the player's callback set with fluid_player_set_playback_callback()).
|
||||
* If the player's status is #FLUID_PLAYER_PLAYING and a previous seek operation has
|
||||
* not been completed yet, #FLUID_FAILED is returned.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
int fluid_player_seek(fluid_player_t *player, int ticks)
|
||||
{
|
||||
if(ticks < 0 || ticks > fluid_player_get_total_ticks(player))
|
||||
if(ticks < 0 || (fluid_player_get_status(player) != FLUID_PLAYER_READY && ticks > fluid_player_get_total_ticks(player)))
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
player->seek_ticks = ticks;
|
||||
return FLUID_OK;
|
||||
if(fluid_player_get_status(player) == FLUID_PLAYER_PLAYING)
|
||||
{
|
||||
if(fluid_atomic_int_compare_and_exchange(&player->seek_ticks, -1, ticks))
|
||||
{
|
||||
// new seek position has been set, as no previous seek was in progress
|
||||
return FLUID_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the player is not currently playing, a new seek position can be set at any time. This allows
|
||||
// the user to do:
|
||||
// fluid_player_stop();
|
||||
// fluid_player_seek(0); // to beginning
|
||||
fluid_atomic_int_set(&player->seek_ticks, ticks);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
// a previous seek is still in progress or hasn't been processed yet
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable looping of a MIDI player
|
||||
*
|
||||
* @param player MIDI player instance
|
||||
* @param loop Times left to loop the playlist. -1 means loop infinitely.
|
||||
* @return Always returns #FLUID_OK
|
||||
* @since 1.1.0
|
||||
*
|
||||
* For example, if you want to loop the playlist twice, set loop to 2
|
||||
* and call this function before you start the player.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int fluid_player_set_loop(fluid_player_t *player, int loop)
|
||||
{
|
||||
|
@ -2205,15 +2279,32 @@ int fluid_player_set_loop(fluid_player_t *player, int loop)
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the tempo of a MIDI player.
|
||||
* update the MIDI player internal deltatime dependant of actual tempo.
|
||||
* @param player MIDI player instance
|
||||
* @param tempo Tempo to set playback speed to (in microseconds per quarter note, as per MIDI file spec)
|
||||
* @return Always returns #FLUID_OK
|
||||
*/
|
||||
int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
|
||||
static void fluid_player_update_tempo(fluid_player_t *player)
|
||||
{
|
||||
player->miditempo = tempo;
|
||||
player->deltatime = (double) tempo / player->division / 1000.0; /* in milliseconds */
|
||||
int tempo; /* tempo in micro seconds by quarter note */
|
||||
float deltatime;
|
||||
|
||||
if(fluid_atomic_int_get(&player->sync_mode))
|
||||
{
|
||||
/* take internal tempo from MIDI file */
|
||||
tempo = fluid_atomic_int_get(&player->miditempo);
|
||||
/* compute deltattime (in ms) from current tempo and apply tempo multiplier */
|
||||
deltatime = (float)tempo / (float)player->division / (float)1000.0;
|
||||
deltatime /= fluid_atomic_float_get(&player->multempo); /* multiply tempo */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* take external tempo */
|
||||
tempo = fluid_atomic_int_get(&player->exttempo);
|
||||
/* compute deltattime (in ms) from current tempo */
|
||||
deltatime = (float)tempo / (float)player->division / (float)1000.0;
|
||||
}
|
||||
|
||||
fluid_atomic_float_set(&player->deltatime, deltatime);
|
||||
|
||||
player->start_msec = player->cur_msec;
|
||||
player->start_ticks = player->cur_ticks;
|
||||
|
||||
|
@ -2221,6 +2312,106 @@ int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
|
|||
"tempo=%d, tick time=%f msec, cur time=%d msec, cur tick=%d",
|
||||
tempo, player->deltatime, player->cur_msec, player->cur_ticks);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tempo of a MIDI player.
|
||||
* The player can be controlled by internal tempo coming from MIDI file tempo
|
||||
* change or controlled by external tempo expressed in BPM or in micro seconds
|
||||
* per quarter note.
|
||||
*
|
||||
* @param player MIDI player instance. Must be a valid pointer.
|
||||
* @param tempo_type Must a be value of #fluid_player_set_tempo_type and indicates the
|
||||
* meaning of tempo value and how the player will be controlled, see below.
|
||||
* @param tempo Tempo value or multiplier.
|
||||
*
|
||||
* #FLUID_PLAYER_TEMPO_INTERNAL, the player will be controlled by internal
|
||||
* MIDI file tempo changes. If there are no tempo change in the MIDI file a default
|
||||
* value of 120 bpm is used. The @c tempo parameter is used as a multiplier factor
|
||||
* that must be in the range (0.001 to 1000).
|
||||
* For example, if the current MIDI file tempo is 120 bpm and the multiplier
|
||||
* value is 0.5 then this tempo will be slowed down to 60 bpm.
|
||||
* At creation, the player is set to be controlled by internal tempo with a
|
||||
* multiplier factor set to 1.0.
|
||||
*
|
||||
* #FLUID_PLAYER_TEMPO_EXTERNAL_BPM, the player will be controlled by the
|
||||
* external tempo value provided by the tempo parameter in bpm
|
||||
* (i.e in quarter notes per minute) which must be in the range (1 to 60000000).
|
||||
*
|
||||
* #FLUID_PLAYER_TEMPO_EXTERNAL_MIDI, similar as FLUID_PLAYER_TEMPO_EXTERNAL_BPM,
|
||||
* but the tempo parameter value is in micro seconds per quarter note which
|
||||
* must be in the range (1 to 60000000).
|
||||
* Using micro seconds per quarter note is convenient when the tempo value is
|
||||
* derived from MIDI clock realtime messages.
|
||||
*
|
||||
* @note When the player is controlled by an external tempo
|
||||
* (#FLUID_PLAYER_TEMPO_EXTERNAL_BPM or #FLUID_PLAYER_TEMPO_EXTERNAL_MIDI) it
|
||||
* continues to memorize the most recent internal tempo change coming from the
|
||||
* MIDI file so that next call to fluid_player_set_tempo() with
|
||||
* #FLUID_PLAYER_TEMPO_INTERNAL will set the player to follow this internal
|
||||
* tempo.
|
||||
*
|
||||
* @return #FLUID_OK if success or #FLUID_FAILED otherwise (incorrect parameters).
|
||||
* @since 2.2.0
|
||||
*/
|
||||
int fluid_player_set_tempo(fluid_player_t *player, int tempo_type, double tempo)
|
||||
{
|
||||
fluid_return_val_if_fail(player != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(tempo_type >= FLUID_PLAYER_TEMPO_INTERNAL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(tempo_type < FLUID_PLAYER_TEMPO_NBR, FLUID_FAILED);
|
||||
|
||||
switch(tempo_type)
|
||||
{
|
||||
/* set the player to be driven by internal tempo coming from MIDI file */
|
||||
case FLUID_PLAYER_TEMPO_INTERNAL:
|
||||
/* check if the multiplier is in correct range */
|
||||
fluid_return_val_if_fail(tempo >= MIN_TEMPO_MULTIPLIER, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(tempo <= MAX_TEMPO_MULTIPLIER, FLUID_FAILED);
|
||||
|
||||
/* set the tempo multiplier */
|
||||
fluid_atomic_float_set(&player->multempo, (float)tempo);
|
||||
fluid_atomic_int_set(&player->sync_mode, 1); /* set internal mode */
|
||||
break;
|
||||
|
||||
/* set the player to be driven by external tempo */
|
||||
case FLUID_PLAYER_TEMPO_EXTERNAL_BPM: /* value in bpm */
|
||||
case FLUID_PLAYER_TEMPO_EXTERNAL_MIDI: /* value in us/quarter note */
|
||||
/* check if tempo is in correct range */
|
||||
fluid_return_val_if_fail(tempo >= MIN_TEMPO_VALUE, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(tempo <= MAX_TEMPO_VALUE, FLUID_FAILED);
|
||||
|
||||
/* set the tempo value */
|
||||
if(tempo_type == FLUID_PLAYER_TEMPO_EXTERNAL_BPM)
|
||||
{
|
||||
tempo = 60000000L / tempo; /* convert tempo in us/quarter note */
|
||||
}
|
||||
fluid_atomic_int_set(&player->exttempo, (int)tempo);
|
||||
fluid_atomic_int_set(&player->sync_mode, 0); /* set external mode */
|
||||
break;
|
||||
|
||||
default: /* shouldn't happen */
|
||||
break;
|
||||
}
|
||||
|
||||
/* update deltatime depending of current tempo */
|
||||
fluid_player_update_tempo(player);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tempo of a MIDI player.
|
||||
* @param player MIDI player instance
|
||||
* @param tempo Tempo to set playback speed to (in microseconds per quarter note, as per MIDI file spec)
|
||||
* @return Always returns #FLUID_OK
|
||||
* @note Tempo change events contained in the MIDI file can override the specified tempo at any time!
|
||||
* @deprecated Use fluid_player_set_tempo() instead.
|
||||
*/
|
||||
int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
|
||||
{
|
||||
player->miditempo = tempo;
|
||||
|
||||
fluid_player_update_tempo(player);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
@ -2229,9 +2420,16 @@ int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo)
|
|||
* @param player MIDI player instance
|
||||
* @param bpm Tempo in beats per minute
|
||||
* @return Always returns #FLUID_OK
|
||||
* @note Tempo change events contained in the MIDI file can override the specified BPM at any time!
|
||||
* @deprecated Use fluid_player_set_tempo() instead.
|
||||
*/
|
||||
int fluid_player_set_bpm(fluid_player_t *player, int bpm)
|
||||
{
|
||||
if(bpm <= 0)
|
||||
{
|
||||
return FLUID_FAILED; /* to avoid a division by 0 */
|
||||
}
|
||||
|
||||
return fluid_player_set_midi_tempo(player, 60000000L / bpm);
|
||||
}
|
||||
|
||||
|
@ -2243,7 +2441,7 @@ int fluid_player_set_bpm(fluid_player_t *player, int bpm)
|
|||
int
|
||||
fluid_player_join(fluid_player_t *player)
|
||||
{
|
||||
while(player->status != FLUID_PLAYER_DONE)
|
||||
while(fluid_player_get_status(player) != FLUID_PLAYER_DONE)
|
||||
{
|
||||
fluid_msleep(10);
|
||||
}
|
||||
|
@ -2289,25 +2487,51 @@ int fluid_player_get_total_ticks(fluid_player_t *player)
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the tempo of a MIDI player in beats per minute.
|
||||
* @param player MIDI player instance
|
||||
* @return MIDI player tempo in BPM
|
||||
* Get the tempo currently used by a MIDI player.
|
||||
* The player can be controlled by internal tempo coming from MIDI file tempo
|
||||
* change or controlled by external tempo see fluid_player_set_tempo().
|
||||
* @param player MIDI player instance. Must be a valid pointer.
|
||||
* @return MIDI player tempo in BPM or FLUID_FAILED if error.
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_player_get_bpm(fluid_player_t *player)
|
||||
{
|
||||
return 60000000L / player->miditempo;
|
||||
|
||||
int midi_tempo = fluid_player_get_midi_tempo(player);
|
||||
|
||||
if(midi_tempo > 0)
|
||||
{
|
||||
midi_tempo = 60000000L / midi_tempo; /* convert in bpm */
|
||||
}
|
||||
|
||||
return midi_tempo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tempo of a MIDI player.
|
||||
* @param player MIDI player instance
|
||||
* @return Tempo of the MIDI player (in microseconds per quarter note, as per MIDI file spec)
|
||||
* Get the tempo currently used by a MIDI player.
|
||||
* The player can be controlled by internal tempo coming from MIDI file tempo
|
||||
* change or controlled by external tempo see fluid_player_set_tempo().
|
||||
|
||||
* @param player MIDI player instance. Must be a valid pointer.
|
||||
* @return Tempo of the MIDI player (in microseconds per quarter note, as per
|
||||
* MIDI file spec) or FLUID_FAILED if error.
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_player_get_midi_tempo(fluid_player_t *player)
|
||||
{
|
||||
return player->miditempo;
|
||||
int midi_tempo; /* value to return */
|
||||
|
||||
fluid_return_val_if_fail(player != NULL, FLUID_FAILED);
|
||||
|
||||
midi_tempo = fluid_atomic_int_get(&player->exttempo);
|
||||
/* look if the player is internally synced */
|
||||
if(fluid_atomic_int_get(&player->sync_mode))
|
||||
{
|
||||
midi_tempo = (int)((float)fluid_atomic_int_get(&player->miditempo)/
|
||||
fluid_atomic_float_get(&player->multempo));
|
||||
}
|
||||
|
||||
return midi_tempo;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
@ -2355,7 +2579,7 @@ delete_fluid_midi_parser(fluid_midi_parser_t *parser)
|
|||
* apps to abuse fluidsynth as midi parser, e.g. feeding it with rawmidi and pull out
|
||||
* the needed midi information using the getter functions of fluid_midi_event_t.
|
||||
* This parser however is incomplete as it e.g. only provides a limited buffer to
|
||||
* store and process SYSEX data (i.e. doesnt allow arbitrary lengths)
|
||||
* store and process SYSEX data (i.e. doesn't allow arbitrary lengths)
|
||||
*/
|
||||
fluid_midi_event_t *
|
||||
fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
|
||||
|
|
|
@ -187,6 +187,7 @@ enum midi_sysex_manuf
|
|||
/* 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 */
|
||||
#define MIDI_SYSEX_GS_ID 0x42 /**< Model ID (GS) serving as sub-ID #1 for GS messages*/
|
||||
|
||||
/**
|
||||
* SYSEX tuning message IDs.
|
||||
|
@ -208,6 +209,7 @@ enum midi_sysex_tuning_msg_id
|
|||
/* General MIDI sub-ID #2 */
|
||||
#define MIDI_SYSEX_GM_ON 0x01 /**< Enable GM mode */
|
||||
#define MIDI_SYSEX_GM_OFF 0x02 /**< Disable GM mode */
|
||||
#define MIDI_SYSEX_GS_DT1 0x12 /**< GS DT1 command */
|
||||
|
||||
enum fluid_driver_status
|
||||
{
|
||||
|
@ -267,12 +269,19 @@ typedef struct
|
|||
size_t buffer_len; /** Number of bytes in buffer; 0 if filename */
|
||||
} fluid_playlist_item;
|
||||
|
||||
/* range of tempo values */
|
||||
#define MIN_TEMPO_VALUE (1.0f)
|
||||
#define MAX_TEMPO_VALUE (60000000.0f)
|
||||
/* range of tempo multiplier values */
|
||||
#define MIN_TEMPO_MULTIPLIER (0.001f)
|
||||
#define MAX_TEMPO_MULTIPLIER (1000.0f)
|
||||
|
||||
/*
|
||||
* fluid_player
|
||||
*/
|
||||
struct _fluid_player_t
|
||||
{
|
||||
int status;
|
||||
fluid_atomic_int_t status;
|
||||
int ntracks;
|
||||
fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
|
||||
fluid_synth_t *synth;
|
||||
|
@ -283,21 +292,35 @@ struct _fluid_player_t
|
|||
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 seek_ticks; /* new position in tempo ticks (midi ticks) for seeking */
|
||||
fluid_atomic_int_t seek_ticks; /* new position in tempo ticks (midi ticks) for seeking */
|
||||
int start_ticks; /* the number of tempo ticks passed at the last tempo change */
|
||||
int cur_ticks; /* the number of tempo ticks passed */
|
||||
int last_callback_ticks; /* the last tick number that was passed to player->tick_callback */
|
||||
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 */
|
||||
/* sync mode: indicates the tempo mode the player is driven by (see fluid_player_set_tempo()):
|
||||
1, the player is driven by internal tempo (miditempo). This is the default.
|
||||
0, the player is driven by external tempo (exttempo)
|
||||
*/
|
||||
int sync_mode;
|
||||
/* miditempo: internal tempo comming from MIDI file tempo change events
|
||||
(in micro seconds per quarter note)
|
||||
*/
|
||||
int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */
|
||||
/* exttempo: external tempo set by fluid_player_set_tempo() (in micro seconds per quarter note) */
|
||||
int exttempo;
|
||||
/* multempo: tempo multiplier set by fluid_player_set_tempo() */
|
||||
float multempo;
|
||||
float deltatime; /* milliseconds per midi tick. depends on current tempo mode (see sync_mode) */
|
||||
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 */
|
||||
handle_midi_tick_func_t tick_callback; /* function fired on each tick change */
|
||||
void *tick_userdata; /* pointer to user-defined data passed to tick_callback function */
|
||||
};
|
||||
|
||||
void fluid_player_settings(fluid_settings_t *settings);
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
|
||||
/**
|
||||
* Clone the modulators destination, sources, flags and amount.
|
||||
*
|
||||
* @param mod the modulator to store the copy to
|
||||
* @param src the source modulator to retrieve the information from
|
||||
*
|
||||
* @note The \c next member of \c mod will be left unchanged.
|
||||
*/
|
||||
void
|
||||
|
@ -41,6 +43,7 @@ fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src)
|
|||
|
||||
/**
|
||||
* Set a modulator's primary source controller and flags.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
|
||||
* @param flags Flags determining mapping function and whether the source
|
||||
|
@ -56,6 +59,7 @@ fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags)
|
|||
|
||||
/**
|
||||
* Set a modulator's secondary source controller and flags.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
|
||||
* @param flags Flags determining mapping function and whether the source
|
||||
|
@ -71,6 +75,7 @@ fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags)
|
|||
|
||||
/**
|
||||
* Set the destination effect of a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @param dest Destination generator (#fluid_gen_type)
|
||||
*/
|
||||
|
@ -82,6 +87,7 @@ fluid_mod_set_dest(fluid_mod_t *mod, int dest)
|
|||
|
||||
/**
|
||||
* Set the scale amount of a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @param amount Scale amount to assign
|
||||
*/
|
||||
|
@ -93,6 +99,7 @@ fluid_mod_set_amount(fluid_mod_t *mod, double amount)
|
|||
|
||||
/**
|
||||
* Get the primary source value from a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @return The primary source value (#fluid_mod_src or a MIDI CC controller value).
|
||||
*/
|
||||
|
@ -104,6 +111,7 @@ fluid_mod_get_source1(const fluid_mod_t *mod)
|
|||
|
||||
/**
|
||||
* Get primary source flags from a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @return The primary source flags (#fluid_mod_flags).
|
||||
*/
|
||||
|
@ -115,6 +123,7 @@ fluid_mod_get_flags1(const fluid_mod_t *mod)
|
|||
|
||||
/**
|
||||
* Get the secondary source value from a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @return The secondary source value (#fluid_mod_src or a MIDI CC controller value).
|
||||
*/
|
||||
|
@ -126,6 +135,7 @@ fluid_mod_get_source2(const fluid_mod_t *mod)
|
|||
|
||||
/**
|
||||
* Get secondary source flags from a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @return The secondary source flags (#fluid_mod_flags).
|
||||
*/
|
||||
|
@ -137,6 +147,7 @@ fluid_mod_get_flags2(const fluid_mod_t *mod)
|
|||
|
||||
/**
|
||||
* Get destination effect from a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @return Destination generator (#fluid_gen_type)
|
||||
*/
|
||||
|
@ -148,6 +159,7 @@ fluid_mod_get_dest(const fluid_mod_t *mod)
|
|||
|
||||
/**
|
||||
* Get the scale amount from a modulator.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @return Scale amount
|
||||
*/
|
||||
|
@ -466,6 +478,7 @@ fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
|
|||
|
||||
/**
|
||||
* Create a new uninitialized modulator structure.
|
||||
*
|
||||
* @return New allocated modulator or NULL if out of memory
|
||||
*/
|
||||
fluid_mod_t *
|
||||
|
@ -484,6 +497,7 @@ new_fluid_mod()
|
|||
|
||||
/**
|
||||
* Free a modulator structure.
|
||||
*
|
||||
* @param mod Modulator to free
|
||||
*/
|
||||
void
|
||||
|
@ -495,9 +509,9 @@ delete_fluid_mod(fluid_mod_t *mod)
|
|||
/**
|
||||
* Returns the size of the fluid_mod_t structure.
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a modulator on the stack.
|
||||
*
|
||||
* @return Size of fluid_mod_t in bytes
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a modulator on the stack.
|
||||
*/
|
||||
size_t fluid_mod_sizeof()
|
||||
{
|
||||
|
@ -518,13 +532,14 @@ fluid_mod_is_src1_none(const fluid_mod_t *mod)
|
|||
|
||||
/**
|
||||
* Checks if modulators source other than CC source is invalid.
|
||||
* (specs SF 2.01 7.4, 7.8, 8.2.1)
|
||||
*
|
||||
* @param mod, modulator.
|
||||
* @param src1_select, source input selection to check.
|
||||
* 1 to check src1 source.
|
||||
* 0 to check src2 source.
|
||||
* @return FALSE if selected modulator source other than cc is invalid, TRUE otherwise.
|
||||
*
|
||||
* (specs SF 2.01 7.4, 7.8, 8.2.1)
|
||||
*/
|
||||
static int
|
||||
fluid_mod_check_non_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
|
||||
|
@ -556,6 +571,7 @@ fluid_mod_check_non_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
|
|||
|
||||
/**
|
||||
* Checks if modulator CC source is invalid (specs SF 2.01 7.4, 7.8, 8.2.1).
|
||||
*
|
||||
* @param mod, modulator.
|
||||
* @src1_select, source input selection:
|
||||
* 1 to check src1 source or
|
||||
|
@ -599,6 +615,7 @@ fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
|
|||
|
||||
/**
|
||||
* Checks valid modulator sources (specs SF 2.01 7.4, 7.8, 8.2.1)
|
||||
*
|
||||
* @param mod, modulator.
|
||||
* @param name,if not NULL, pointer on a string displayed as a warning.
|
||||
* @return TRUE if modulator sources src1, src2 are valid, FALSE otherwise.
|
||||
|
@ -677,6 +694,7 @@ int fluid_mod_check_sources(const fluid_mod_t *mod, const char *name)
|
|||
|
||||
/**
|
||||
* 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
|
||||
|
@ -720,6 +738,7 @@ int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl)
|
|||
|
||||
/**
|
||||
* Check if the modulator has the given destination.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @param gen The destination generator of type #fluid_gen_type to check for
|
||||
* @return TRUE if the modulator has the given destination, FALSE otherwise.
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
* output is the same. This sounds like a monophonic signal.
|
||||
* When 100, the separation between left and right is maximum.
|
||||
*
|
||||
* - level (0 to 1), controls the ouput level reverberation.
|
||||
* - level (0 to 1), controls the output level reverberation.
|
||||
*
|
||||
* This FDN reverb produces a better quality reverberation tail than Freeverb with
|
||||
* far less ringing by using modulated delay lines that help to cancel
|
||||
|
@ -120,17 +120,17 @@
|
|||
* freeverb | 2 x 8 comb | 0.670 % | 204616 | ringing
|
||||
* | 2 x 4 all-pass | | |
|
||||
* ----------|---------------------------------------------------------------
|
||||
* FDN | 8 | 0.650 % | 112160 | far less
|
||||
* modulated | |(feeverb - 3%) | (55% freeverb) | ringing
|
||||
* FDN | 8 | 0.650 % | 112480 | far less
|
||||
* modulated | |(feeverb - 3%) | (56% freeverb) | ringing
|
||||
* |---------------------------------------------------------------
|
||||
* | 12 | 0.942 % | 168240 | best than
|
||||
* | 12 | 0.942 % | 168720 | best than
|
||||
* | |(freeverb + 41%) | (82 %freeverb) | 8 lines
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* Note:
|
||||
* Values in this column is the memory consumption for sample rate <= 44100Hz.
|
||||
* For sample rate > 44100Hz , multiply these values by (sample rate / 44100Hz).
|
||||
*
|
||||
* For example: for sample rate 96000Hz, the memory consumed is 244760 bytes
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
* 'Denormalise' method to avoid loss of performance.
|
||||
|
@ -182,7 +182,7 @@
|
|||
|
||||
/* Number of delay lines (must be only 8 or 12)
|
||||
8 is the default.
|
||||
12 produces a better quality but is +50% cpu expensive
|
||||
12 produces a better quality but is +50% cpu expensive.
|
||||
*/
|
||||
#define NBR_DELAYS 8 /* default*/
|
||||
|
||||
|
@ -274,7 +274,7 @@ a flatter response on comb filter. So the input gain is set to 0.1 rather 1.0. *
|
|||
/*
|
||||
Number of samples to add to the desired length of a delay line. This
|
||||
allow to take account of modulation interpolation.
|
||||
1 is sufficient with MOD_DEPTH equal to 6.
|
||||
1 is sufficient with MOD_DEPTH equal to 4.
|
||||
*/
|
||||
#define INTERP_SAMPLES_NBR 1
|
||||
|
||||
|
@ -368,7 +368,7 @@ static void set_fdn_delay_lpf(fdn_delay_lpf *lpf,
|
|||
typedef struct
|
||||
{
|
||||
fluid_real_t *line; /* buffer line */
|
||||
int size; /* effective internal size (in samples) */
|
||||
int size; /* effective internal size (in samples) */
|
||||
/*-------------*/
|
||||
int line_in; /* line in position */
|
||||
int line_out; /* line out position */
|
||||
|
@ -428,7 +428,7 @@ typedef struct
|
|||
static void set_mod_frequency(sinus_modulator *mod,
|
||||
float freq, float sample_rate, float phase)
|
||||
{
|
||||
fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* intial angle */
|
||||
fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* initial angle */
|
||||
fluid_real_t a;
|
||||
|
||||
mod->a1 = 2 * FLUID_COS(w);
|
||||
|
@ -500,115 +500,6 @@ typedef struct
|
|||
fluid_real_t buffer;
|
||||
} mod_delay_line;
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Modulated delay line initialization.
|
||||
|
||||
Sets the length line ( alloc delay samples).
|
||||
Remark: the function sets the internal size accordling to the length delay_length.
|
||||
As the delay line is a modulated line, its internal size is augmented by mod_depth.
|
||||
The size is also augmented by INTERP_SAMPLES_NBR to take account of interpolation.
|
||||
|
||||
@param mdl, pointer on modulated delay line.
|
||||
@param delay_length the length of the delay line in samples.
|
||||
@param mod_depth depth of the modulation in samples (amplitude of the sine wave).
|
||||
@param mod_rate the rate of the modulation in samples.
|
||||
@return FLUID_OK if success , FLUID_FAILED if memory error.
|
||||
|
||||
Return FLUID_OK if success, FLUID_FAILED if memory error.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static int set_mod_delay_line(mod_delay_line *mdl,
|
||||
int delay_length,
|
||||
int mod_depth,
|
||||
int mod_rate
|
||||
)
|
||||
{
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* checks parameter */
|
||||
if(delay_length < 1)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* limits mod_depth to the requested delay length */
|
||||
if(mod_depth >= delay_length)
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO,
|
||||
"fdn reverb: modulation depth has been limited");
|
||||
mod_depth = delay_length - 1;
|
||||
}
|
||||
|
||||
mdl->mod_depth = mod_depth;
|
||||
/*-----------------------------------------------------------------------
|
||||
allocates delay_line and initialize members:
|
||||
- line, size, line_in, line_out...
|
||||
*/
|
||||
{
|
||||
/* total size of the line:
|
||||
size = INTERP_SAMPLES_NBR + mod_depth + delay_length */
|
||||
mdl->dl.size = delay_length + mod_depth + INTERP_SAMPLES_NBR;
|
||||
mdl->dl.line = FLUID_ARRAY(fluid_real_t, mdl->dl.size);
|
||||
|
||||
if(! mdl->dl.line)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
clear_delay_line(&mdl->dl); /* clears the buffer */
|
||||
|
||||
/* Initializes line_in to the start of the buffer */
|
||||
mdl->dl.line_in = 0;
|
||||
/* Initializes line_out index INTERP_SAMPLES_NBR samples after line_in */
|
||||
/* so that the delay between line_out and line_in is:
|
||||
mod_depth + delay_length */
|
||||
mdl->dl.line_out = mdl->dl.line_in + INTERP_SAMPLES_NBR;
|
||||
}
|
||||
|
||||
/* Damping low pass filter -------------------*/
|
||||
mdl->dl.damping.buffer = 0;
|
||||
/*------------------------------------------------------------------------
|
||||
Initializes modulation members:
|
||||
- modulated center position: center_pos_mod
|
||||
- index rate to know when to update center_pos_mod:index_rate
|
||||
- modulation rate (the speed at which center_pos_mod is modulated: mod_rate
|
||||
- interpolator member: buffer, frac_pos_mod
|
||||
-------------------------------------------------------------------------*/
|
||||
/* Sets the modulation rate. This rate defines how often
|
||||
the center position (center_pos_mod ) is modulated .
|
||||
The value is expressed in samples. The default value is 1 that means that
|
||||
center_pos_mod is updated at every sample.
|
||||
For example with a value of 2, the center position position will be
|
||||
updated only one time every 2 samples only.
|
||||
*/
|
||||
mdl->mod_rate = 1; /* default modulation rate: every one sample */
|
||||
|
||||
if(mod_rate > mdl->dl.size)
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO,
|
||||
"fdn reverb: modulation rate is out of range");
|
||||
}
|
||||
else
|
||||
{
|
||||
mdl->mod_rate = mod_rate;
|
||||
}
|
||||
|
||||
/* Initializes the modulated center position (center_pos_mod) so that:
|
||||
- the delay between line_out and center_pos_mod is mod_depth.
|
||||
- the delay between center_pos_mod and line_in is delay_length.
|
||||
*/
|
||||
mdl->center_pos_mod = (fluid_real_t) INTERP_SAMPLES_NBR + mod_depth;
|
||||
|
||||
/* index rate to control when to update center_pos_mod */
|
||||
/* Important: must be set to get center_pos_mod immediatly used for the
|
||||
reading of first sample (see get_mod_delay()) */
|
||||
mdl->index_rate = mdl->mod_rate;
|
||||
|
||||
/* initializes 1st order All-Pass interpolator members */
|
||||
mdl->buffer = 0; /* previous delay sample value */
|
||||
mdl->frac_pos_mod = 0; /* fractional position (between consecutives sample) */
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Return norminal delay length
|
||||
|
||||
|
@ -631,7 +522,7 @@ static FLUID_INLINE fluid_real_t get_mod_delay(mod_delay_line *mdl)
|
|||
fluid_real_t out; /* value to return */
|
||||
|
||||
/* Checks if the modulator must be updated (every mod_rate samples). */
|
||||
/* Important: center_pos_mod must be used immediatly for the
|
||||
/* Important: center_pos_mod must be used immediately for the
|
||||
first sample. So, mdl->index_rate must be initialized
|
||||
to mdl->mod_rate (set_mod_delay_line()) */
|
||||
|
||||
|
@ -688,7 +579,7 @@ static FLUID_INLINE fluid_real_t get_mod_delay(mod_delay_line *mdl)
|
|||
mdl->dl.line_out -= mdl->dl.size;
|
||||
}
|
||||
|
||||
/* Fractional interpolation beetween next sample (at next position) and
|
||||
/* Fractional interpolation between next sample (at next position) and
|
||||
previous output added to current sample.
|
||||
*/
|
||||
out += mdl->frac_pos_mod * (mdl->dl.line[mdl->dl.line_out] - mdl->buffer);
|
||||
|
@ -702,6 +593,7 @@ static FLUID_INLINE fluid_real_t get_mod_delay(mod_delay_line *mdl)
|
|||
struct _fluid_late
|
||||
{
|
||||
fluid_real_t samplerate; /* sample rate */
|
||||
fluid_real_t sample_rate_max; /* sample rate maximum */
|
||||
/*----- High pass tone corrector -------------------------------------*/
|
||||
fluid_real_t tone_buffer;
|
||||
fluid_real_t b1, b2;
|
||||
|
@ -904,118 +796,220 @@ static void delete_fluid_rev_late(fluid_late *late)
|
|||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Creates all modulated lines.
|
||||
@param late, pointer on the fnd late reverb to initialize.
|
||||
@param sample_rate, the audio sample rate.
|
||||
@return FLUID_OK if success, FLUID_FAILED otherwise.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static int create_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate)
|
||||
|
||||
/* Nominal delay lines length table (in samples) */
|
||||
static const int nom_delay_length[NBR_DELAYS] =
|
||||
{
|
||||
/* Delay lines length table (in samples) */
|
||||
static const int delay_length[NBR_DELAYS] =
|
||||
{
|
||||
DELAY_L0, DELAY_L1, DELAY_L2, DELAY_L3,
|
||||
DELAY_L4, DELAY_L5, DELAY_L6, DELAY_L7,
|
||||
#if (NBR_DELAYS == 12)
|
||||
DELAY_L8, DELAY_L9, DELAY_L10, DELAY_L11
|
||||
#endif
|
||||
};
|
||||
DELAY_L0, DELAY_L1, DELAY_L2, DELAY_L3,
|
||||
DELAY_L4, DELAY_L5, DELAY_L6, DELAY_L7,
|
||||
#if (NBR_DELAYS == 12)
|
||||
DELAY_L8, DELAY_L9, DELAY_L10, DELAY_L11
|
||||
#endif
|
||||
};
|
||||
|
||||
int result; /* return value */
|
||||
int i;
|
||||
/*
|
||||
1)"modal density" is one property that contributes to the quality of the reverb tail.
|
||||
The more is the modal density, the less are unwanted resonant frequencies
|
||||
build during the decay time: modal density = total delay / sample rate.
|
||||
|
||||
/*
|
||||
1)"modal density" is one property that contributes to the quality of the reverb tail.
|
||||
The more is the modal density, the less are unwanted resonant frequencies
|
||||
build during the decay time: modal density = total delay / sample rate.
|
||||
Delay line's length given by static table delay_length[] are nominal
|
||||
to get minimum modal density of 0.15 at sample rate 44100Hz.
|
||||
Here we set length_factor to 2 to multiply this nominal modal
|
||||
density by 2. This leads to a default modal density of 0.15 * 2 = 0.3 for
|
||||
sample rate <= 44100.
|
||||
|
||||
Delay line's length given by static table delay_length[] is nominal
|
||||
to get minimum modal density of 0.15 at sample rate 44100Hz.
|
||||
Here we set length_factor to 2 to mutiply this nominal modal
|
||||
density by 2. This leads to a default modal density of 0.15 * 2 = 0.3 for
|
||||
sample rate <= 44100.
|
||||
For sample rate > 44100, length_factor is multiplied by
|
||||
sample_rate / 44100. This ensures that the default modal density keeps inchanged.
|
||||
(Without this compensation, the default modal density would be diminished for
|
||||
new sample rate change above 44100Hz).
|
||||
|
||||
For sample rate > 44100, length_factor is multiplied by
|
||||
sample_rate / 44100. This ensures that the default modal density keeps inchanged.
|
||||
(Without this compensation, the default modal density would be diminished for
|
||||
new sample rate change above 44100Hz).
|
||||
|
||||
2)Modulated delay line contributes to diminish resonnant frequencies (often called "ringing").
|
||||
Modulation depth (mod_depth) is set to nominal value of MOD_DEPTH at sample rate 44100Hz.
|
||||
For sample rate > 44100, mod_depth is multiplied by sample_rate / 44100. This ensures
|
||||
that the effect of modulated delay line keeps inchanged.
|
||||
*/
|
||||
fluid_real_t length_factor = 2.0f;
|
||||
fluid_real_t mod_depth = MOD_DEPTH;
|
||||
2)Modulated delay line contributes to diminish resonnant frequencies (often called "ringing").
|
||||
Modulation depth (mod_depth) is set to nominal value of MOD_DEPTH at sample rate 44100Hz.
|
||||
For sample rate > 44100, mod_depth is multiplied by sample_rate / 44100. This ensures
|
||||
that the effect of modulated delay line remains inchanged.
|
||||
*/
|
||||
static void compensate_from_sample_rate(fluid_real_t sample_rate,
|
||||
fluid_real_t *mod_depth,
|
||||
fluid_real_t *length_factor)
|
||||
{
|
||||
*mod_depth = MOD_DEPTH;
|
||||
*length_factor = 2.0f;
|
||||
if(sample_rate > 44100.0f)
|
||||
{
|
||||
fluid_real_t sample_rate_factor = sample_rate/44100.0f;
|
||||
length_factor *= sample_rate_factor;
|
||||
mod_depth *= sample_rate_factor;
|
||||
*length_factor *= sample_rate_factor;
|
||||
*mod_depth *= sample_rate_factor;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Creates all modulated lines.
|
||||
@param late, pointer on the fnd late reverb to initialize.
|
||||
@param sample_rate_max, the maximum audio sample rate expected.
|
||||
@return FLUID_OK if success, FLUID_FAILED otherwise.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static int create_mod_delay_lines(fluid_late *late,
|
||||
fluid_real_t sample_rate_max)
|
||||
{
|
||||
int i;
|
||||
|
||||
fluid_real_t mod_depth, length_factor;
|
||||
|
||||
/* compute mod_depth, length factor */
|
||||
compensate_from_sample_rate(sample_rate_max, &mod_depth, &length_factor);
|
||||
|
||||
late->sample_rate_max = sample_rate_max;
|
||||
|
||||
#ifdef INFOS_PRINT // allows message to be printed on the console.
|
||||
printf("length_factor:%f, mod_depth:%f\n", length_factor, mod_depth);
|
||||
/* Print: modal density and total memory bytes */
|
||||
{
|
||||
int i;
|
||||
int total_delay; /* total delay in samples */
|
||||
for (i = 0, total_delay = 0; i < NBR_DELAYS; i++)
|
||||
int total_delay = 0; /* total delay in samples */
|
||||
for (i = 0; i < NBR_DELAYS; i++)
|
||||
{
|
||||
total_delay += length_factor * delay_length[i];
|
||||
int length = (length_factor * nom_delay_length[i])
|
||||
+ mod_depth + INTERP_SAMPLES_NBR;
|
||||
total_delay += length;
|
||||
}
|
||||
|
||||
/* modal density and total memory bytes */
|
||||
printf("modal density:%f, total memory:%d bytes\n",
|
||||
total_delay / sample_rate , total_delay * sizeof(fluid_real_t));
|
||||
printf("modal density:%f, total delay:%d, total memory:%d bytes\n",
|
||||
total_delay / sample_rate_max ,total_delay ,
|
||||
total_delay * sizeof(fluid_real_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */
|
||||
{
|
||||
/* allocate delay line and set local delay lines's parameters */
|
||||
result = set_mod_delay_line(&late->mod_delay_lines[i],
|
||||
delay_length[i] * length_factor,
|
||||
mod_depth, MOD_RATE);
|
||||
int delay_length = nom_delay_length[i] * length_factor;
|
||||
mod_delay_line *mdl = &late->mod_delay_lines[i];
|
||||
|
||||
if(result == FLUID_FAILED)
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* checks parameter */
|
||||
if(delay_length < 1)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* Sets local Modulators parameters: frequency and phase
|
||||
Each modulateur are shifted of MOD_PHASE degree
|
||||
/* limits mod_depth to the requested delay length */
|
||||
if(mod_depth >= delay_length)
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO,
|
||||
"fdn reverb: modulation depth has been limited");
|
||||
mod_depth = delay_length - 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
allocates delay lines
|
||||
*/
|
||||
set_mod_frequency(&late->mod_delay_lines[i].mod,
|
||||
MOD_FREQ * MOD_RATE,
|
||||
late->samplerate,
|
||||
(float)(MOD_PHASE * i));
|
||||
|
||||
/* real size of the line in use (in samples):
|
||||
size = INTERP_SAMPLES_NBR + mod_depth + delay_length */
|
||||
mdl->dl.size = delay_length + mod_depth + INTERP_SAMPLES_NBR;
|
||||
mdl->dl.line = FLUID_ARRAY(fluid_real_t, mdl->dl.size);
|
||||
|
||||
if(! mdl->dl.line)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Creates the fdn reverb.
|
||||
Initialize all modulated lines.
|
||||
@param late, pointer on the fnd late reverb to initialize.
|
||||
@param sample_rate the sample rate.
|
||||
@param sample_rate, the audio sample rate.
|
||||
@return FLUID_OK if success, FLUID_FAILED otherwise.
|
||||
-----------------------------------------------------------------------------*/
|
||||
static int create_fluid_rev_late(fluid_late *late, fluid_real_t sample_rate)
|
||||
static void initialize_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate)
|
||||
{
|
||||
FLUID_MEMSET(late, 0, sizeof(fluid_late));
|
||||
int i;
|
||||
fluid_real_t mod_depth, length_factor;
|
||||
|
||||
/* update delay line parameter dependant of sample rate */
|
||||
late->samplerate = sample_rate;
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
First initialize the modulated delay lines
|
||||
*/
|
||||
/* compute mod_depth, length factor */
|
||||
compensate_from_sample_rate(sample_rate, &mod_depth, &length_factor);
|
||||
|
||||
if(create_mod_delay_lines(late, sample_rate) == FLUID_FAILED)
|
||||
for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
mod_delay_line *mdl = &late->mod_delay_lines[i];
|
||||
int delay_length = nom_delay_length[i] * length_factor;
|
||||
|
||||
return FLUID_OK;
|
||||
/* limits mod_depth to the requested delay length */
|
||||
if(mod_depth >= delay_length)
|
||||
{
|
||||
mod_depth = delay_length - 1;
|
||||
}
|
||||
|
||||
mdl->mod_depth = mod_depth;
|
||||
|
||||
clear_delay_line(&mdl->dl); /* clears the buffer */
|
||||
|
||||
/* Initializes line_in to the start of the buffer */
|
||||
mdl->dl.line_in = 0;
|
||||
|
||||
/* Initializes line_out index INTERP_SAMPLES_NBR samples after
|
||||
line_in so that the delay between line_out and line_in is:
|
||||
mod_depth + delay_length
|
||||
*/
|
||||
mdl->dl.line_out = mdl->dl.line_in + INTERP_SAMPLES_NBR;
|
||||
|
||||
/* Damping low pass filter ------------------------------------------*/
|
||||
mdl->dl.damping.buffer = 0;
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Initializes modulation members:
|
||||
- modulated center position: center_pos_mod
|
||||
- modulation rate (the speed at which center_pos_mod is modulated: mod_rate
|
||||
- index rate to know when to update center_pos_mod:index_rate
|
||||
- interpolator member: buffer, frac_pos_mod
|
||||
---------------------------------------------------------------------*/
|
||||
/* Initializes the modulated center position (center_pos_mod) so that:
|
||||
- the delay between line_out and center_pos_mod is mod_depth.
|
||||
- the delay between center_pos_mod and line_in is delay_length.
|
||||
*/
|
||||
mdl->center_pos_mod = (fluid_real_t) INTERP_SAMPLES_NBR + mod_depth;
|
||||
|
||||
/* Sets the modulation rate. This rate defines how often
|
||||
the center position (center_pos_mod ) is modulated .
|
||||
The value is expressed in samples. The default value is 1 that means that
|
||||
center_pos_mod is updated at every sample.
|
||||
For example with a value of 2, the center position position will be
|
||||
updated only one time every 2 samples only.
|
||||
*/
|
||||
if(MOD_RATE < 1 || MOD_RATE > mdl->dl.size)
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO, "fdn reverb: modulation rate is out of range");
|
||||
mdl->mod_rate = 1; /* default modulation rate: every one sample */
|
||||
}
|
||||
else
|
||||
{
|
||||
mdl->mod_rate = MOD_RATE;
|
||||
}
|
||||
|
||||
/* index rate to control when to update center_pos_mod.
|
||||
Important: must be set to get center_pos_mod immediately used for
|
||||
the reading of first sample (see get_mod_delay())
|
||||
*/
|
||||
mdl->index_rate = mdl->mod_rate;
|
||||
|
||||
/* initializes first order All-Pass interpolator members */
|
||||
mdl->buffer = 0; /* previous delay sample value */
|
||||
mdl->frac_pos_mod = 0; /* frac. position (between consecutives sample) */
|
||||
|
||||
|
||||
/* Sets local Modulators parameters: frequency and phase.
|
||||
Each modulateur are shifted of MOD_PHASE degree
|
||||
*/
|
||||
set_mod_frequency(&mdl->mod,
|
||||
MOD_FREQ * MOD_RATE,
|
||||
sample_rate,
|
||||
(float)(MOD_PHASE * i));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1055,7 +1049,7 @@ fluid_revmodel_update(fluid_revmodel_t *rev)
|
|||
fluid_real_t wet = (rev->level * SCALE_WET) /
|
||||
(1.0f + rev->width * SCALE_WET_WIDTH);
|
||||
|
||||
/* wet1 and wet2 are used by the stereo effect controled by the width setting
|
||||
/* wet1 and wet2 are used by the stereo effect controlled by the width setting
|
||||
for producing a stereo ouptput from a monophonic reverb signal.
|
||||
Please see the note above about a side effect tendency */
|
||||
|
||||
|
@ -1077,20 +1071,27 @@ fluid_revmodel_update(fluid_revmodel_t *rev)
|
|||
/*----------------------------------------------------------------------------
|
||||
Reverb API
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Creates a reverb. One created the reverb have no parameters set, so
|
||||
* Creates a reverb. Once created the reverb have no parameters set, so
|
||||
* fluid_revmodel_set() must be called at least one time after calling
|
||||
* new_fluid_revmodel().
|
||||
*
|
||||
* @param sample_rate sample rate in Hz.
|
||||
* @param sample_rate_max maximum sample rate expected in Hz.
|
||||
*
|
||||
* @param sample_rate actual sample rate needed in Hz.
|
||||
* @return pointer on the new reverb or NULL if memory error.
|
||||
* Reverb API.
|
||||
*/
|
||||
fluid_revmodel_t *
|
||||
new_fluid_revmodel(fluid_real_t sample_rate)
|
||||
new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate)
|
||||
{
|
||||
fluid_revmodel_t *rev;
|
||||
|
||||
if(sample_rate <= 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rev = FLUID_NEW(fluid_revmodel_t);
|
||||
|
||||
if(rev == NULL)
|
||||
|
@ -1098,13 +1099,33 @@ new_fluid_revmodel(fluid_real_t sample_rate)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* create fdn reverb */
|
||||
if(create_fluid_rev_late(&rev->late, sample_rate) != FLUID_OK)
|
||||
FLUID_MEMSET(&rev->late, 0, sizeof(fluid_late));
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Create fdn late reverb.
|
||||
*/
|
||||
|
||||
/* update minimum value for sample_rate_max */
|
||||
if(sample_rate > sample_rate_max)
|
||||
{
|
||||
sample_rate_max = sample_rate;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Allocate the modulated delay lines
|
||||
*/
|
||||
if(create_mod_delay_lines(&rev->late, sample_rate_max) == FLUID_FAILED)
|
||||
{
|
||||
delete_fluid_revmodel(rev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Initialize the fdn reverb
|
||||
*/
|
||||
/* Initialize all modulated lines. */
|
||||
initialize_mod_delay_lines(&rev->late, sample_rate);
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
|
@ -1131,11 +1152,12 @@ delete_fluid_revmodel(fluid_revmodel_t *rev)
|
|||
|
||||
/*
|
||||
* Sets one or more reverb parameters. Note this must be called at least one
|
||||
* time after calling new_fluid_revmodel().
|
||||
* time after calling new_fluid_revmodel() and before any call to
|
||||
* fluid_revmodel_processXXX() and fluid_revmodel_samplerate_change().
|
||||
*
|
||||
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
|
||||
* function, calling fluid_revmodel_set() could produce audible clics.
|
||||
* If this is a problem, optionnaly call fluid_revmodel_reset() before calling
|
||||
* If this is a problem, optionally call fluid_revmodel_reset() before calling
|
||||
* fluid_revmodel_set().
|
||||
*
|
||||
* @param rev Reverb instance.
|
||||
|
@ -1152,6 +1174,8 @@ void
|
|||
fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
|
||||
fluid_real_t damping, fluid_real_t width, fluid_real_t level)
|
||||
{
|
||||
fluid_return_if_fail(rev != NULL);
|
||||
|
||||
/*-----------------------------------*/
|
||||
if(set & FLUID_REVMODEL_SET_ROOMSIZE)
|
||||
{
|
||||
|
@ -1185,12 +1209,15 @@ fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
|
|||
|
||||
/*
|
||||
* Applies a sample rate change on the reverb.
|
||||
* fluid_revmodel_set() must be called at least one time before calling
|
||||
* this function.
|
||||
*
|
||||
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
|
||||
* function, calling fluid_revmodel_samplerate_change() isn't multi task safe because
|
||||
* delay line are memory reallocated. To deal properly with this issue follow
|
||||
* the steps:
|
||||
* function, calling fluid_revmodel_samplerate_change() isn't multi task safe.
|
||||
* To deal properly with this issue follow the steps:
|
||||
* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().
|
||||
* reverb functions.
|
||||
* Optionally, call fluid_revmodel_reset() to damp the reverb.
|
||||
* 2) Change sample rate by calling fluid_revmodel_samplerate_change().
|
||||
* 3) Restart reverb processing (i.e enabling calling of any fluid_revmodel_processXXX()
|
||||
* reverb functions.
|
||||
|
@ -1199,29 +1226,44 @@ fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
|
|||
* 2.1) delete the reverb by calling delete_fluid_revmodel().
|
||||
* 2.2) create the reverb by calling new_fluid_revmodel().
|
||||
*
|
||||
* The best solution would be that this function be called only by the same task
|
||||
* calling fluid_revmodel_processXXX().
|
||||
*
|
||||
* @param rev the reverb.
|
||||
* @param sample_rate new sample rate value.
|
||||
* @return FLUID_OK if success, FLUID_FAILED otherwise (memory error).
|
||||
* @param sample_rate new sample rate value. Must be <= sample_rate_max
|
||||
* @return FLUID_OK if success, FLUID_FAILED if new sample rate is greater
|
||||
* then the maximumum sample rate set at creation time. The reverb will
|
||||
* continue to work but with possible lost of quality.
|
||||
* If this is a problem, the caller should follow steps 2.1 and 2.2.
|
||||
* Reverb API.
|
||||
*/
|
||||
int
|
||||
fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)
|
||||
{
|
||||
rev->late.samplerate = sample_rate; /* new sample rate value */
|
||||
int status = FLUID_OK;
|
||||
|
||||
/* free all delay lines */
|
||||
delete_fluid_rev_late(&rev->late);
|
||||
fluid_return_val_if_fail(rev != NULL, FLUID_FAILED);
|
||||
|
||||
/* create all delay lines */
|
||||
if(create_mod_delay_lines(&rev->late, sample_rate) == FLUID_FAILED)
|
||||
if(sample_rate > rev->late.sample_rate_max)
|
||||
{
|
||||
return FLUID_FAILED; /* memory error */
|
||||
FLUID_LOG(FLUID_WARN,
|
||||
"fdn reverb: sample rate %.0f Hz is deduced to %.0f Hz\n",
|
||||
sample_rate, rev->late.sample_rate_max);
|
||||
|
||||
/* Reduce sample rate to the maximum value set at creation time.
|
||||
The reverb will continue to work with possible lost of quality.
|
||||
*/
|
||||
sample_rate = rev->late.sample_rate_max;
|
||||
status = FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* Initialize all modulated lines according to sample rate change. */
|
||||
initialize_mod_delay_lines(&rev->late, sample_rate);
|
||||
|
||||
/* updates damping filter coefficients according to sample rate change */
|
||||
update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);
|
||||
|
||||
return FLUID_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1233,6 +1275,8 @@ fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate
|
|||
void
|
||||
fluid_revmodel_reset(fluid_revmodel_t *rev)
|
||||
{
|
||||
fluid_return_if_fail(rev != NULL);
|
||||
|
||||
fluid_revmodel_init(rev);
|
||||
}
|
||||
|
||||
|
@ -1298,7 +1342,7 @@ fluid_revmodel_processreplace(fluid_revmodel_t *rev, const fluid_real_t *in,
|
|||
process_damping_filter(delay_out_s, delay_out_s, mdl);
|
||||
|
||||
/* Result in delay_out[], and matrix_factor.
|
||||
These wil be use later during input line process */
|
||||
These will be of use later during input line process */
|
||||
delay_out[i] = delay_out_s; /* result in delay_out[] */
|
||||
matrix_factor += delay_out_s; /* result in matrix_factor */
|
||||
|
||||
|
@ -1347,7 +1391,7 @@ fluid_revmodel_processreplace(fluid_revmodel_t *rev, const fluid_real_t *in,
|
|||
right_out[k] = out_right * rev->wet1 + out_left * rev->wet2;
|
||||
|
||||
As wet1 is integrated in stereo coefficient wet 1 is now
|
||||
integrated in out_left and out_right we simplify previous
|
||||
integrated in out_left and out_right, so we simplify previous
|
||||
relation by suppression of one multiply as this:
|
||||
|
||||
left_out[k] = out_left + out_right * rev->wet2;
|
||||
|
@ -1419,7 +1463,7 @@ void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in,
|
|||
process_damping_filter(delay_out_s, delay_out_s, mdl);
|
||||
|
||||
/* Result in delay_out[], and matrix_factor.
|
||||
These wil be use later during input line process */
|
||||
These will be of use later during input line process */
|
||||
delay_out[i] = delay_out_s; /* result in delay_out[] */
|
||||
matrix_factor += delay_out_s; /* result in matrix_factor */
|
||||
|
||||
|
@ -1467,7 +1511,7 @@ void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in,
|
|||
right_out[k] += out_right * rev->wet1 + out_left * rev->wet2;
|
||||
|
||||
As wet1 is integrated in stereo coefficient wet 1 is now
|
||||
integrated in out_left and out_right we simplify previous
|
||||
integrated in out_left and out_right, so we simplify previous
|
||||
relation by suppression of one multiply as this:
|
||||
|
||||
left_out[k] += out_left + out_right * rev->wet2;
|
||||
|
|
|
@ -26,14 +26,26 @@
|
|||
|
||||
typedef struct _fluid_revmodel_t fluid_revmodel_t;
|
||||
|
||||
/* enum describing each reverb parameter */
|
||||
enum fluid_reverb_param
|
||||
{
|
||||
FLUID_REVERB_ROOMSIZE, /**< reverb time */
|
||||
FLUID_REVERB_DAMP, /**< high frequency damping */
|
||||
FLUID_REVERB_WIDTH, /**< stereo width */
|
||||
FLUID_REVERB_LEVEL, /**< output level */
|
||||
FLUID_REVERB_PARAM_LAST /* number of enum fluid_reverb_param */
|
||||
};
|
||||
|
||||
/* return a bit flag from param: 2^param */
|
||||
#define FLUID_REVPARAM_TO_SETFLAG(param) (1 << param)
|
||||
|
||||
/** 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_ROOMSIZE = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_ROOMSIZE),
|
||||
FLUID_REVMODEL_SET_DAMPING = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_DAMP),
|
||||
FLUID_REVMODEL_SET_WIDTH = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_WIDTH),
|
||||
FLUID_REVMODEL_SET_LEVEL = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_LEVEL),
|
||||
|
||||
/** Value for fluid_revmodel_set() which sets all reverb parameters. */
|
||||
FLUID_REVMODEL_SET_ALL = FLUID_REVMODEL_SET_LEVEL
|
||||
|
@ -58,7 +70,9 @@ typedef struct _fluid_revmodel_presets_t
|
|||
/*
|
||||
* reverb
|
||||
*/
|
||||
fluid_revmodel_t *new_fluid_revmodel(fluid_real_t sample_rate);
|
||||
fluid_revmodel_t *
|
||||
new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate);
|
||||
|
||||
void delete_fluid_revmodel(fluid_revmodel_t *rev);
|
||||
|
||||
void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in,
|
||||
|
|
|
@ -493,7 +493,8 @@ fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t *buffers, unsigned int
|
|||
|
||||
for(i = buffers->count; i <= bufnum; i++)
|
||||
{
|
||||
buffers->bufs[i].amp = 0.0f;
|
||||
buffers->bufs[i].target_amp = 0.0f;
|
||||
buffers->bufs[i].current_amp = 0.0f;
|
||||
}
|
||||
|
||||
buffers->count = bufnum + 1;
|
||||
|
@ -512,7 +513,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp)
|
|||
return;
|
||||
}
|
||||
|
||||
buffers->bufs[bufnum].amp = value;
|
||||
buffers->bufs[bufnum].target_amp = value;
|
||||
}
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping)
|
||||
|
|
|
@ -143,8 +143,14 @@ 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 */
|
||||
/* the actual, linearly interpolated amplitude with which the dsp sample should be mixed into the buf */
|
||||
fluid_real_t current_amp;
|
||||
|
||||
/* the desired amplitude [...] mixed into the buf (directly set by e.g. rapidly changing PAN events) */
|
||||
fluid_real_t target_amp;
|
||||
|
||||
/* Mapping to mixdown buffer index */
|
||||
int mapping;
|
||||
} bufs[FLUID_RVOICE_MAX_BUFS];
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "fluid_sys.h"
|
||||
#include "fluid_phase.h"
|
||||
#include "fluid_rvoice.h"
|
||||
#include "fluid_rvoice_dsp_tables.c"
|
||||
#include "fluid_rvoice_dsp_tables.inc.h"
|
||||
|
||||
/* Purpose:
|
||||
*
|
||||
|
|
|
@ -88,7 +88,7 @@ static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *han
|
|||
if(event == NULL)
|
||||
{
|
||||
fluid_atomic_int_add(&handler->queue_stored, -1);
|
||||
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
|
||||
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing synth.polyphony!");
|
||||
return FLUID_FAILED; // Buffer full...
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,9 @@ fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *e
|
|||
|
||||
fluid_rvoice_eventhandler_t *
|
||||
new_fluid_rvoice_eventhandler(int queuesize,
|
||||
int finished_voices_size, int bufs, int fx_bufs, int fx_units, fluid_real_t sample_rate, int extra_threads, int prio)
|
||||
int finished_voices_size, int bufs, int fx_bufs, int fx_units,
|
||||
fluid_real_t sample_rate_max, fluid_real_t sample_rate,
|
||||
int extra_threads, int prio)
|
||||
{
|
||||
fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
|
||||
|
||||
|
@ -145,7 +147,8 @@ new_fluid_rvoice_eventhandler(int queuesize,
|
|||
goto error_recovery;
|
||||
}
|
||||
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, sample_rate, eventhandler, extra_threads, prio);
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units,
|
||||
sample_rate_max, sample_rate, eventhandler, extra_threads, prio);
|
||||
|
||||
if(eventhandler->mixer == NULL)
|
||||
{
|
||||
|
|
|
@ -37,7 +37,7 @@ struct _fluid_rvoice_event_t
|
|||
|
||||
/*
|
||||
* Bridge between the renderer thread and the midi state thread.
|
||||
* fluid_rvoice_eventhandler_fetch_all() can be called in parallell
|
||||
* fluid_rvoice_eventhandler_fetch_all() can be called in parallel
|
||||
* with fluid_rvoice_eventhandler_push/flush()
|
||||
*/
|
||||
struct _fluid_rvoice_eventhandler_t
|
||||
|
@ -50,7 +50,7 @@ struct _fluid_rvoice_eventhandler_t
|
|||
|
||||
fluid_rvoice_eventhandler_t *new_fluid_rvoice_eventhandler(
|
||||
int queuesize, int finished_voices_size, int bufs,
|
||||
int fx_bufs, int fx_units, fluid_real_t sample_rate, int, int);
|
||||
int fx_bufs, int fx_units, fluid_real_t sample_rate_max, fluid_real_t sample_rate, int, int);
|
||||
|
||||
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *);
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ struct _fluid_mixer_buffers_t
|
|||
|
||||
/** buffer to store the left part of a stereo channel to.
|
||||
* Specifically a two dimensional array, containing \c buf_count sample buffers
|
||||
* (i.e. for each synth.audio-channels), of which each contains
|
||||
* (i.e. for each synth.audio-groups), of which each contains
|
||||
* FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT audio items (=samples)
|
||||
* @note Each sample buffer is aligned to the FLUID_DEFAULT_ALIGNMENT
|
||||
* boundary provided that this pointer points to an aligned buffer.
|
||||
|
@ -76,7 +76,14 @@ typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t;
|
|||
struct _fluid_mixer_fx_t
|
||||
{
|
||||
fluid_revmodel_t *reverb; /**< Reverb unit */
|
||||
/* reverb shadow parameters here will be returned if queried */
|
||||
double reverb_param[FLUID_REVERB_PARAM_LAST];
|
||||
int reverb_on; /* reverb on/off */
|
||||
|
||||
fluid_chorus_t *chorus; /**< Chorus unit */
|
||||
/* chorus shadow parameters here will be returned if queried */
|
||||
double chorus_param[FLUID_CHORUS_PARAM_LAST];
|
||||
int chorus_on; /* chorus on/off */
|
||||
};
|
||||
|
||||
struct _fluid_rvoice_mixer_t
|
||||
|
@ -124,6 +131,12 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun
|
|||
{
|
||||
const int fx_channels_per_unit = mixer->buffers.fx_buf_count / mixer->fx_units;
|
||||
int i, f;
|
||||
int dry_count = mixer->buffers.buf_count; /* dry buffers count */
|
||||
int mix_fx_to_out = mixer->mix_fx_to_out; /* get mix_fx_to_out mode */
|
||||
int dry_idx = 0; /* dry buffer index */
|
||||
int buf_idx; /* buffer index */
|
||||
int samp_idx; /* sample index in buffer */
|
||||
int sample_count; /* sample count to process */
|
||||
|
||||
void (*reverb_process_func)(fluid_revmodel_t *rev, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void (*chorus_process_func)(fluid_chorus_t *chorus, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
@ -137,7 +150,7 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun
|
|||
fluid_profile_ref_var(prof_ref);
|
||||
|
||||
|
||||
if(mixer->mix_fx_to_out)
|
||||
if(mix_fx_to_out)
|
||||
{
|
||||
// mix effects to first stereo channel
|
||||
out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
|
||||
|
@ -162,16 +175,28 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun
|
|||
{
|
||||
for(f = 0; f < mixer->fx_units; f++)
|
||||
{
|
||||
int buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL;
|
||||
|
||||
for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
if(!mixer->fx[f].reverb_on)
|
||||
{
|
||||
continue; /* this reverb unit is disabled */
|
||||
}
|
||||
|
||||
buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL;
|
||||
samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
|
||||
sample_count = current_blockcount * FLUID_BUFSIZE;
|
||||
|
||||
/* in mix mode, map fx out_rev at index f to a dry buffer at index dry_idx */
|
||||
if(mix_fx_to_out)
|
||||
{
|
||||
/* dry buffer mapping, should be done more flexible in the future */
|
||||
dry_idx = (f % dry_count) * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
|
||||
}
|
||||
|
||||
for(i = 0; i < sample_count; i += FLUID_BUFSIZE, samp_idx += FLUID_BUFSIZE)
|
||||
{
|
||||
int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + i;
|
||||
|
||||
reverb_process_func(mixer->fx[f].reverb,
|
||||
&in_rev[samp_idx],
|
||||
mixer->mix_fx_to_out ? &out_rev_l[i] : &out_rev_l[samp_idx],
|
||||
mixer->mix_fx_to_out ? &out_rev_r[i] : &out_rev_r[samp_idx]);
|
||||
mix_fx_to_out ? &out_rev_l[dry_idx + i] : &out_rev_l[samp_idx],
|
||||
mix_fx_to_out ? &out_rev_r[dry_idx + i] : &out_rev_r[samp_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,16 +208,28 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun
|
|||
{
|
||||
for(f = 0; f < mixer->fx_units; f++)
|
||||
{
|
||||
int buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL;
|
||||
|
||||
for(i = 0; i < current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
|
||||
if(!mixer->fx[f].chorus_on)
|
||||
{
|
||||
continue; /* this chorus unit is disabled */
|
||||
}
|
||||
|
||||
buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL;
|
||||
samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
|
||||
sample_count = current_blockcount * FLUID_BUFSIZE;
|
||||
|
||||
/* in mix mode, map fx out_ch at index f to a dry buffer at index dry_idx */
|
||||
if(mix_fx_to_out)
|
||||
{
|
||||
/* dry buffer mapping, should be done more flexible in the future */
|
||||
dry_idx = (f % dry_count) * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
|
||||
}
|
||||
|
||||
for(i = 0; i < sample_count; i += FLUID_BUFSIZE, samp_idx += FLUID_BUFSIZE)
|
||||
{
|
||||
int samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + i;
|
||||
|
||||
chorus_process_func(mixer->fx[f].chorus,
|
||||
&in_ch [samp_idx],
|
||||
mixer->mix_fx_to_out ? &out_ch_l[i] : &out_ch_l[samp_idx],
|
||||
mixer->mix_fx_to_out ? &out_ch_r[i] : &out_ch_r[samp_idx]);
|
||||
mix_fx_to_out ? &out_ch_l[dry_idx + i] : &out_ch_l[samp_idx],
|
||||
mix_fx_to_out ? &out_ch_r[dry_idx + i] : &out_ch_r[samp_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,18 +279,18 @@ fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbu
|
|||
for(i = 0; i < buffers->mixer->fx_units; i++)
|
||||
{
|
||||
int fx_idx = i * fx_channels_per_unit;
|
||||
|
||||
|
||||
outbufs[offset + fx_idx + SYNTH_REVERB_CHANNEL] =
|
||||
(with_reverb)
|
||||
? &base_ptr[(fx_idx + SYNTH_REVERB_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
|
||||
: NULL;
|
||||
|
||||
|
||||
outbufs[offset + fx_idx + SYNTH_CHORUS_CHANNEL] =
|
||||
(with_chorus)
|
||||
? &base_ptr[(fx_idx + SYNTH_CHORUS_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
|
||||
: NULL;
|
||||
}
|
||||
|
||||
|
||||
/* 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',
|
||||
|
@ -378,7 +415,7 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
|
|||
int bufcount = buffers->count;
|
||||
int i, dsp_i;
|
||||
|
||||
/* if there is nothing to mix, return immediatly */
|
||||
/* if there is nothing to mix, return immediately */
|
||||
if(sample_count <= 0 || dest_bufcount <= 0)
|
||||
{
|
||||
return;
|
||||
|
@ -391,27 +428,65 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
|
|||
for(i = 0; i < bufcount; i++)
|
||||
{
|
||||
fluid_real_t *FLUID_RESTRICT buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
|
||||
fluid_real_t amp = buffers->bufs[i].amp;
|
||||
fluid_real_t target_amp = buffers->bufs[i].target_amp;
|
||||
fluid_real_t current_amp = buffers->bufs[i].current_amp;
|
||||
fluid_real_t amp_incr;
|
||||
|
||||
if(buf == NULL || amp == 0.0f)
|
||||
if(buf == NULL || (current_amp == 0.0f && target_amp == 0.0f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
amp_incr = (target_amp - current_amp) / FLUID_BUFSIZE;
|
||||
|
||||
FLUID_ASSERT((uintptr_t)buf % FLUID_DEFAULT_ALIGNMENT == 0);
|
||||
|
||||
/* mixdown sample_count samples in the current buffer buf
|
||||
Note, that this loop could be unrolled by FLUID_BUFSIZE elements */
|
||||
#pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
|
||||
for(dsp_i = 0; dsp_i < sample_count; dsp_i++)
|
||||
/* Mixdown sample_count samples in the current buffer buf
|
||||
*
|
||||
* For the first FLUID_BUFSIZE samples, we linearly interpolate the buffers amplitude to
|
||||
* avoid clicks/pops when rapidly changing the channels panning (issue 768).
|
||||
*
|
||||
* We could have squashed this into one single loop by using an if clause within the loop body.
|
||||
* But it seems like having two separate loops is easier for compilers to understand, and therefore
|
||||
* auto-vectorizing the loops.
|
||||
*/
|
||||
if(sample_count < FLUID_BUFSIZE)
|
||||
{
|
||||
// Index by blocks (not by samples) to let the compiler know that we always start accessing
|
||||
// buf and dsp_buf at the FLUID_BUFSIZE*sizeof(fluid_real_t) byte boundary and never somewhere
|
||||
// in between.
|
||||
// A good compiler should understand: Aha, so I don't need to add a peel loop when vectorizing
|
||||
// this loop. Great.
|
||||
buf[start_block * FLUID_BUFSIZE + dsp_i] += amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
|
||||
// scalar loop variant, the voice will have finished afterwards
|
||||
for(dsp_i = 0; dsp_i < sample_count; dsp_i++)
|
||||
{
|
||||
buf[start_block * FLUID_BUFSIZE + dsp_i] += current_amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
|
||||
current_amp += amp_incr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// here goes the vectorizable loop
|
||||
#pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
|
||||
for(dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||
{
|
||||
// We cannot simply increment current_amp by amp_incr during every iteration, as this would create a dependency and prevent vectorization.
|
||||
buf[start_block * FLUID_BUFSIZE + dsp_i] += (current_amp + amp_incr * dsp_i) * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
|
||||
}
|
||||
|
||||
// we have reached the target_amp
|
||||
if(target_amp > 0)
|
||||
{
|
||||
/* Note, that this loop could be unrolled by FLUID_BUFSIZE elements */
|
||||
#pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
|
||||
for(dsp_i = FLUID_BUFSIZE; dsp_i < sample_count; dsp_i++)
|
||||
{
|
||||
// Index by blocks (not by samples) to let the compiler know that we always start accessing
|
||||
// buf and dsp_buf at the FLUID_BUFSIZE*sizeof(fluid_real_t) byte boundary and never somewhere
|
||||
// in between.
|
||||
// A good compiler should understand: Aha, so I don't need to add a peel loop when vectorizing
|
||||
// this loop. Great.
|
||||
buf[start_block * FLUID_BUFSIZE + dsp_i] += target_amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffers->bufs[i].current_amp = target_amp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,20 +506,22 @@ fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers,
|
|||
{
|
||||
/* render one block in src_buf */
|
||||
int s = fluid_rvoice_write(rvoice, &src_buf[FLUID_BUFSIZE * i]);
|
||||
|
||||
if(s == -1)
|
||||
{
|
||||
/* the voice is silent, mix back all the previously rendered sound */
|
||||
fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed,
|
||||
total_samples - (last_block_mixed*FLUID_BUFSIZE),
|
||||
total_samples - (last_block_mixed * FLUID_BUFSIZE),
|
||||
dest_bufs, dest_bufcount);
|
||||
|
||||
last_block_mixed = i+1; /* future block start index to mix from */
|
||||
last_block_mixed = i + 1; /* future block start index to mix from */
|
||||
total_samples += FLUID_BUFSIZE; /* accumulate samples count rendered */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the voice wasn't quiet. Some samples have been rendered [0..FLUID_BUFSIZE] */
|
||||
total_samples += s;
|
||||
|
||||
if(s < FLUID_BUFSIZE)
|
||||
{
|
||||
/* voice has finished */
|
||||
|
@ -455,7 +532,7 @@ fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers,
|
|||
|
||||
/* Now mix the remaining blocks from last_block_mixed to total_sample */
|
||||
fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed,
|
||||
total_samples - (last_block_mixed*FLUID_BUFSIZE),
|
||||
total_samples - (last_block_mixed * FLUID_BUFSIZE),
|
||||
dest_bufs, dest_bufcount);
|
||||
|
||||
if(total_samples < blockcount * FLUID_BUFSIZE)
|
||||
|
@ -671,21 +748,27 @@ fluid_mixer_buffers_init(fluid_mixer_buffers_t *buffers, fluid_rvoice_mixer_t *m
|
|||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
|
||||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
fluid_real_t samplerate = param[1].real; // becausee fluid_synth_update_mixer() puts real into arg2
|
||||
fluid_real_t samplerate = param[1].real; // because fluid_synth_update_mixer() puts real into arg2
|
||||
|
||||
int i;
|
||||
|
||||
for(i = 0; i < mixer->fx_units; i++)
|
||||
{
|
||||
if(mixer->fx[i].chorus)
|
||||
{
|
||||
delete_fluid_chorus(mixer->fx[i].chorus);
|
||||
fluid_chorus_samplerate_change(mixer->fx[i].chorus, samplerate);
|
||||
}
|
||||
|
||||
mixer->fx[i].chorus = new_fluid_chorus(samplerate);
|
||||
|
||||
if(mixer->fx[i].reverb)
|
||||
{
|
||||
fluid_revmodel_samplerate_change(mixer->fx[i].reverb, samplerate);
|
||||
|
||||
/*
|
||||
fluid_revmodel_samplerate_change() shouldn't fail if the reverb was created
|
||||
with sample_rate_max set to the maximum sample rate indicated in the settings.
|
||||
If this condition isn't respected, the reverb will continue to work but with
|
||||
lost of quality.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -705,7 +788,11 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
|
|||
* @param fx_buf_count number of stereo effect buffers
|
||||
*/
|
||||
fluid_rvoice_mixer_t *
|
||||
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, fluid_real_t sample_rate, fluid_rvoice_eventhandler_t *evthandler, int extra_threads, int prio)
|
||||
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units,
|
||||
fluid_real_t sample_rate_max,
|
||||
fluid_real_t sample_rate,
|
||||
fluid_rvoice_eventhandler_t *evthandler,
|
||||
int extra_threads, int prio)
|
||||
{
|
||||
int i;
|
||||
fluid_rvoice_mixer_t *mixer = FLUID_NEW(fluid_rvoice_mixer_t);
|
||||
|
@ -724,17 +811,19 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, fluid_real
|
|||
|
||||
/* allocate the reverb module */
|
||||
mixer->fx = FLUID_ARRAY(fluid_mixer_fx_t, fx_units);
|
||||
|
||||
if(mixer->fx == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
|
||||
FLUID_MEMSET(mixer->fx, 0, fx_units * sizeof(*mixer->fx));
|
||||
|
||||
|
||||
for(i = 0; i < fx_units; i++)
|
||||
{
|
||||
mixer->fx[i].reverb = new_fluid_revmodel(sample_rate);
|
||||
/* create reverb and chorus units */
|
||||
mixer->fx[i].reverb = new_fluid_revmodel(sample_rate_max, sample_rate);
|
||||
mixer->fx[i].chorus = new_fluid_chorus(sample_rate);
|
||||
|
||||
if(mixer->fx[i].reverb == NULL || mixer->fx[i].chorus == NULL)
|
||||
|
@ -769,7 +858,7 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, fluid_real
|
|||
#endif
|
||||
|
||||
return mixer;
|
||||
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_rvoice_mixer(mixer);
|
||||
return NULL;
|
||||
|
@ -791,7 +880,7 @@ fluid_mixer_buffers_free(fluid_mixer_buffers_t *buffers)
|
|||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
fluid_return_if_fail(mixer != NULL);
|
||||
|
||||
#if ENABLE_MIXER_THREADS
|
||||
|
@ -820,7 +909,7 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer)
|
|||
#endif
|
||||
fluid_mixer_buffers_free(&mixer->buffers);
|
||||
|
||||
|
||||
|
||||
for(i = 0; i < mixer->fx_units; i++)
|
||||
{
|
||||
if(mixer->fx[i].reverb)
|
||||
|
@ -839,7 +928,6 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer)
|
|||
FLUID_FREE(mixer);
|
||||
}
|
||||
|
||||
|
||||
#ifdef LADSPA
|
||||
/**
|
||||
* Set a LADSPS fx instance to be used by the mixer and assign the mixer buffers
|
||||
|
@ -883,6 +971,130 @@ void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer,
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* set one or more reverb shadow parameters for one fx group.
|
||||
* These parameters will be returned if queried.
|
||||
* (see fluid_rvoice_mixer_reverb_get_param())
|
||||
*
|
||||
* @param mixer that contains all fx units.
|
||||
* @param fx_group index of the fx group to which parameters must be set.
|
||||
* must be in the range [-1..mixer->fx_units[. If -1 the changes are applied to
|
||||
* all fx units.
|
||||
* @param set Flags indicating which parameters should be set (#fluid_revmodel_set_t)
|
||||
* @param values table of parameters values.
|
||||
*/
|
||||
void
|
||||
fluid_rvoice_mixer_set_reverb_full(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int set, const double values[])
|
||||
{
|
||||
fluid_mixer_fx_t *fx = mixer->fx;
|
||||
int nr_units = mixer->fx_units;
|
||||
|
||||
if(fx_group >= 0) /* apply parameters to this fx group only */
|
||||
{
|
||||
nr_units = fx_group + 1;
|
||||
}
|
||||
else /* apply parameters to all fx groups */
|
||||
{
|
||||
fx_group = 0;
|
||||
}
|
||||
|
||||
for(; fx_group < nr_units; fx_group++)
|
||||
{
|
||||
int param;
|
||||
|
||||
for(param = 0; param < FLUID_REVERB_PARAM_LAST; param++)
|
||||
{
|
||||
if(set & FLUID_REVPARAM_TO_SETFLAG(param))
|
||||
{
|
||||
fx[fx_group].reverb_param[param] = values[param];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get one reverb shadow parameter for one fx group.
|
||||
* (see fluid_rvoice_mixer_set_reverb_full())
|
||||
*
|
||||
* @param mixer that contains all fx group units.
|
||||
* @param fx_group index of the fx group to get parameter from.
|
||||
* must be in the range [0..mixer->fx_units[.
|
||||
* @param enum indicating the parameter to get.
|
||||
* FLUID_REVERB_ROOMSIZE, reverb room size value.
|
||||
* FLUID_REVERB_DAMP, reverb damping value.
|
||||
* FLUID_REVERB_WIDTH, reverb width value.
|
||||
* FLUID_REVERB_LEVEL, reverb level value.
|
||||
* @return value.
|
||||
*/
|
||||
double
|
||||
fluid_rvoice_mixer_reverb_get_param(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int param)
|
||||
{
|
||||
return mixer->fx[fx_group].reverb_param[param];
|
||||
}
|
||||
|
||||
/**
|
||||
* set one or more chorus shadow parameters for one fx group.
|
||||
* These parameters will be returned if queried.
|
||||
* (see fluid_rvoice_mixer_chorus_get_param())
|
||||
*
|
||||
* @param mixer that contains all fx units.
|
||||
* @param fx_group index of the fx group to which parameters must be set.
|
||||
* must be in the range [-1..mixer->fx_units[. If -1 the changes are applied
|
||||
* to all fx group.
|
||||
* Keep in mind, that the needed CPU time is proportional to 'nr'.
|
||||
* @param set Flags indicating which parameters to set (#fluid_chorus_set_t)
|
||||
* @param values table of pararameters.
|
||||
*/
|
||||
void
|
||||
fluid_rvoice_mixer_set_chorus_full(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int set, const double values[])
|
||||
{
|
||||
fluid_mixer_fx_t *fx = mixer->fx;
|
||||
int nr_units = mixer->fx_units;
|
||||
|
||||
if(fx_group >= 0) /* apply parameters to this group fx only */
|
||||
{
|
||||
nr_units = fx_group + 1;
|
||||
}
|
||||
else /* apply parameters to all fx units*/
|
||||
{
|
||||
fx_group = 0;
|
||||
}
|
||||
|
||||
for(; fx_group < nr_units; fx_group++)
|
||||
{
|
||||
int param;
|
||||
|
||||
for(param = 0; param < FLUID_CHORUS_PARAM_LAST; param++)
|
||||
{
|
||||
if(set & FLUID_CHORPARAM_TO_SETFLAG(param))
|
||||
{
|
||||
fx[fx_group].chorus_param[param] = values[param];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get one chorus shadow parameter for one fx group.
|
||||
* (see fluid_rvoice_mixer_set_chorus_full())
|
||||
*
|
||||
* @param mixer that contains all fx groups units.
|
||||
* @param fx_group index of the fx group to get parameter from.
|
||||
* must be in the range [0..mixer->fx_units[.
|
||||
* @param get Flags indicating which parameter to get (#fluid_chorus_set_t)
|
||||
* @return the parameter value (0.0 is returned if error)
|
||||
*/
|
||||
double
|
||||
fluid_rvoice_mixer_chorus_get_param(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int param)
|
||||
{
|
||||
return mixer->fx[fx_group].chorus_param[param];
|
||||
}
|
||||
|
||||
/* @deprecated: use fluid_rvoice_mixer_reverb_enable instead */
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled)
|
||||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
|
@ -891,6 +1103,43 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled)
|
|||
mixer->with_reverb = on;
|
||||
}
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reverb_enable)
|
||||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
int fx_group = param[0].i; /* reverb fx group index */
|
||||
int on = param[1].i; /* on/off */
|
||||
|
||||
int nr_units = mixer->fx_units;
|
||||
|
||||
/* does on/off must be applied only to fx group at index fx_group ? */
|
||||
if(fx_group >= 0)
|
||||
{
|
||||
mixer->fx[fx_group].reverb_on = on;
|
||||
}
|
||||
/* on/off must be applied to all fx groups */
|
||||
else
|
||||
{
|
||||
for(fx_group = 0; fx_group < nr_units; fx_group++)
|
||||
{
|
||||
mixer->fx[fx_group].reverb_on = on;
|
||||
}
|
||||
}
|
||||
|
||||
/* set with_reverb if at least one reverb unit is on */
|
||||
for(fx_group = 0; fx_group < nr_units; fx_group++)
|
||||
{
|
||||
on = mixer->fx[fx_group].reverb_on;
|
||||
|
||||
if(on)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mixer->with_reverb = on;
|
||||
}
|
||||
|
||||
/* @deprecated: use fluid_rvoice_mixer_chorus_enable instead */
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled)
|
||||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
|
@ -898,6 +1147,42 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled)
|
|||
mixer->with_chorus = on;
|
||||
}
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_chorus_enable)
|
||||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
int fx_group = param[0].i; /* chorus fx group index */
|
||||
int on = param[1].i; /* on/off */
|
||||
|
||||
int nr_units = mixer->fx_units;
|
||||
|
||||
/* does on/off must be applied only to fx group at index fx_group ? */
|
||||
if(fx_group >= 0)
|
||||
{
|
||||
mixer->fx[fx_group].chorus_on = on;
|
||||
}
|
||||
/* on/off must be applied to all fx groups */
|
||||
else
|
||||
{
|
||||
for(fx_group = 0; fx_group < nr_units; fx_group++)
|
||||
{
|
||||
mixer->fx[fx_group].chorus_on = on;
|
||||
}
|
||||
}
|
||||
|
||||
/* set with_chorus if at least one chorus unit is on */
|
||||
for(fx_group = 0; fx_group < nr_units; fx_group++)
|
||||
{
|
||||
on = mixer->fx[fx_group].chorus_on;
|
||||
|
||||
if(on)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mixer->with_chorus = on;
|
||||
}
|
||||
|
||||
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on)
|
||||
{
|
||||
mixer->mix_fx_to_out = on;
|
||||
|
@ -906,33 +1191,57 @@ void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on)
|
|||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params)
|
||||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
int set = param[0].i;
|
||||
int nr = param[1].i;
|
||||
fluid_real_t level = param[2].real;
|
||||
fluid_real_t speed = param[3].real;
|
||||
fluid_real_t depth_ms = param[4].real;
|
||||
int type = param[5].i;
|
||||
int i = param[0].i;
|
||||
int set = param[1].i;
|
||||
int nr = param[2].i;
|
||||
fluid_real_t level = param[3].real;
|
||||
fluid_real_t speed = param[4].real;
|
||||
fluid_real_t depth_ms = param[5].real;
|
||||
int type = param[6].i;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < mixer->fx_units; i++)
|
||||
int nr_units = mixer->fx_units;
|
||||
|
||||
/* does parameters must be applied only to fx group i ? */
|
||||
if(i >= 0)
|
||||
{
|
||||
fluid_chorus_set(mixer->fx[i].chorus, set, nr, level, speed, depth_ms, type);
|
||||
nr_units = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0; /* parameters must be applied to all fx groups */
|
||||
}
|
||||
|
||||
while(i < nr_units)
|
||||
{
|
||||
fluid_chorus_set(mixer->fx[i++].chorus, set, nr, level, speed, depth_ms, type);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params)
|
||||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
int set = param[0].i;
|
||||
fluid_real_t roomsize = param[1].real;
|
||||
fluid_real_t damping = param[2].real;
|
||||
fluid_real_t width = param[3].real;
|
||||
fluid_real_t level = param[4].real;
|
||||
int i = param[0].i; /* fx group index */
|
||||
int set = param[1].i;
|
||||
fluid_real_t roomsize = param[2].real;
|
||||
fluid_real_t damping = param[3].real;
|
||||
fluid_real_t width = param[4].real;
|
||||
fluid_real_t level = param[5].real;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < mixer->fx_units; i++)
|
||||
int nr_units = mixer->fx_units;
|
||||
|
||||
/* does parameters change should be applied only to fx group i ? */
|
||||
if(i >= 0)
|
||||
{
|
||||
fluid_revmodel_set(mixer->fx[i].reverb, set, roomsize, damping, width, level);
|
||||
nr_units = i + 1; /* parameters change must be applied to fx groups i */
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0; /* parameters change must be applied to all fx groups */
|
||||
}
|
||||
|
||||
while(i < nr_units)
|
||||
{
|
||||
fluid_revmodel_set(mixer->fx[i++].reverb, set, roomsize, damping, width, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,6 +1249,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb)
|
|||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < mixer->fx_units; i++)
|
||||
{
|
||||
fluid_revmodel_reset(mixer->fx[i].reverb);
|
||||
|
@ -950,6 +1260,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus)
|
|||
{
|
||||
fluid_rvoice_mixer_t *mixer = obj;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < mixer->fx_units; i++)
|
||||
{
|
||||
fluid_chorus_reset(mixer->fx[i].chorus);
|
||||
|
@ -1267,27 +1578,33 @@ fluid_render_loop_multithread(fluid_rvoice_mixer_t *mixer, int current_blockcoun
|
|||
static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t *mixer)
|
||||
{
|
||||
int i;
|
||||
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++)
|
||||
// if no threads have been created yet (e.g. because a previous error prevented creation of threads
|
||||
// mutexes and condition variables), skip terminating threads
|
||||
if(mixer->thread_count != 0)
|
||||
{
|
||||
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE);
|
||||
}
|
||||
fluid_atomic_int_set(&mixer->threads_should_terminate, 1);
|
||||
// Signal threads to wake up
|
||||
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
|
||||
|
||||
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)
|
||||
for(i = 0; i < mixer->thread_count; i++)
|
||||
{
|
||||
fluid_thread_join(mixer->threads[i].thread);
|
||||
delete_fluid_thread(mixer->threads[i].thread);
|
||||
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE);
|
||||
}
|
||||
|
||||
fluid_mixer_buffers_free(&mixer->threads[i]);
|
||||
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);
|
||||
|
|
|
@ -37,16 +37,38 @@ int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer);
|
|||
int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer);
|
||||
#endif
|
||||
fluid_rvoice_mixer_t *new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units,
|
||||
fluid_real_t sample_rate, fluid_rvoice_eventhandler_t *, int, int);
|
||||
fluid_real_t sample_rate_max, fluid_real_t sample_rate,
|
||||
fluid_rvoice_eventhandler_t *, int, int);
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *);
|
||||
|
||||
void
|
||||
fluid_rvoice_mixer_set_reverb_full(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int set, const double values[]);
|
||||
|
||||
double
|
||||
fluid_rvoice_mixer_reverb_get_param(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int param);
|
||||
void
|
||||
fluid_rvoice_mixer_set_chorus_full(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int set, const double values[]);
|
||||
double
|
||||
fluid_rvoice_mixer_chorus_get_param(const fluid_rvoice_mixer_t *mixer,
|
||||
int fx_group, int param);
|
||||
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony);
|
||||
|
||||
/* @deprecated */
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled);
|
||||
/* @deprecated */
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled);
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reverb_enable);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_chorus_enable);
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params);
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t;
|
|||
|
||||
struct _fluid_samplecache_entry_t
|
||||
{
|
||||
/* The follwing members all form the cache key */
|
||||
/* The following members all form the cache key */
|
||||
char *filename;
|
||||
time_t modification_time;
|
||||
unsigned int sf_samplepos;
|
||||
|
@ -89,6 +89,7 @@ int fluid_samplecache_load(SFData *sf,
|
|||
|
||||
if(entry == NULL)
|
||||
{
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime);
|
||||
|
||||
if(entry == NULL)
|
||||
|
@ -97,8 +98,10 @@ int fluid_samplecache_load(SFData *sf,
|
|||
goto unlock_exit;
|
||||
}
|
||||
|
||||
fluid_mutex_lock(samplecache_mutex);
|
||||
samplecache_list = fluid_list_prepend(samplecache_list, entry);
|
||||
}
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
|
||||
if(try_mlock && !entry->mlocked)
|
||||
{
|
||||
|
@ -129,7 +132,6 @@ int fluid_samplecache_load(SFData *sf,
|
|||
ret = entry->sample_count;
|
||||
|
||||
unlock_exit:
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -290,3 +292,22 @@ static int fluid_get_file_modification_time(char *filename, time_t *modification
|
|||
*modification_time = buf.st_mtime;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Only used for tests */
|
||||
int fluid_samplecache_count_entries(void)
|
||||
{
|
||||
fluid_list_t *entry;
|
||||
int count = 0;
|
||||
|
||||
fluid_mutex_lock(samplecache_mutex);
|
||||
|
||||
for(entry = samplecache_list; entry != NULL; entry = fluid_list_next(entry))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -31,4 +31,7 @@ int fluid_samplecache_load(SFData *sf,
|
|||
|
||||
int fluid_samplecache_unload(const short *sample_data);
|
||||
|
||||
/* Only used for tests */
|
||||
int fluid_samplecache_count_entries(void);
|
||||
|
||||
#endif /* _FLUID_SAMPLECACHE_H */
|
||||
|
|
|
@ -252,6 +252,7 @@ delete_fluid_set_setting(fluid_setting_node_t *node)
|
|||
|
||||
/**
|
||||
* Create a new settings object
|
||||
*
|
||||
* @return the pointer to the settings object
|
||||
*/
|
||||
fluid_settings_t *
|
||||
|
@ -275,6 +276,7 @@ new_fluid_settings(void)
|
|||
|
||||
/**
|
||||
* Delete the provided settings object
|
||||
*
|
||||
* @param settings a settings object
|
||||
*/
|
||||
void
|
||||
|
@ -543,6 +545,7 @@ fluid_settings_register_str(fluid_settings_t *settings, const char *name, const
|
|||
if(node->type == FLUID_STR_TYPE)
|
||||
{
|
||||
fluid_str_setting_t *setting = &node->str;
|
||||
FLUID_FREE(setting->def);
|
||||
setting->def = def ? FLUID_STRDUP(def) : NULL;
|
||||
setting->hints = hints;
|
||||
retval = FLUID_OK;
|
||||
|
@ -790,6 +793,40 @@ int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name)
|
||||
{
|
||||
fluid_setting_node_t *node;
|
||||
void* retval = NULL;
|
||||
|
||||
fluid_return_val_if_fail(settings != NULL, NULL);
|
||||
fluid_return_val_if_fail(name != NULL, NULL);
|
||||
fluid_return_val_if_fail(name[0] != '\0', NULL);
|
||||
|
||||
fluid_rec_mutex_lock(settings->mutex);
|
||||
|
||||
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
|
||||
{
|
||||
if(node->type == FLUID_NUM_TYPE)
|
||||
{
|
||||
fluid_num_setting_t *setting = &node->num;
|
||||
retval = setting->data;
|
||||
}
|
||||
else if(node->type == FLUID_STR_TYPE)
|
||||
{
|
||||
fluid_str_setting_t *setting = &node->str;
|
||||
retval = setting->data;
|
||||
}
|
||||
else if(node->type == FLUID_INT_TYPE)
|
||||
{
|
||||
fluid_int_setting_t *setting = &node->i;
|
||||
retval = setting->data;
|
||||
}
|
||||
}
|
||||
|
||||
fluid_rec_mutex_unlock(settings->mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of the setting with the given name
|
||||
*
|
||||
|
@ -872,6 +909,10 @@ fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *hint
|
|||
* @param settings a settings object
|
||||
* @param name a setting's name
|
||||
* @return TRUE if the setting is changeable in real-time, FALSE otherwise
|
||||
*
|
||||
* @note Before using this function, make sure the @p settings object has already been used to create
|
||||
* a synthesizer, a MIDI driver, an audio driver, a MIDI player, or a command handler (depending on
|
||||
* which settings you want to query).
|
||||
*/
|
||||
int
|
||||
fluid_settings_is_realtime(fluid_settings_t *settings, const char *name)
|
||||
|
@ -980,15 +1021,17 @@ error_recovery:
|
|||
|
||||
/**
|
||||
* Copy the value of a string setting into the provided buffer (thread safe)
|
||||
*
|
||||
* @param settings a settings object
|
||||
* @param name a setting's name
|
||||
* @param str Caller supplied buffer to copy string value to
|
||||
* @param len Size of 'str' buffer (no more than len bytes will be written, which
|
||||
* will always include a zero terminator)
|
||||
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @note A size of 256 should be more than sufficient for the string buffer.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int
|
||||
fluid_settings_copystr(fluid_settings_t *settings, const char *name,
|
||||
|
@ -1040,14 +1083,16 @@ fluid_settings_copystr(fluid_settings_t *settings, const char *name,
|
|||
|
||||
/**
|
||||
* Duplicate the value of a string setting
|
||||
*
|
||||
* @param settings a settings object
|
||||
* @param name a setting's name
|
||||
* @param str Location to store pointer to allocated duplicate string
|
||||
* @return #FLUID_OK if the value exists and was successfully duplicated, #FLUID_FAILED otherwise
|
||||
* @since 1.1.0
|
||||
*
|
||||
* Like fluid_settings_copystr() but allocates a new copy of the string. Caller
|
||||
* owns the string and should free it with fluid_free() when done using it.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int
|
||||
fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str)
|
||||
|
@ -1159,19 +1204,20 @@ fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const cha
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the default value of a string setting. Note that the returned string is
|
||||
* not owned by the caller and should not be modified or freed.
|
||||
* Get the default value of a string setting.
|
||||
*
|
||||
* @param settings a settings object
|
||||
* @param name a setting's name
|
||||
* @param def the default string value of the setting if it exists
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||
* @return FLUID_OK if a default vaule exists, FLUID_FAILED otherwise
|
||||
*
|
||||
* @note The returned string is not owned by the caller and should not be modified or freed.
|
||||
*/
|
||||
int
|
||||
fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def)
|
||||
fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char const **def)
|
||||
{
|
||||
fluid_setting_node_t *node;
|
||||
char *retval = NULL;
|
||||
char const *retval = NULL;
|
||||
|
||||
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
|
||||
|
@ -1205,6 +1251,7 @@ fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char
|
|||
|
||||
/**
|
||||
* Add an option to a string setting (like an enumeration value).
|
||||
*
|
||||
* @param settings a settings object
|
||||
* @param name a setting's name
|
||||
* @param s option string to add
|
||||
|
@ -1242,6 +1289,7 @@ fluid_settings_add_option(fluid_settings_t *settings, const char *name, const ch
|
|||
|
||||
/**
|
||||
* Remove an option previously assigned by fluid_settings_add_option().
|
||||
*
|
||||
* @param settings a settings object
|
||||
* @param name a setting's name
|
||||
* @param s option string to remove
|
||||
|
@ -1567,6 +1615,7 @@ fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val)
|
|||
|
||||
/**
|
||||
* Get the range of values of an integer setting
|
||||
*
|
||||
* @param settings a settings object
|
||||
* @param name a setting's name
|
||||
* @param min setting's range lower limit
|
||||
|
@ -1692,10 +1741,12 @@ fluid_settings_foreach_option(fluid_settings_t *settings, const char *name,
|
|||
|
||||
/**
|
||||
* Count option string values for a string setting.
|
||||
*
|
||||
* @param settings a settings object
|
||||
* @param name Name of setting
|
||||
* @return Count of options for this string setting (0 if none, -1 if not found
|
||||
* or not a string setting)
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
int
|
||||
|
@ -1723,11 +1774,13 @@ fluid_settings_option_count(fluid_settings_t *settings, const char *name)
|
|||
|
||||
/**
|
||||
* Concatenate options for a string setting together with a separator between.
|
||||
*
|
||||
* @param settings Settings object
|
||||
* @param name Settings name
|
||||
* @param separator String to use between options (NULL to use ", ")
|
||||
* @return Newly allocated string or NULL on error (out of memory, not a valid
|
||||
* setting \p name or not a string setting). Free the string when finished with it by using fluid_free().
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
char *
|
||||
|
|
|
@ -52,4 +52,6 @@ int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
|
|||
|
||||
int fluid_settings_split_csv(const char *str, int *buf, int buf_len);
|
||||
|
||||
void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name);
|
||||
|
||||
#endif /* _FLUID_SETTINGS_H */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,7 +29,7 @@
|
|||
#include "fluid_list.h"
|
||||
#include "fluid_mod.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
|
||||
/* Sound Font structure defines */
|
||||
|
@ -45,10 +45,6 @@ typedef struct _SFInst SFInst;
|
|||
typedef struct _SFPreset SFPreset;
|
||||
typedef struct _SFData SFData;
|
||||
typedef struct _SFChunk SFChunk;
|
||||
typedef struct _SFPhdr SFPhdr;
|
||||
typedef struct _SFBag SFBag;
|
||||
typedef struct _SFIhdr SFIhdr;
|
||||
typedef struct _SFShdr SFShdr;
|
||||
|
||||
|
||||
struct _SFVersion
|
||||
|
@ -89,7 +85,6 @@ struct _SFGen
|
|||
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 */
|
||||
};
|
||||
|
@ -98,7 +93,7 @@ struct _SFSample
|
|||
{
|
||||
/* Sample structure */
|
||||
char name[21]; /* Name of sample */
|
||||
unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
|
||||
int idx; /* Index of this instrument in the Soundfont */
|
||||
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
|
||||
|
@ -131,9 +126,6 @@ struct _SFPreset
|
|||
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 */
|
||||
};
|
||||
|
||||
|
@ -160,6 +152,8 @@ struct _SFData
|
|||
FILE *sffd; /* loaded sfont file descriptor */
|
||||
const fluid_file_callbacks_t *fcbs; /* file callbacks used to read this file */
|
||||
|
||||
fluid_rec_mutex_t mtx; /* this mutex can be used to synchronize calls to fcbs when using multiple threads (e.g. SF3 loading) */
|
||||
|
||||
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 */
|
||||
|
@ -182,44 +176,6 @@ struct _SFChunk
|
|||
unsigned int size; /* size of the following chunk */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
struct _SFBag
|
||||
{
|
||||
unsigned short genndx; /* index into generator list */
|
||||
unsigned short modndx; /* index into modulator list */
|
||||
};
|
||||
|
||||
struct _SFIhdr
|
||||
{
|
||||
char name[20]; /* Name of instrument */
|
||||
unsigned short ibagndx; /* Instrument bag index */
|
||||
};
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
/* Public functions */
|
||||
SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs);
|
||||
void fluid_sffile_close(SFData *sf);
|
||||
|
@ -227,4 +183,12 @@ int fluid_sffile_parse_presets(SFData *sf);
|
|||
int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
|
||||
int sample_type, short **data, char **data24);
|
||||
|
||||
|
||||
/* extern only for unit test purposes */
|
||||
int load_igen(SFData *sf, int size);
|
||||
int load_pgen(SFData *sf, int size);
|
||||
void delete_preset(SFPreset *preset);
|
||||
void delete_inst(SFInst *inst);
|
||||
void delete_zone(SFZone *zone);
|
||||
|
||||
#endif /* _FLUID_SFFILE_H */
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "fluid_sys.h"
|
||||
|
||||
|
||||
void *default_fopen(const char *path)
|
||||
static void *default_fopen(const char *path)
|
||||
{
|
||||
const char* msg;
|
||||
FILE* handle = fluid_file_open(path, &msg);
|
||||
|
@ -35,23 +35,23 @@ void *default_fopen(const char *path)
|
|||
return handle;
|
||||
}
|
||||
|
||||
int default_fclose(void *handle)
|
||||
static int default_fclose(void *handle)
|
||||
{
|
||||
return FLUID_FCLOSE((FILE *)handle) == 0 ? FLUID_OK : FLUID_FAILED;
|
||||
}
|
||||
|
||||
long default_ftell(void *handle)
|
||||
static fluid_long_long_t default_ftell(void *handle)
|
||||
{
|
||||
return FLUID_FTELL((FILE *)handle);
|
||||
}
|
||||
|
||||
int safe_fread(void *buf, int count, void *fd)
|
||||
static int safe_fread(void *buf, fluid_long_long_t count, void *fd)
|
||||
{
|
||||
if(FLUID_FREAD(buf, count, 1, (FILE *)fd) != 1)
|
||||
if(FLUID_FREAD(buf, (size_t)count, 1, (FILE *)fd) != 1)
|
||||
{
|
||||
if(feof((FILE *)fd))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "EOF while attemping to read %d bytes", count);
|
||||
FLUID_LOG(FLUID_ERR, "EOF while attempting to read %lld bytes", count);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -64,11 +64,11 @@ int safe_fread(void *buf, int count, void *fd)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int safe_fseek(void *fd, long ofs, int whence)
|
||||
static int safe_fseek(void *fd, fluid_long_long_t ofs, int whence)
|
||||
{
|
||||
if(FLUID_FSEEK((FILE *)fd, ofs, whence) != 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "File seek failed with offset = %ld and whence = %d", ofs, whence);
|
||||
FLUID_LOG(FLUID_ERR, "File seek failed with offset = %lld and whence = %d", ofs, whence);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
|
@ -156,8 +156,6 @@ void *fluid_sfloader_get_data(fluid_sfloader_t *loader)
|
|||
/**
|
||||
* Set custom callbacks to be used upon soundfont loading.
|
||||
*
|
||||
* Useful for loading a soundfont from memory, see \a doc/fluidsynth_sfload_mem.c as an example.
|
||||
*
|
||||
* @param loader The SoundFont loader instance.
|
||||
* @param open A function implementing #fluid_sfloader_callback_open_t.
|
||||
* @param read A function implementing #fluid_sfloader_callback_read_t.
|
||||
|
@ -165,6 +163,9 @@ void *fluid_sfloader_get_data(fluid_sfloader_t *loader)
|
|||
* @param tell A function implementing #fluid_sfloader_callback_tell_t.
|
||||
* @param close A function implementing #fluid_sfloader_callback_close_t.
|
||||
* @return #FLUID_OK if the callbacks have been successfully set, #FLUID_FAILED otherwise.
|
||||
*
|
||||
* Useful for loading a soundfont from memory, see \a doc/fluidsynth_sfload_mem.c as an example.
|
||||
*
|
||||
*/
|
||||
int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
|
||||
fluid_sfloader_callback_open_t open,
|
||||
|
@ -196,6 +197,7 @@ int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
|
|||
|
||||
/**
|
||||
* Creates a new virtual SoundFont instance structure.
|
||||
*
|
||||
* @param get_name A function implementing #fluid_sfont_get_name_t.
|
||||
* @param get_preset A function implementing #fluid_sfont_get_preset_t.
|
||||
* @param iter_start A function implementing #fluid_sfont_iteration_start_t, or NULL if preset iteration not needed.
|
||||
|
@ -285,8 +287,8 @@ const char *fluid_sfont_get_name(fluid_sfont_t *sfont)
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the preset assigned the a SoundFont instance
|
||||
* for the given bank and preset number.
|
||||
* Retrieve the preset assigned the a SoundFont instance for the given bank and preset number.
|
||||
*
|
||||
* @param sfont The SoundFont instance.
|
||||
* @param bank bank number of the preset
|
||||
* @param prenum program number of the preset
|
||||
|
@ -300,6 +302,7 @@ fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenu
|
|||
|
||||
/**
|
||||
* Starts / re-starts virtual preset iteration in a SoundFont.
|
||||
*
|
||||
* @param sfont Virtual SoundFont instance
|
||||
*/
|
||||
void fluid_sfont_iteration_start(fluid_sfont_t *sfont)
|
||||
|
@ -329,10 +332,11 @@ fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont)
|
|||
/**
|
||||
* Destroys a SoundFont instance created with new_fluid_sfont().
|
||||
*
|
||||
* Implements #fluid_sfont_free_t.
|
||||
*
|
||||
* @param sfont The SoundFont instance to destroy.
|
||||
* @return Always returns 0.
|
||||
*
|
||||
* Implements #fluid_sfont_free_t.
|
||||
*
|
||||
*/
|
||||
int delete_fluid_sfont(fluid_sfont_t *sfont)
|
||||
{
|
||||
|
@ -467,9 +471,10 @@ fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset)
|
|||
/**
|
||||
* Destroys a SoundFont preset instance created with new_fluid_preset().
|
||||
*
|
||||
* @param preset The SoundFont preset instance to destroy.
|
||||
*
|
||||
* Implements #fluid_preset_free_t.
|
||||
*
|
||||
* @param preset The SoundFont preset instance to destroy.
|
||||
*/
|
||||
void delete_fluid_preset(fluid_preset_t *preset)
|
||||
{
|
||||
|
@ -480,6 +485,7 @@ void delete_fluid_preset(fluid_preset_t *preset)
|
|||
|
||||
/**
|
||||
* Create a new sample instance.
|
||||
*
|
||||
* @return The sample on success, NULL otherwise.
|
||||
*/
|
||||
fluid_sample_t *
|
||||
|
@ -502,6 +508,7 @@ new_fluid_sample()
|
|||
|
||||
/**
|
||||
* Destroy a sample instance previously created with new_fluid_sample().
|
||||
*
|
||||
* @param sample The sample to destroy.
|
||||
*/
|
||||
void
|
||||
|
@ -521,10 +528,10 @@ delete_fluid_sample(fluid_sample_t *sample)
|
|||
/**
|
||||
* Returns the size of the fluid_sample_t structure.
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a pool of samples.
|
||||
*
|
||||
* @return Size of fluid_sample_t in bytes
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a pool of samples.
|
||||
*
|
||||
* @note It is recommend to zero initialize the memory before using the object.
|
||||
*
|
||||
* @warning Do NOT allocate samples on the stack and assign them to a voice!
|
||||
|
@ -536,6 +543,7 @@ size_t fluid_sample_sizeof()
|
|||
|
||||
/**
|
||||
* Set the name of a SoundFont sample.
|
||||
*
|
||||
* @param sample SoundFont sample
|
||||
* @param name Name to assign to sample (20 chars in length + zero terminator)
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
|
@ -551,6 +559,7 @@ int fluid_sample_set_name(fluid_sample_t *sample, const char *name)
|
|||
|
||||
/**
|
||||
* Assign sample data to a SoundFont sample.
|
||||
*
|
||||
* @param sample SoundFont sample
|
||||
* @param data Buffer containing 16 bit (mono-)audio sample data
|
||||
* @param data24 If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples
|
||||
|
@ -700,6 +709,9 @@ int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune)
|
|||
*/
|
||||
int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size)
|
||||
{
|
||||
#define EXCLUSIVE_FLAGS (FLUID_SAMPLETYPE_MONO | FLUID_SAMPLETYPE_RIGHT | FLUID_SAMPLETYPE_LEFT)
|
||||
static const unsigned int supported_flags = EXCLUSIVE_FLAGS | FLUID_SAMPLETYPE_LINKED | FLUID_SAMPLETYPE_OGG_VORBIS | FLUID_SAMPLETYPE_ROM;
|
||||
|
||||
/* ROM samples are unusable for us by definition */
|
||||
if(sample->sampletype & FLUID_SAMPLETYPE_ROM)
|
||||
{
|
||||
|
@ -707,6 +719,28 @@ int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size)
|
|||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if(sample->sampletype & ~supported_flags)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Sample '%s' has unknown flags, possibly using an unsupported compression; sample ignored", sample->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if((sample->sampletype & EXCLUSIVE_FLAGS) & ((sample->sampletype & EXCLUSIVE_FLAGS) - 1))
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO, "Sample '%s' should be either mono or left or right; using it anyway", sample->name);
|
||||
}
|
||||
|
||||
if((sample->sampletype & FLUID_SAMPLETYPE_LINKED) && (sample->sampletype & EXCLUSIVE_FLAGS))
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO, "Linked sample '%s' should not be mono, left or right at the same time; using it anyway", sample->name);
|
||||
}
|
||||
|
||||
if((sample->sampletype & EXCLUSIVE_FLAGS) == 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_INFO, "Sample '%s' has no flags set, assuming mono", sample->name);
|
||||
sample->sampletype = FLUID_SAMPLETYPE_MONO;
|
||||
}
|
||||
|
||||
/* Ogg vorbis compressed samples in the SF3 format use byte indices for
|
||||
* sample start and end pointers before decompression. Standard SF2 samples
|
||||
* use sample word indices for all pointers, so use half the buffer_size
|
||||
|
@ -729,6 +763,7 @@ int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size)
|
|||
}
|
||||
|
||||
return FLUID_OK;
|
||||
#undef EXCLUSIVE_FLAGS
|
||||
}
|
||||
|
||||
/* Check the sample loop pointers and optionally convert them to something
|
||||
|
|
|
@ -45,7 +45,7 @@ int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int max_end);
|
|||
(*(_preset)->noteon)(_preset,_synth,_ch,_key,_vel)
|
||||
|
||||
#define fluid_preset_notify(_preset,_reason,_chan) \
|
||||
{ if ((_preset) && (_preset)->notify) { (*(_preset)->notify)(_preset,_reason,_chan); }}
|
||||
( ((_preset) && (_preset)->notify) ? (*(_preset)->notify)(_preset,_reason,_chan) : FLUID_OK )
|
||||
|
||||
|
||||
#define fluid_sample_incr_ref(_sample) { (_sample)->refcount++; }
|
||||
|
@ -147,7 +147,7 @@ struct _fluid_sample_t
|
|||
{
|
||||
char name[21]; /**< Sample name */
|
||||
|
||||
/* The following for sample pointers store the original pointers from the Soundfont
|
||||
/* The following four sample pointers store the original pointers from the Soundfont
|
||||
* file. They are never changed after loading and are used to re-create the
|
||||
* actual sample pointers after a sample has been unloaded and loaded again. The
|
||||
* actual sample pointers get modified during loading for SF3 (compressed) samples
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -125,6 +125,7 @@ struct _fluid_synth_t
|
|||
fluid_list_t *loaders; /**< the SoundFont loaders */
|
||||
fluid_list_t *sfont; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
|
||||
int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
|
||||
fluid_list_t *fonts_to_be_unloaded; /**< list of timers that try to unload a soundfont */
|
||||
|
||||
float gain; /**< master gain */
|
||||
fluid_channel_t **channel; /**< the channels */
|
||||
|
@ -136,16 +137,11 @@ struct _fluid_synth_t
|
|||
int fromkey_portamento; /**< fromkey portamento */
|
||||
fluid_rvoice_eventhandler_t *eventhandler;
|
||||
|
||||
double reverb_roomsize; /**< Shadow of reverb roomsize */
|
||||
double reverb_damping; /**< Shadow of reverb damping */
|
||||
double reverb_width; /**< Shadow of reverb width */
|
||||
double reverb_level; /**< Shadow of reverb level */
|
||||
/**< Shadow of reverb parameter: roomsize, damping, width, level */
|
||||
double reverb_param[FLUID_REVERB_PARAM_LAST];
|
||||
|
||||
int chorus_nr; /**< Shadow of chorus number */
|
||||
double chorus_level; /**< Shadow of chorus level */
|
||||
double chorus_speed; /**< Shadow of chorus speed */
|
||||
double chorus_depth; /**< Shadow of chorus depth */
|
||||
int chorus_type; /**< Shadow of chorus type */
|
||||
/**< Shadow of chorus parameter: chorus number, level, speed, depth, type */
|
||||
double chorus_param[FLUID_CHORUS_PARAM_LAST];
|
||||
|
||||
int cur; /**< the current sample in the audio buffers to be output */
|
||||
int curmax; /**< current amount of samples present in the audio buffers */
|
||||
|
@ -185,6 +181,29 @@ typedef int (*fluid_audio_callback_t)(fluid_synth_t *synth, int len,
|
|||
void *out1, int loff, int lincr,
|
||||
void *out2, int roff, int rincr);
|
||||
|
||||
typedef int (*fluid_audio_channels_callback_t)(fluid_synth_t *synth, int len,
|
||||
int channels_count,
|
||||
void *channels_out[], int channels_off[],
|
||||
int channels_incr[]);
|
||||
|
||||
int
|
||||
fluid_synth_write_float_channels_LOCAL(fluid_synth_t *synth, int len,
|
||||
int channels_count,
|
||||
void *channels_out[], int channels_off[],
|
||||
int channels_incr[],
|
||||
int (*block_render_func)(fluid_synth_t *, int));
|
||||
|
||||
int
|
||||
fluid_synth_write_s16_channels(fluid_synth_t *synth, int len,
|
||||
int channels_count,
|
||||
void *channels_out[], int channels_off[],
|
||||
int channels_incr[]);
|
||||
int
|
||||
fluid_synth_write_float_channels(fluid_synth_t *synth, int len,
|
||||
int channels_count,
|
||||
void *channels_out[], int channels_off[],
|
||||
int channels_incr[]);
|
||||
|
||||
fluid_preset_t *fluid_synth_find_preset(fluid_synth_t *synth,
|
||||
int banknum,
|
||||
int prognum);
|
||||
|
@ -196,12 +215,17 @@ void fluid_synth_dither_s16(int *dither_index, int len, const float *lin, const
|
|||
|
||||
int fluid_synth_reset_reverb(fluid_synth_t *synth);
|
||||
int fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned 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_reverb_set_param(fluid_synth_t *synth, int fx_group,
|
||||
int param,
|
||||
double value);
|
||||
int fluid_synth_set_reverb_full(fluid_synth_t *synth, int fx_group, int set,
|
||||
const double values[]);
|
||||
|
||||
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);
|
||||
int fluid_synth_chorus_set_param(fluid_synth_t *synth, int fx_group,
|
||||
int param, double value);
|
||||
int fluid_synth_set_chorus_full(fluid_synth_t *synth, int fx_group, int set,
|
||||
const double values[]);
|
||||
|
||||
fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data);
|
||||
void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer);
|
||||
|
@ -215,16 +239,17 @@ int fluid_synth_set_gen2(fluid_synth_t *synth, int chan,
|
|||
|
||||
int
|
||||
fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[],
|
||||
int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int));
|
||||
int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int));
|
||||
int
|
||||
fluid_synth_write_float_LOCAL(fluid_synth_t *synth, int len,
|
||||
void *lout, int loff, int lincr,
|
||||
void *rout, int roff, int rincr,
|
||||
int (*block_render_func)(fluid_synth_t *, int));
|
||||
void *lout, int loff, int lincr,
|
||||
void *rout, int roff, int rincr,
|
||||
int (*block_render_func)(fluid_synth_t *, int));
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
void fluid_synth_settings(fluid_settings_t *settings);
|
||||
void fluid_synth_set_sample_rate_immediately(fluid_synth_t *synth, float sample_rate);
|
||||
|
||||
|
||||
/* extern declared in fluid_synth_monopoly.c */
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
note 'tokey'. Portamento fromkey note choice is determined at noteOn by
|
||||
fluid_synth_get_fromkey_portamento_legato() (see below).
|
||||
|
||||
More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
@ -95,7 +95,7 @@
|
|||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* fluid_synth_get_fromkey_portamento_legato returns two informations:
|
||||
* fluid_synth_get_fromkey_portamento_legato returns two information:
|
||||
* - fromkey note for portamento.
|
||||
* - fromkey note for legato.
|
||||
* +-----> fromkey_portamento
|
||||
|
@ -120,7 +120,7 @@
|
|||
* - default_fromkey if valid
|
||||
* - otherwise prev_note(prev_note is the note prior the most recent
|
||||
* note played).
|
||||
* Then portamento mode is applied to validate the value choosen.
|
||||
* Then portamento mode is applied to validate the value chosen.
|
||||
* Where portamento mode is:
|
||||
* - each note, a portamento occurs on each note.
|
||||
* - legato only, portamento only on notes played legato.
|
||||
|
@ -143,7 +143,7 @@
|
|||
*
|
||||
* On input
|
||||
* @param chan fluid_channel_t.
|
||||
* @param defaultFromkey, the defaut 'fromkey portamento' note or 'fromkey legato'
|
||||
* @param defaultFromkey, the default 'fromkey portamento' note or 'fromkey legato'
|
||||
* note (see description above).
|
||||
*
|
||||
* @return
|
||||
|
@ -254,7 +254,7 @@ static char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t *chan,
|
|||
* polyphonic mode and legato pedal is On during the playing.
|
||||
* When a channel is in "monophonic playing" state, only one note at a time can be
|
||||
* played in a staccato or legato manner (with or without portamento).
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
* More information in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
* _______________
|
||||
* ________________ | noteon |
|
||||
* | legato detector| O-->| mono_staccato |--*-> preset_noteon
|
||||
|
@ -521,7 +521,7 @@ fluid_synth_noteon_mono_staccato(fluid_synth_t *synth, int chan, int key, int ve
|
|||
*
|
||||
* The function has the same behaviour when the noteoff is poly of mono, except
|
||||
* that for mono noteoff, if any pedal (sustain or sostenuto ) is depressed, the
|
||||
* key is memorized. This is neccessary when the next mono note will be played
|
||||
* key is memorized. This is necessary when the next mono note will be played
|
||||
* staccato, as any current mono note currently sustained will need to be released
|
||||
* (see fluid_synth_noteon_mono_staccato()).
|
||||
* Note also that for a monophonic legato passage, the function is called only when
|
||||
|
@ -647,7 +647,7 @@ int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key,
|
|||
* When key tokey is outside the current Instrument Zone, Preset Zone,
|
||||
* current 'fromkey' voices are released. If necessary new voices
|
||||
* are restarted when tokey enters inside new Instrument(s) Zones,Preset Zone(s).
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4.7 (Appendices).
|
||||
* More information in FluidPolyMono-0004.pdf chapter 4.7 (Appendices).
|
||||
*/
|
||||
int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan,
|
||||
int fromkey, int tokey, int vel)
|
||||
|
|
|
@ -60,6 +60,10 @@ typedef struct
|
|||
struct _fluid_timer_t
|
||||
{
|
||||
long msec;
|
||||
|
||||
// Pointer to a function to be executed by the timer.
|
||||
// This field is set to NULL once the timer is finished to indicate completion.
|
||||
// This allows for timed waits, rather than waiting forever as fluid_timer_join() does.
|
||||
fluid_timer_callback_t callback;
|
||||
void *data;
|
||||
fluid_thread_t *thread;
|
||||
|
@ -85,7 +89,11 @@ static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] =
|
|||
fluid_default_log_function,
|
||||
fluid_default_log_function,
|
||||
fluid_default_log_function,
|
||||
#ifdef DEBUG
|
||||
fluid_default_log_function
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
};
|
||||
static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL };
|
||||
|
||||
|
@ -149,9 +157,7 @@ fluid_default_log_function(int level, const char *message, void *data)
|
|||
break;
|
||||
|
||||
case FLUID_DBG:
|
||||
#if DEBUG
|
||||
FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -216,9 +222,73 @@ void* fluid_alloc(size_t len)
|
|||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper for free() that satisfies at least C90 requirements.
|
||||
* Especially useful when using fluidsynth with programming languages that do not provide malloc() and free().
|
||||
* @note Only use this function when the API documentation explicitly says so. Otherwise use adequate \c delete_fluid_* functions.
|
||||
* Open a file with a UTF-8 string, even in Windows
|
||||
* @param filename The name of the file to open
|
||||
* @param mode The mode to open the file in
|
||||
*/
|
||||
FILE *fluid_fopen(const char *filename, const char *mode)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
wchar_t *wpath = NULL, *wmode = NULL;
|
||||
FILE *file = NULL;
|
||||
int length;
|
||||
if ((length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, NULL, 0)) == 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Unable to perform MultiByteToWideChar() conversion for filename '%s'. Error was: '%s'", filename, fluid_get_windows_error());
|
||||
errno = EINVAL;
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
wpath = FLUID_MALLOC(length * sizeof(wchar_t));
|
||||
if (wpath == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory.");
|
||||
errno = EINVAL;
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, wpath, length);
|
||||
|
||||
if ((length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, NULL, 0)) == 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Unable to perform MultiByteToWideChar() conversion for mode '%s'. Error was: '%s'", mode, fluid_get_windows_error());
|
||||
errno = EINVAL;
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
wmode = FLUID_MALLOC(length * sizeof(wchar_t));
|
||||
if (wmode == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory.");
|
||||
errno = EINVAL;
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, wmode, length);
|
||||
|
||||
file = _wfopen(wpath, wmode);
|
||||
|
||||
error_recovery:
|
||||
FLUID_FREE(wpath);
|
||||
FLUID_FREE(wmode);
|
||||
|
||||
return file;
|
||||
#else
|
||||
return fopen(filename, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for free() that satisfies at least C90 requirements.
|
||||
*
|
||||
* @param ptr Pointer to memory region that should be freed
|
||||
*
|
||||
* @note Only use this function when the API documentation explicitly says so. Otherwise use
|
||||
* adequate \c delete_fluid_* functions.
|
||||
*
|
||||
* @warning Calling ::free() on memory that is advised to be freed with fluid_free() results in undefined behaviour!
|
||||
* (cf.: "Potential Errors Passing CRT Objects Across DLL Boundaries" found in MS Docs)
|
||||
*
|
||||
* @since 2.0.7
|
||||
*/
|
||||
void fluid_free(void* ptr)
|
||||
|
@ -234,7 +304,7 @@ void fluid_free(void* ptr)
|
|||
* @internal
|
||||
* @param str Pointer to a string pointer of source to tokenize. Pointer gets
|
||||
* updated on each invocation to point to beginning of next token. Note that
|
||||
* token char get's overwritten with a 0 byte. String pointer is set to NULL
|
||||
* token char gets overwritten with a 0 byte. String pointer is set to NULL
|
||||
* when final token is returned.
|
||||
* @param delim String of delimiter chars.
|
||||
* @return Pointer to the next token or NULL if no more tokens.
|
||||
|
@ -441,7 +511,7 @@ fluid_thread_self_set_prio(int prio_level)
|
|||
* Floating point exceptions
|
||||
*
|
||||
* The floating point exception functions were taken from Ircam's
|
||||
* jMax source code. http://www.ircam.fr/jmax
|
||||
* jMax source code. https://www.ircam.fr/jmax
|
||||
*
|
||||
* FIXME: check in config for i386 machine
|
||||
*
|
||||
|
@ -514,7 +584,7 @@ void fluid_clear_fpe_i386(void)
|
|||
*/
|
||||
|
||||
#if WITH_PROFILING
|
||||
/* Profiling interface beetween profiling command shell and audio rendering API
|
||||
/* Profiling interface between profiling command shell and audio rendering API
|
||||
(FluidProfile_0004.pdf- 3.2.2).
|
||||
Macros are in defined in fluid_sys.h.
|
||||
*/
|
||||
|
@ -693,8 +763,8 @@ static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out)
|
|||
* @param sample_rate the sample rate of audio output.
|
||||
* @param out output stream device.
|
||||
*
|
||||
* When print mode is 1, the function prints all the informations (see below).
|
||||
* When print mode is 0, the fonction prints only the cpu loads.
|
||||
* When print mode is 1, the function prints all the information (see below).
|
||||
* When print mode is 0, the function prints only the cpu loads.
|
||||
*
|
||||
* ------------------------------------------------------------------------------
|
||||
* Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond)
|
||||
|
@ -975,7 +1045,7 @@ new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int pri
|
|||
#if OLD_GLIB_THREAD_API
|
||||
|
||||
/* Make sure g_thread_init has been called.
|
||||
* FIXME - Probably not a good idea in a shared library,
|
||||
* Probably not a good idea in a shared library,
|
||||
* but what can we do *and* remain backwards compatible? */
|
||||
if(!g_thread_supported())
|
||||
{
|
||||
|
@ -1095,6 +1165,7 @@ fluid_timer_run(void *data)
|
|||
}
|
||||
|
||||
FLUID_LOG(FLUID_DBG, "Timer thread finished");
|
||||
timer->callback = NULL;
|
||||
|
||||
if(timer->auto_destroy)
|
||||
{
|
||||
|
@ -1188,6 +1259,19 @@ fluid_timer_join(fluid_timer_t *timer)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int
|
||||
fluid_timer_is_running(const fluid_timer_t *timer)
|
||||
{
|
||||
// for unit test usage only
|
||||
return timer->callback != NULL;
|
||||
}
|
||||
|
||||
long fluid_timer_get_interval(const fluid_timer_t * timer)
|
||||
{
|
||||
// for unit test usage only
|
||||
return timer->msec;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
|
@ -1199,7 +1283,7 @@ fluid_timer_join(fluid_timer_t *timer)
|
|||
* Get standard in stream handle.
|
||||
* @return Standard in stream.
|
||||
*/
|
||||
fluid_istream_t
|
||||
static fluid_istream_t
|
||||
fluid_get_stdin(void)
|
||||
{
|
||||
return STDIN_FILENO;
|
||||
|
@ -1209,7 +1293,7 @@ fluid_get_stdin(void)
|
|||
* Get standard output stream handle.
|
||||
* @return Standard out stream.
|
||||
*/
|
||||
fluid_ostream_t
|
||||
static fluid_ostream_t
|
||||
fluid_get_stdout(void)
|
||||
{
|
||||
return STDOUT_FILENO;
|
||||
|
@ -1669,3 +1753,50 @@ FILE* fluid_file_open(const char* path, const char** errMsg)
|
|||
|
||||
return handle;
|
||||
}
|
||||
|
||||
fluid_long_long_t fluid_file_tell(FILE* f)
|
||||
{
|
||||
#ifdef WIN32
|
||||
// On Windows, long is only a 32 bit integer. Thus ftell() does not support to handle files >2GiB.
|
||||
// We should use _ftelli64() in this case, however its availability depends on MS CRT and might not be
|
||||
// availble on WindowsXP, Win98, etc.
|
||||
//
|
||||
// The web recommends to fallback to _telli64() in this case. However, it's return value differs from
|
||||
// _ftelli64() on Win10: https://github.com/FluidSynth/fluidsynth/pull/629#issuecomment-602238436
|
||||
//
|
||||
// Thus, we use fgetpos().
|
||||
fpos_t pos;
|
||||
if(fgetpos(f, &pos) != 0)
|
||||
{
|
||||
return (fluid_long_long_t)-1L;
|
||||
}
|
||||
return pos;
|
||||
#else
|
||||
return ftell(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
// not thread-safe!
|
||||
char* fluid_get_windows_error(void)
|
||||
{
|
||||
static TCHAR err[1024];
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
err,
|
||||
sizeof(err)/sizeof(err[0]),
|
||||
NULL);
|
||||
|
||||
#ifdef _UNICODE
|
||||
static char ascii_err[sizeof(err)];
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0, err, -1, ascii_err, sizeof(ascii_err)/sizeof(ascii_err[0]), 0, 0);
|
||||
return ascii_err;
|
||||
#else
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -168,9 +168,14 @@ typedef gintptr intptr_t;
|
|||
*/
|
||||
#define fluid_gerror_message(err) ((err) ? err->message : "No error details")
|
||||
|
||||
#ifdef WIN32
|
||||
char* fluid_get_windows_error(void);
|
||||
#endif
|
||||
|
||||
#define FLUID_INLINE inline
|
||||
|
||||
#define FLUID_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
|
||||
|
||||
/* Integer<->pointer conversion */
|
||||
#define FLUID_POINTER_TO_UINT(x) ((unsigned int)(uintptr_t)(x))
|
||||
#define FLUID_UINT_TO_POINTER(x) ((void *)(uintptr_t)(x))
|
||||
|
@ -231,10 +236,12 @@ fluid_timer_t *new_fluid_timer(int msec, fluid_timer_callback_t callback,
|
|||
void delete_fluid_timer(fluid_timer_t *timer);
|
||||
int fluid_timer_join(fluid_timer_t *timer);
|
||||
int fluid_timer_stop(fluid_timer_t *timer);
|
||||
int fluid_timer_is_running(const fluid_timer_t *timer);
|
||||
long fluid_timer_get_interval(const 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))
|
||||
#define NEW_GLIB_THREAD_API GLIB_CHECK_VERSION(2,32,0)
|
||||
#define OLD_GLIB_THREAD_API !GLIB_CHECK_VERSION(2,32,0)
|
||||
|
||||
/* Muteces */
|
||||
|
||||
|
@ -403,19 +410,19 @@ typedef GStaticPrivate fluid_private_t;
|
|||
g_atomic_pointer_compare_and_exchange(_pp, _old, _new)
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_atomic_float_set(volatile float *fptr, float val)
|
||||
fluid_atomic_float_set(fluid_atomic_float_t *fptr, float val)
|
||||
{
|
||||
int32_t ival;
|
||||
memcpy(&ival, &val, 4);
|
||||
fluid_atomic_int_set((volatile int *)fptr, ival);
|
||||
fluid_atomic_int_set((fluid_atomic_int_t *)fptr, ival);
|
||||
}
|
||||
|
||||
static FLUID_INLINE float
|
||||
fluid_atomic_float_get(volatile float *fptr)
|
||||
fluid_atomic_float_get(fluid_atomic_float_t *fptr)
|
||||
{
|
||||
int32_t ival;
|
||||
float fval;
|
||||
ival = fluid_atomic_int_get((volatile int *)fptr);
|
||||
ival = fluid_atomic_int_get((fluid_atomic_int_t *)fptr);
|
||||
memcpy(&fval, &ival, 4);
|
||||
return fval;
|
||||
}
|
||||
|
@ -465,7 +472,7 @@ typedef SOCKET fluid_socket_t;
|
|||
typedef int fluid_socket_t;
|
||||
#endif
|
||||
|
||||
/* The function should return 0 if no error occured, non-zero
|
||||
/* The function should return 0 if no error occurred, 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);
|
||||
|
@ -498,10 +505,12 @@ typedef GStatBuf fluid_stat_buf_t;
|
|||
#endif
|
||||
|
||||
FILE* fluid_file_open(const char* filename, const char** errMsg);
|
||||
fluid_long_long_t fluid_file_tell(FILE* f);
|
||||
|
||||
|
||||
/* Profiling */
|
||||
#if WITH_PROFILING
|
||||
/** profiling interface beetween Profiling command shell and Audio
|
||||
/** profiling interface between Profiling command shell and Audio
|
||||
rendering API (FluidProfile_0004.pdf- 3.2.2)
|
||||
*/
|
||||
|
||||
|
@ -734,7 +743,7 @@ void fluid_msleep(unsigned int msecs);
|
|||
* Make sure you've allocated an extra of \c alignment bytes to avoid a buffer overflow.
|
||||
*
|
||||
* @note \c alignment must be a power of two
|
||||
* @return Returned pointer is guarenteed to be aligned to \c alignment boundary and in range \f[ ptr <= returned_ptr < ptr + alignment \f].
|
||||
* @return Returned pointer is guaranteed to be aligned to \c alignment boundary and in range \f[ ptr <= returned_ptr < ptr + alignment \f].
|
||||
*/
|
||||
static FLUID_INLINE void *fluid_align_ptr(const void *ptr, unsigned int alignment)
|
||||
{
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
|
||||
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
|
||||
https://www.midi.org/about-midi/tuning.htm
|
||||
https://www.midi.org/about-midi/tuning-scale.htm
|
||||
https://www.midi.org/about-midi/tuning_extens.htm
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ static void fluid_voice_swap_rvoice(fluid_voice_t *voice)
|
|||
voice->can_access_rvoice = voice->can_access_overflow_rvoice;
|
||||
voice->overflow_rvoice = rtemp;
|
||||
voice->can_access_overflow_rvoice = ctemp;
|
||||
voice->overflow_sample = voice->sample;
|
||||
}
|
||||
|
||||
static void fluid_voice_initialize_rvoice(fluid_voice_t *voice, fluid_real_t output_rate)
|
||||
|
@ -242,6 +243,7 @@ new_fluid_voice(fluid_rvoice_eventhandler_t *handler, fluid_real_t output_rate)
|
|||
voice->eventhandler = handler;
|
||||
voice->channel = NULL;
|
||||
voice->sample = NULL;
|
||||
voice->overflow_sample = NULL;
|
||||
voice->output_rate = output_rate;
|
||||
|
||||
/* Initialize both the rvoice and overflow_rvoice */
|
||||
|
@ -321,12 +323,13 @@ fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
|
|||
voice->has_noteoff = 0;
|
||||
UPDATE_RVOICE0(fluid_rvoice_reset);
|
||||
|
||||
/* Increment the reference count of the sample to prevent the
|
||||
unloading of the soundfont while this voice is playing,
|
||||
once for us and once for the rvoice. */
|
||||
/*
|
||||
We increment the reference count of the sample to indicate that this
|
||||
sample is about to be owned by the rvoice. This will prevent the
|
||||
unloading of the soundfont while this rvoice is playing.
|
||||
*/
|
||||
fluid_sample_incr_ref(sample);
|
||||
fluid_rvoice_eventhandler_push_ptr(voice->eventhandler, fluid_rvoice_set_sample, voice->rvoice, sample);
|
||||
fluid_sample_incr_ref(sample);
|
||||
voice->sample = sample;
|
||||
|
||||
i = fluid_channel_get_interp_method(channel);
|
||||
|
@ -367,6 +370,7 @@ fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
|
|||
|
||||
/**
|
||||
* Update sample rate.
|
||||
*
|
||||
* @note If the voice is active, it will be turned off.
|
||||
*/
|
||||
void
|
||||
|
@ -385,6 +389,7 @@ fluid_voice_set_output_rate(fluid_voice_t *voice, fluid_real_t value)
|
|||
|
||||
/**
|
||||
* Set the value of a generator.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @param i Generator ID (#fluid_gen_type)
|
||||
* @param val Generator value
|
||||
|
@ -403,6 +408,7 @@ fluid_voice_gen_set(fluid_voice_t *voice, int i, float val)
|
|||
|
||||
/**
|
||||
* Offset the value of a generator.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @param i Generator ID (#fluid_gen_type)
|
||||
* @param val Value to add to the existing value
|
||||
|
@ -416,6 +422,7 @@ fluid_voice_gen_incr(fluid_voice_t *voice, int i, float val)
|
|||
|
||||
/**
|
||||
* Get the value of a generator.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @param gen Generator ID (#fluid_gen_type)
|
||||
* @return Current generator value
|
||||
|
@ -473,7 +480,7 @@ fluid_voice_calculate_gain_amplitude(const fluid_voice_t *voice, fluid_real_t ga
|
|||
This is useful to set the value of GEN_PITCH generator on noteOn.
|
||||
This is useful to get the beginning/ending pitch for portamento.
|
||||
*/
|
||||
fluid_real_t fluid_voice_calculate_pitch(fluid_voice_t *voice, int key)
|
||||
static fluid_real_t fluid_voice_calculate_pitch(fluid_voice_t *voice, int key)
|
||||
{
|
||||
fluid_tuning_t *tuning;
|
||||
fluid_real_t x, pitch;
|
||||
|
@ -734,13 +741,14 @@ calculate_hold_decay_buffers(fluid_voice_t *voice, int gen_base,
|
|||
* NRPN system. fluid_voice_gen_value(voice, generator_enumerator) returns the sum
|
||||
* of all three.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update all the synthesis parameters, which depend on generator \a gen.
|
||||
* Update all the synthesis parameters which depend on generator \a gen.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @param gen Generator id (#fluid_gen_type)
|
||||
*
|
||||
* This is only necessary after changing a generator of an already operating voice.
|
||||
* Most applications will not need this function.
|
||||
* Calling this function is only necessary after changing a generator of an already playing voice.
|
||||
*/
|
||||
void
|
||||
fluid_voice_update_param(fluid_voice_t *voice, int gen)
|
||||
|
@ -1140,8 +1148,9 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
|
|||
|
||||
/**
|
||||
* Recalculate voice parameters for a given control.
|
||||
*
|
||||
* @param voice the synthesis voice
|
||||
* @param cc flag to distinguish between a continous control and a channel control (pitch bend, ...)
|
||||
* @param cc flag to distinguish between a continuous control and a channel control (pitch bend, ...)
|
||||
* @param ctrl the control number:
|
||||
* when >=0, only modulators's destination having ctrl as source are updated.
|
||||
* when -1, all modulators's destination are updated (regardless of ctrl).
|
||||
|
@ -1236,17 +1245,18 @@ int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
|
|||
}
|
||||
|
||||
/**
|
||||
* Update all the modulators. This function is called after a
|
||||
* ALL_CTRL_OFF MIDI message has been received (CC 121).
|
||||
* Update all the modulators.
|
||||
*
|
||||
* All destination of all modulators must be updated.
|
||||
* This function is called after a ALL_CTRL_OFF MIDI message has been received (CC 121).
|
||||
* All destinations of all modulators will be updated.
|
||||
*/
|
||||
int fluid_voice_modulate_all(fluid_voice_t *voice)
|
||||
{
|
||||
return fluid_voice_modulate(voice, 0, -1);
|
||||
}
|
||||
|
||||
/** legato update functions --------------------------------------------------*/
|
||||
/* legato update functions --------------------------------------------------*/
|
||||
|
||||
/* Updates voice portamento parameters
|
||||
*
|
||||
* @voice voice the synthesis voice
|
||||
|
@ -1324,7 +1334,7 @@ fluid_voice_release(fluid_voice_t *voice)
|
|||
{
|
||||
unsigned int at_tick = fluid_channel_get_min_note_length_ticks(voice->channel);
|
||||
UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick);
|
||||
voice->has_noteoff = 1; // voice is marked as noteoff occured
|
||||
voice->has_noteoff = 1; // voice is marked as noteoff occurred
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1406,12 +1416,20 @@ fluid_voice_kill_excl(fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/*
|
||||
* Called by fluid_synth when the overflow rvoice can be reclaimed.
|
||||
* Unlock the overflow rvoice of the voice.
|
||||
* Decrement the reference count of the sample owned by this rvoice.
|
||||
*
|
||||
* Called by fluid_synth when the overflow rvoice has finished by itself.
|
||||
* Must be called also explicitly at synth destruction to ensure that
|
||||
* the soundfont be unloaded successfully.
|
||||
*/
|
||||
void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice)
|
||||
{
|
||||
voice->can_access_overflow_rvoice = 1;
|
||||
fluid_voice_sample_unref(&voice->overflow_rvoice->dsp.sample);
|
||||
|
||||
/* Decrement the reference count of the sample to indicate
|
||||
that this sample isn't owned by the rvoice anymore */
|
||||
fluid_voice_sample_unref(&voice->overflow_sample);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1439,23 +1457,21 @@ fluid_voice_stop(fluid_voice_t *voice)
|
|||
|
||||
voice->chan = NO_CHANNEL;
|
||||
|
||||
if(voice->can_access_rvoice)
|
||||
{
|
||||
fluid_voice_sample_unref(&voice->rvoice->dsp.sample);
|
||||
}
|
||||
/* Decrement the reference count of the sample, to indicate
|
||||
that this sample isn't owned by the rvoice anymore.
|
||||
*/
|
||||
fluid_voice_sample_unref(&voice->sample);
|
||||
|
||||
voice->status = FLUID_VOICE_OFF;
|
||||
voice->has_noteoff = 1;
|
||||
|
||||
/* Decrement the reference count of the sample. */
|
||||
fluid_voice_sample_unref(&voice->sample);
|
||||
|
||||
/* Decrement voice count */
|
||||
voice->channel->synth->active_voice_count--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a modulator to the voice if the modulator has valid sources.
|
||||
*
|
||||
* @param voice Voice instance.
|
||||
* @param mod Modulator info (copied).
|
||||
* @param mode Determines how to handle an existing identical modulator.
|
||||
|
@ -1484,7 +1500,7 @@ fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode)
|
|||
* are checked for identity.
|
||||
* - When check_count_limit is below the actual number of voices modulators
|
||||
* (voice->mod_count), this will restrict identity check to this number,
|
||||
* This is usefull when we know by advance that there is no duplicate with
|
||||
* This is useful when we know by advance that there is no duplicate with
|
||||
* modulators at index above this limit. This avoid wasting cpu cycles at noteon.
|
||||
*/
|
||||
void
|
||||
|
@ -1543,15 +1559,16 @@ fluid_voice_add_mod_local(fluid_voice_t *voice, fluid_mod_t *mod, int mode, int
|
|||
|
||||
/**
|
||||
* Get the unique ID of the noteon-event.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return Note on unique ID
|
||||
*
|
||||
* A SoundFont loader may store the voice processes it has created for
|
||||
* A SoundFont loader may store pointers to voices it has created for
|
||||
* real-time control during the operation of a voice (for example: parameter
|
||||
* changes in SoundFont editor). The synth uses a pool of voices, which are
|
||||
* changes in SoundFont editor). The synth uses a pool of voices internally which are
|
||||
* 'recycled' and never deallocated.
|
||||
*
|
||||
* Before modifying an existing voice, check
|
||||
* However, before modifying an existing voice, check
|
||||
* - that its state is still 'playing'
|
||||
* - that the ID is still the same
|
||||
*
|
||||
|
@ -1563,7 +1580,14 @@ unsigned int fluid_voice_get_id(const fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if a voice is producing sound. This is also true after a voice received a noteoff as it may be playing in release phase.
|
||||
* Check if a voice is producing sound.
|
||||
*
|
||||
* Like fluid_voice_is_on() this will return TRUE once a call to
|
||||
* fluid_synth_start_voice() has been made. Contrary to fluid_voice_is_on(),
|
||||
* this might also return TRUE after the voice received a noteoff event, as it may
|
||||
* still be playing in release phase, or because it has been sustained or
|
||||
* sostenuto'ed.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return TRUE if playing, FALSE otherwise
|
||||
*/
|
||||
|
@ -1576,9 +1600,15 @@ int fluid_voice_is_playing(const fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if a voice is ON. A voice is ON, if it has not yet received a noteoff event.
|
||||
* Check if a voice is ON.
|
||||
*
|
||||
* A voice is in ON state as soon as a call to fluid_synth_start_voice() has been made
|
||||
* (which is typically done in a fluid_preset_t's noteon function).
|
||||
* A voice stays ON as long as it has not received a noteoff event.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return TRUE if on, FALSE otherwise
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_is_on(const fluid_voice_t *voice)
|
||||
|
@ -1588,8 +1618,10 @@ int fluid_voice_is_on(const fluid_voice_t *voice)
|
|||
|
||||
/**
|
||||
* Check if a voice keeps playing after it has received a noteoff due to being held by sustain.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return TRUE if sustained, FALSE otherwise
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_is_sustained(const fluid_voice_t *voice)
|
||||
|
@ -1599,8 +1631,10 @@ int fluid_voice_is_sustained(const fluid_voice_t *voice)
|
|||
|
||||
/**
|
||||
* Check if a voice keeps playing after it has received a noteoff due to being held by sostenuto.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return TRUE if sostenuto, FALSE otherwise
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_is_sostenuto(const fluid_voice_t *voice)
|
||||
|
@ -1609,9 +1643,13 @@ int fluid_voice_is_sostenuto(const fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/**
|
||||
* If the voice is playing, gets the midi channel the voice is playing on. Else the result is undefined.
|
||||
* Return the MIDI channel the voice is playing on.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return The channel assigned to this voice
|
||||
*
|
||||
* @note The result of this function is only valid if the voice is playing.
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_get_channel(const fluid_voice_t *voice)
|
||||
|
@ -1620,11 +1658,16 @@ int fluid_voice_get_channel(const fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/**
|
||||
* If the voice is playing, gets the midi key the voice is actually playing at. Else the result is undefined.
|
||||
* If the voice was started from an instrument which uses a fixed key generator, it returns that.
|
||||
* Else returns the same as \c fluid_voice_get_key.
|
||||
* Return the effective MIDI key of the playing voice.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return The midi key this voice is playing at
|
||||
* @return The MIDI key this voice is playing at
|
||||
*
|
||||
* If the voice was started from an instrument which uses a fixed key generator, it returns that.
|
||||
* Otherwise returns the same value as \c fluid_voice_get_key.
|
||||
*
|
||||
* @note The result of this function is only valid if the voice is playing.
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_get_actual_key(const fluid_voice_t *voice)
|
||||
|
@ -1642,10 +1685,13 @@ int fluid_voice_get_actual_key(const fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/**
|
||||
* If the voice is playing, gets the midi key from the noteon event, by which the voice was initially turned on with.
|
||||
* Else the result is undefined.
|
||||
* Return the MIDI key from the starting noteon event.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return The midi key of the noteon event that originally turned on this voice
|
||||
* @return The MIDI key of the noteon event that originally turned on this voice
|
||||
*
|
||||
* @note The result of this function is only valid if the voice is playing.
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_get_key(const fluid_voice_t *voice)
|
||||
|
@ -1654,11 +1700,16 @@ int fluid_voice_get_key(const fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/**
|
||||
* If the voice is playing, gets the midi velocity the voice is actually playing at. Else the result is undefined.
|
||||
* If the voice was started from an instrument which uses a fixed velocity generator, it returns that.
|
||||
* Else returns the same as \c fluid_voice_get_velocity.
|
||||
* Return the effective MIDI velocity of the playing voice.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return The midi velocity this voice is playing at
|
||||
* @return The MIDI velocity this voice is playing at
|
||||
*
|
||||
* If the voice was started from an instrument which uses a fixed velocity generator, it returns that.
|
||||
* Otherwise it returns the same value as \c fluid_voice_get_velocity.
|
||||
*
|
||||
* @note The result of this function is only valid if the voice is playing.
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_get_actual_velocity(const fluid_voice_t *voice)
|
||||
|
@ -1676,10 +1727,13 @@ int fluid_voice_get_actual_velocity(const fluid_voice_t *voice)
|
|||
}
|
||||
|
||||
/**
|
||||
* If the voice is playing, gets the midi velocity from the noteon event, by which the voice was initially
|
||||
* turned on with. Else the result is undefined.
|
||||
* Return the MIDI velocity from the starting noteon event.
|
||||
*
|
||||
* @param voice Voice instance
|
||||
* @return The midi velocity which originally turned on this voice
|
||||
* @return The MIDI velocity which originally turned on this voice
|
||||
*
|
||||
* @note The result of this function is only valid if the voice is playing.
|
||||
*
|
||||
* @since 1.1.7
|
||||
*/
|
||||
int fluid_voice_get_velocity(const fluid_voice_t *voice)
|
||||
|
@ -1819,8 +1873,10 @@ int fluid_voice_set_gain(fluid_voice_t *voice, fluid_real_t gain)
|
|||
* - Calculate, what factor will make the loop inaudible
|
||||
* - Store in sample
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculate the peak volume of a sample for voice off optimization.
|
||||
*
|
||||
* @param s Sample to optimize
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*
|
||||
|
|
|
@ -71,7 +71,8 @@ struct _fluid_voice_t
|
|||
fluid_channel_t *channel;
|
||||
fluid_rvoice_eventhandler_t *eventhandler;
|
||||
fluid_zone_range_t *zone_range; /* instrument zone range*/
|
||||
fluid_sample_t *sample; /* Pointer to sample (dupe in rvoice) */
|
||||
fluid_sample_t *sample; /* Pointer to sample (dupe in rvoice) */
|
||||
fluid_sample_t *overflow_sample; /* Pointer to sample (dupe in overflow_rvoice) */
|
||||
|
||||
unsigned int start_time;
|
||||
int mod_count;
|
||||
|
|
|
@ -98,7 +98,7 @@ typedef union _fluid_rvoice_param_t
|
|||
int i;
|
||||
fluid_real_t real;
|
||||
} fluid_rvoice_param_t;
|
||||
enum { MAX_EVENT_PARAMS = 6 }; /**< Maximum number of #fluid_rvoice_param_t to be passed to an #fluid_rvoice_function_t */
|
||||
enum { MAX_EVENT_PARAMS = 7 }; /**< Maximum number of #fluid_rvoice_param_t to be passed to an #fluid_rvoice_function_t */
|
||||
typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS]);
|
||||
|
||||
/* Macro for declaring an rvoice event function (#fluid_rvoice_function_t). The functions may only access
|
||||
|
@ -191,11 +191,19 @@ typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t pa
|
|||
void* fluid_alloc(size_t len);
|
||||
|
||||
/* File access */
|
||||
#define FLUID_FOPEN(_f,_m) fopen(_f,_m)
|
||||
#define FLUID_FOPEN(_f,_m) fluid_fopen(_f,_m)
|
||||
#define FLUID_FCLOSE(_f) fclose(_f)
|
||||
#define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
|
||||
|
||||
FILE *fluid_fopen(const char *filename, const char *mode);
|
||||
|
||||
#ifdef WIN32
|
||||
#define FLUID_FSEEK(_f,_n,_set) _fseeki64(_f,_n,_set)
|
||||
#else
|
||||
#define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
|
||||
#define FLUID_FTELL(_f) ftell(_f)
|
||||
#endif
|
||||
|
||||
#define FLUID_FTELL(_f) fluid_file_tell(_f)
|
||||
|
||||
/* Memory functions */
|
||||
#define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
|
||||
|
@ -206,9 +214,10 @@ void* fluid_alloc(size_t len);
|
|||
#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_STRTOL(_s,_e,_b) strtol(_s,_e,_b)
|
||||
|
||||
#define FLUID_STRNCPY(_dst,_src,_n) \
|
||||
do { strncpy(_dst,_src,_n); \
|
||||
do { strncpy(_dst,_src,_n-1); \
|
||||
(_dst)[(_n)-1]='\0'; \
|
||||
}while(0)
|
||||
|
||||
|
@ -226,8 +235,8 @@ do { strncpy(_dst,_src,_n); \
|
|||
|
||||
#if (defined(WIN32) && _MSC_VER < 1900) || defined(MINGW32)
|
||||
/* need to make sure we use a C99 compliant implementation of (v)snprintf(),
|
||||
* i.e. not microsofts non compliant extension _snprintf() as it doesnt
|
||||
* reliably null-terminates the buffer
|
||||
* i.e. not microsofts non compliant extension _snprintf() as it doesn't
|
||||
* reliably null-terminate the buffer
|
||||
*/
|
||||
#define FLUID_SNPRINTF g_snprintf
|
||||
#else
|
||||
|
|
|
@ -1,49 +1,44 @@
|
|||
diff --git b/libs/fluidsynth/fluidsynth/settings.h a/libs/fluidsynth/fluidsynth/settings.h
|
||||
index a8b3cb85ec..aba86e3379 100644
|
||||
--- b/libs/fluidsynth/fluidsynth/settings.h
|
||||
+++ a/libs/fluidsynth/fluidsynth/settings.h
|
||||
@@ -123,7 +123,7 @@ FLUIDSYNTH_API
|
||||
int fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
-int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def);
|
||||
+int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char const **def);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *value);
|
||||
diff --git b/libs/fluidsynth/fluidsynth/synth.h a/libs/fluidsynth/fluidsynth/synth.h
|
||||
index f4802ee5b9..3003972542 100644
|
||||
index b8d0b0ab1e..126532554f 100644
|
||||
--- b/libs/fluidsynth/fluidsynth/synth.h
|
||||
+++ a/libs/fluidsynth/fluidsynth/synth.h
|
||||
@@ -176,7 +176,7 @@ FLUIDSYNTH_API int fluid_synth_count_effects_groups(fluid_synth_t *synth);
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef _FLUIDSYNTH_SYNTH_H
|
||||
#define _FLUIDSYNTH_SYNTH_H
|
||||
|
||||
/* Synthesis parameters */
|
||||
+#define FLUID_DEPRECATED
|
||||
|
||||
-FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate);
|
||||
+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);
|
||||
@@ -233,7 +233,7 @@ FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int p
|
||||
/* Misc */
|
||||
|
||||
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t *synth);
|
||||
-FLUID_DEPRECATED FLUIDSYNTH_API const char *fluid_synth_error(fluid_synth_t *synth);
|
||||
+const char *fluid_synth_error(fluid_synth_t *synth);
|
||||
|
||||
|
||||
/* Default modulators */
|
||||
@@ -265,7 +265,7 @@ FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t *synth, int len,
|
||||
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);
|
||||
-FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
|
||||
+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,
|
||||
@@ -310,7 +310,9 @@ FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int
|
||||
|
||||
/* LADSPA */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -530,8 +531,10 @@ int fluid_synth_pin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_unpin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num);
|
||||
|
||||
+#ifdef LADSPA
|
||||
/** @ingroup ladspa */
|
||||
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
|
||||
+#endif
|
||||
|
||||
|
||||
/* API: Poly mono mode */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
diff --git b/libs/fluidsynth/fluidsynth/types.h a/libs/fluidsynth/fluidsynth/types.h
|
||||
index 47ef18336a..5ad29281ad 100644
|
||||
index 4352b4c573..6c7994fe83 100644
|
||||
--- b/libs/fluidsynth/fluidsynth/types.h
|
||||
+++ a/libs/fluidsynth/fluidsynth/types.h
|
||||
@@ -56,7 +56,9 @@ typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer i
|
||||
@@ -58,7 +58,9 @@ typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer i
|
||||
typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */
|
||||
typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */
|
||||
typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */
|
||||
|
@ -66,8 +61,21 @@ index 60f441c49f..e6455186eb 100644
|
|||
|
||||
fluid_real_t fluid_ct2hz_real(fluid_real_t cents);
|
||||
fluid_real_t fluid_ct2hz(fluid_real_t cents);
|
||||
diff --git b/libs/fluidsynth/src/fluid_gen.h a/libs/fluidsynth/src/fluid_gen.h
|
||||
index b87e8d8a8c..75a4f39e8a 100644
|
||||
--- b/libs/fluidsynth/src/fluid_gen.h
|
||||
+++ a/libs/fluidsynth/src/fluid_gen.h
|
||||
@@ -27,7 +27,7 @@
|
||||
typedef struct _fluid_gen_info_t
|
||||
{
|
||||
char num; /* Generator number */
|
||||
- char *name;
|
||||
+ char const *name;
|
||||
char init; /* Does the generator need to be initialized (not used) */
|
||||
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
|
||||
float min; /* The minimum value */
|
||||
diff --git b/libs/fluidsynth/src/fluid_hash.c a/libs/fluidsynth/src/fluid_hash.c
|
||||
index 946a873bbf..79f83a4583 100644
|
||||
index 7efd0dedda..46f701c4ba 100644
|
||||
--- b/libs/fluidsynth/src/fluid_hash.c
|
||||
+++ a/libs/fluidsynth/src/fluid_hash.c
|
||||
@@ -991,6 +991,7 @@ fluid_hashtable_remove_all(fluid_hashtable_t *hashtable)
|
||||
|
@ -87,10 +95,10 @@ index 946a873bbf..79f83a4583 100644
|
|||
/*
|
||||
* fluid_hashtable_foreach_remove_or_steal:
|
||||
diff --git b/libs/fluidsynth/src/fluid_midi.c a/libs/fluidsynth/src/fluid_midi.c
|
||||
index ea1aff5202..844de01c8f 100644
|
||||
index 796b278fea..830aada199 100644
|
||||
--- b/libs/fluidsynth/src/fluid_midi.c
|
||||
+++ a/libs/fluidsynth/src/fluid_midi.c
|
||||
@@ -77,7 +77,7 @@ static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
|
||||
@@ -72,7 +72,7 @@ static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
|
||||
static int fluid_midi_file_eot(fluid_midi_file *mf);
|
||||
static int fluid_midi_file_get_division(fluid_midi_file *midifile);
|
||||
|
||||
|
@ -99,7 +107,7 @@ index ea1aff5202..844de01c8f 100644
|
|||
/***************************************************************
|
||||
*
|
||||
* MIDIFILE
|
||||
@@ -1048,6 +1048,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
|
||||
@@ -1042,6 +1042,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
|
||||
{
|
||||
return midifile->division;
|
||||
}
|
||||
|
@ -107,7 +115,7 @@ index ea1aff5202..844de01c8f 100644
|
|||
|
||||
/******************************************************
|
||||
*
|
||||
@@ -1414,7 +1415,7 @@ static void fluid_midi_event_get_sysex_LOCAL(fluid_midi_event_t *evt, void **dat
|
||||
@@ -1408,7 +1409,7 @@ static void fluid_midi_event_get_sysex_LOCAL(fluid_midi_event_t *evt, void **dat
|
||||
*
|
||||
* fluid_track_t
|
||||
*/
|
||||
|
@ -116,16 +124,16 @@ index ea1aff5202..844de01c8f 100644
|
|||
/*
|
||||
* new_fluid_track
|
||||
*/
|
||||
@@ -2504,3 +2505,4 @@ fluid_midi_event_length(unsigned char event)
|
||||
@@ -2728,3 +2729,4 @@ fluid_midi_event_length(unsigned char event)
|
||||
|
||||
return 1;
|
||||
}
|
||||
+#endif
|
||||
diff --git b/libs/fluidsynth/src/fluid_mod.c a/libs/fluidsynth/src/fluid_mod.c
|
||||
index 47547b5b5e..57313caf42 100644
|
||||
index effa202750..3b2a827814 100644
|
||||
--- b/libs/fluidsynth/src/fluid_mod.c
|
||||
+++ a/libs/fluidsynth/src/fluid_mod.c
|
||||
@@ -603,7 +603,7 @@ fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
|
||||
@@ -620,7 +620,7 @@ fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
|
||||
* @param name,if not NULL, pointer on a string displayed as a warning.
|
||||
* @return TRUE if modulator sources src1, src2 are valid, FALSE otherwise.
|
||||
*/
|
||||
|
@ -148,7 +156,7 @@ index 3e7661741f..ec8e967a35 100644
|
|||
#ifdef DEBUG
|
||||
void fluid_dump_modulator(fluid_mod_t *mod);
|
||||
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.c a/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||
index 257f0fbdec..d7fd2f541f 100644
|
||||
index 0b2d16066f..9bf7aec7bf 100644
|
||||
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||
@@ -23,7 +23,6 @@
|
||||
|
@ -160,7 +168,7 @@ index 257f0fbdec..d7fd2f541f 100644
|
|||
|
||||
|
||||
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.h a/libs/fluidsynth/src/fluid_rvoice_mixer.h
|
||||
index 4ee072e4b9..1b3fceb342 100644
|
||||
index 63a456ce19..6139081185 100644
|
||||
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.h
|
||||
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.h
|
||||
@@ -24,7 +24,6 @@
|
||||
|
@ -172,7 +180,7 @@ index 4ee072e4b9..1b3fceb342 100644
|
|||
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
|
||||
|
||||
diff --git b/libs/fluidsynth/src/fluid_settings.c a/libs/fluidsynth/src/fluid_settings.c
|
||||
index 78532ad2a3..a825603a44 100644
|
||||
index 2d9f7b10aa..d5c6b940f3 100644
|
||||
--- b/libs/fluidsynth/src/fluid_settings.c
|
||||
+++ a/libs/fluidsynth/src/fluid_settings.c
|
||||
@@ -21,9 +21,6 @@
|
||||
|
@ -185,7 +193,7 @@ index 78532ad2a3..a825603a44 100644
|
|||
#include "fluid_settings.h"
|
||||
#include "fluid_midi.h"
|
||||
|
||||
@@ -328,11 +325,13 @@ fluid_settings_init(fluid_settings_t *settings)
|
||||
@@ -330,11 +327,13 @@ fluid_settings_init(fluid_settings_t *settings)
|
||||
fluid_return_if_fail(settings != NULL);
|
||||
|
||||
fluid_synth_settings(settings);
|
||||
|
@ -199,8 +207,64 @@ index 78532ad2a3..a825603a44 100644
|
|||
}
|
||||
|
||||
static int
|
||||
@@ -1215,10 +1214,10 @@ fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const cha
|
||||
* @note The returned string is not owned by the caller and should not be modified or freed.
|
||||
*/
|
||||
int
|
||||
-fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def)
|
||||
+fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char const **def)
|
||||
{
|
||||
fluid_setting_node_t *node;
|
||||
- char *retval = NULL;
|
||||
+ char const *retval = NULL;
|
||||
|
||||
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
|
||||
diff --git b/libs/fluidsynth/src/fluid_sfont.c a/libs/fluidsynth/src/fluid_sfont.c
|
||||
index f5de0a5bdf..94844f84bf 100644
|
||||
--- b/libs/fluidsynth/src/fluid_sfont.c
|
||||
+++ a/libs/fluidsynth/src/fluid_sfont.c
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "fluid_sys.h"
|
||||
|
||||
|
||||
-void *default_fopen(const char *path)
|
||||
+static void *default_fopen(const char *path)
|
||||
{
|
||||
const char* msg;
|
||||
FILE* handle = fluid_file_open(path, &msg);
|
||||
@@ -35,17 +35,17 @@ void *default_fopen(const char *path)
|
||||
return handle;
|
||||
}
|
||||
|
||||
-int default_fclose(void *handle)
|
||||
+static int default_fclose(void *handle)
|
||||
{
|
||||
return FLUID_FCLOSE((FILE *)handle) == 0 ? FLUID_OK : FLUID_FAILED;
|
||||
}
|
||||
|
||||
-fluid_long_long_t default_ftell(void *handle)
|
||||
+static fluid_long_long_t default_ftell(void *handle)
|
||||
{
|
||||
return FLUID_FTELL((FILE *)handle);
|
||||
}
|
||||
|
||||
-int safe_fread(void *buf, fluid_long_long_t count, void *fd)
|
||||
+static int safe_fread(void *buf, fluid_long_long_t count, void *fd)
|
||||
{
|
||||
if(FLUID_FREAD(buf, (size_t)count, 1, (FILE *)fd) != 1)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ int safe_fread(void *buf, fluid_long_long_t count, void *fd)
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
-int safe_fseek(void *fd, fluid_long_long_t ofs, int whence)
|
||||
+static int safe_fseek(void *fd, fluid_long_long_t ofs, int whence)
|
||||
{
|
||||
if(FLUID_FSEEK((FILE *)fd, ofs, whence) != 0)
|
||||
{
|
||||
diff --git b/libs/fluidsynth/src/fluid_synth.c a/libs/fluidsynth/src/fluid_synth.c
|
||||
index e03c64089f..382979f7f5 100644
|
||||
index 89def2fd03..27e7022c5b 100644
|
||||
--- b/libs/fluidsynth/src/fluid_synth.c
|
||||
+++ a/libs/fluidsynth/src/fluid_synth.c
|
||||
@@ -25,7 +25,6 @@
|
||||
|
@ -211,7 +275,7 @@ index e03c64089f..382979f7f5 100644
|
|||
|
||||
#ifdef TRAP_ON_FPE
|
||||
#define _GNU_SOURCE
|
||||
@@ -262,7 +261,7 @@ void fluid_version(int *major, int *minor, int *micro)
|
||||
@@ -271,7 +270,7 @@ void fluid_version(int *major, int *minor, int *micro)
|
||||
* @return FluidSynth version string, which is internal and should not be
|
||||
* modified or freed.
|
||||
*/
|
||||
|
@ -220,7 +284,7 @@ index e03c64089f..382979f7f5 100644
|
|||
fluid_version_str(void)
|
||||
{
|
||||
return FLUIDSYNTH_VERSION;
|
||||
@@ -5558,7 +5557,7 @@ fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method)
|
||||
@@ -6748,7 +6747,7 @@ fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method)
|
||||
}
|
||||
|
||||
FLUID_API_RETURN(FLUID_OK);
|
||||
|
@ -229,7 +293,7 @@ index e03c64089f..382979f7f5 100644
|
|||
|
||||
/**
|
||||
* Get the total count of MIDI channels.
|
||||
@@ -6496,6 +6495,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
|
||||
@@ -7709,6 +7708,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
|
||||
FLUID_API_RETURN(FLUID_OK);
|
||||
}
|
||||
|
||||
|
@ -237,7 +301,7 @@ index e03c64089f..382979f7f5 100644
|
|||
/**
|
||||
* Return the LADSPA effects instance used by FluidSynth
|
||||
*
|
||||
@@ -6508,6 +6508,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
|
||||
@@ -7721,6 +7721,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
|
||||
|
||||
return synth->ladspa_fx;
|
||||
}
|
||||
|
@ -246,7 +310,7 @@ index e03c64089f..382979f7f5 100644
|
|||
/**
|
||||
* Configure a general-purpose IIR biquad filter.
|
||||
diff --git b/libs/fluidsynth/src/fluid_synth.h a/libs/fluidsynth/src/fluid_synth.h
|
||||
index b649bcf340..955b3fa12e 100644
|
||||
index 132a98ddae..9b0078f04b 100644
|
||||
--- b/libs/fluidsynth/src/fluid_synth.h
|
||||
+++ a/libs/fluidsynth/src/fluid_synth.h
|
||||
@@ -33,8 +33,6 @@
|
||||
|
@ -258,7 +322,7 @@ index b649bcf340..955b3fa12e 100644
|
|||
#include "fluid_rvoice_event.h"
|
||||
|
||||
/***************************************************************
|
||||
@@ -165,7 +163,9 @@ struct _fluid_synth_t
|
||||
@@ -161,7 +159,9 @@ struct _fluid_synth_t
|
||||
|
||||
fluid_mod_t *default_mod; /**< the (dynamic) list of default modulators */
|
||||
|
||||
|
@ -269,10 +333,10 @@ index b649bcf340..955b3fa12e 100644
|
|||
enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */
|
||||
};
|
||||
diff --git b/libs/fluidsynth/src/fluid_sys.c a/libs/fluidsynth/src/fluid_sys.c
|
||||
index 7454217dd2..c6300b90c2 100644
|
||||
index d5a8452963..609af21f36 100644
|
||||
--- b/libs/fluidsynth/src/fluid_sys.c
|
||||
+++ a/libs/fluidsynth/src/fluid_sys.c
|
||||
@@ -239,9 +239,10 @@ void fluid_free(void* ptr)
|
||||
@@ -309,9 +309,10 @@ void fluid_free(void* ptr)
|
||||
* @param delim String of delimiter chars.
|
||||
* @return Pointer to the next token or NULL if no more tokens.
|
||||
*/
|
||||
|
@ -285,8 +349,26 @@ index 7454217dd2..c6300b90c2 100644
|
|||
char c;
|
||||
|
||||
if(str == NULL || delim == NULL || !*delim)
|
||||
@@ -1282,7 +1283,7 @@ long fluid_timer_get_interval(const fluid_timer_t * timer)
|
||||
* Get standard in stream handle.
|
||||
* @return Standard in stream.
|
||||
*/
|
||||
-fluid_istream_t
|
||||
+static fluid_istream_t
|
||||
fluid_get_stdin(void)
|
||||
{
|
||||
return STDIN_FILENO;
|
||||
@@ -1292,7 +1293,7 @@ fluid_get_stdin(void)
|
||||
* Get standard output stream handle.
|
||||
* @return Standard out stream.
|
||||
*/
|
||||
-fluid_ostream_t
|
||||
+static fluid_ostream_t
|
||||
fluid_get_stdout(void)
|
||||
{
|
||||
return STDOUT_FILENO;
|
||||
diff --git b/libs/fluidsynth/src/fluid_sys.h a/libs/fluidsynth/src/fluid_sys.h
|
||||
index 24df6edb5b..b747e5676a 100644
|
||||
index 86a47f32dc..05d6c6f200 100644
|
||||
--- b/libs/fluidsynth/src/fluid_sys.h
|
||||
+++ a/libs/fluidsynth/src/fluid_sys.h
|
||||
@@ -130,8 +130,9 @@ typedef gintptr intptr_t;
|
||||
|
@ -301,7 +383,7 @@ index 24df6edb5b..b747e5676a 100644
|
|||
|
||||
/* WIN32 special defines */
|
||||
#define STDIN_FILENO 0
|
||||
@@ -193,7 +194,7 @@ typedef gintptr intptr_t;
|
||||
@@ -198,7 +199,7 @@ char* fluid_get_windows_error(void);
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
|
@ -310,3 +392,16 @@ index 24df6edb5b..b747e5676a 100644
|
|||
|
||||
|
||||
#if defined(__OS2__)
|
||||
diff --git b/libs/fluidsynth/src/fluid_voice.c a/libs/fluidsynth/src/fluid_voice.c
|
||||
index 47f28d2a50..2ef0aee066 100644
|
||||
--- b/libs/fluidsynth/src/fluid_voice.c
|
||||
+++ a/libs/fluidsynth/src/fluid_voice.c
|
||||
@@ -480,7 +480,7 @@ fluid_voice_calculate_gain_amplitude(const fluid_voice_t *voice, fluid_real_t ga
|
||||
This is useful to set the value of GEN_PITCH generator on noteOn.
|
||||
This is useful to get the beginning/ending pitch for portamento.
|
||||
*/
|
||||
-fluid_real_t fluid_voice_calculate_pitch(fluid_voice_t *voice, int key)
|
||||
+static fluid_real_t fluid_voice_calculate_pitch(fluid_voice_t *voice, int key)
|
||||
{
|
||||
fluid_tuning_t *tuning;
|
||||
fluid_real_t x, pitch;
|
||||
|
|
|
@ -115,5 +115,5 @@ cd "$ASRC"
|
|||
patch -p1 < tools/fluid-patches/ardour_fluidsynth.diff
|
||||
|
||||
# auto-generated files
|
||||
cp tools/fluid-patches/fluid_conv_tables.c libs/fluidsynth/src/
|
||||
cp tools/fluid-patches/fluid_rvoice_dsp_tables.c libs/fluidsynth/src/
|
||||
cp tools/fluid-patches/fluid_conv_tables.inc.h libs/fluidsynth/src/
|
||||
cp tools/fluid-patches/fluid_rvoice_dsp_tables.inc.h libs/fluidsynth/src/
|
||||
|
|
Loading…
Reference in New Issue