mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-13 01:56:34 +01:00
Update to fluidsynth-2.1
see https://github.com/FluidSynth/fluidsynth/releases/tag/v2.1.0 - new, less "ringing" reverb engine - new, stereophonic chorus engine - improved integrity checking of SoundFont modulators ...
This commit is contained in:
parent
c5066dcf38
commit
d425f6dcb5
23 changed files with 1329 additions and 619 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
This is a stripped down version of fluidsynth (library only)
|
This is a stripped down version of fluidsynth (library only)
|
||||||
|
|
||||||
from git://github.com/FluidSynth/fluidsynth.git
|
from git://github.com/FluidSynth/fluidsynth.git
|
||||||
rev. v2.0.7-98-g9ab3e3ab
|
rev. v2.1.0-1-gb266cf2ab
|
||||||
|
|
||||||
fluidsynth is licensed in terms of the LGPL-2+, see individual source
|
fluidsynth is licensed in terms of the LGPL-2+, see individual source
|
||||||
files for (C) holders.
|
files for (C) holders.
|
||||||
|
|
|
||||||
|
|
@ -95,11 +95,22 @@ enum fluid_gen_type
|
||||||
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
|
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
|
||||||
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
|
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
|
||||||
|
|
||||||
/* the initial pitch is not a "standard" generator. It is not
|
/**
|
||||||
* mentioned in the list of generator in the SF2 specifications. It
|
* @brief Initial Pitch
|
||||||
* is used, however, as the destination for the default pitch wheel
|
*
|
||||||
* modulator. */
|
* @note This is not "standard" SoundFont generator, because it is not
|
||||||
GEN_PITCH, /**< Pitch @note Not a real SoundFont generator */
|
* mentioned in the list of generators in the SF2 specifications.
|
||||||
|
* It is used by FluidSynth internally to compute the nominal pitch of
|
||||||
|
* a note on note-on event. By nature it shouldn't be allowed to be modulated,
|
||||||
|
* however the specification defines a default modulator having "Initial Pitch"
|
||||||
|
* as destination (cf. SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch).
|
||||||
|
* Thus it is impossible to cancel this default modulator, which would be required
|
||||||
|
* to let the MIDI Pitch Wheel controller modulate a different generator.
|
||||||
|
* In order to provide this flexibility, FluidSynth >= 2.1.0 uses a default modulator
|
||||||
|
* "Pitch Wheel to Fine Tune", rather than Initial Pitch. The same "compromise" can
|
||||||
|
* be found on the Audigy 2 ZS for instance.
|
||||||
|
*/
|
||||||
|
GEN_PITCH,
|
||||||
|
|
||||||
GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
|
GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
|
||||||
/* non-standard generator for an additional custom high- or low-pass filter */
|
/* non-standard generator for an additional custom high- or low-pass filter */
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,11 @@ fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun,
|
||||||
|
|
||||||
FLUIDSYNTH_API void fluid_default_log_function(int level, const char *message, void *data);
|
FLUIDSYNTH_API void fluid_default_log_function(int level, const char *message, void *data);
|
||||||
|
|
||||||
FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...);
|
FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...)
|
||||||
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,13 @@ extern "C" {
|
||||||
* @brief Embeddable SoundFont synthesizer
|
* @brief Embeddable SoundFont synthesizer
|
||||||
*
|
*
|
||||||
* You create a new synthesizer with new_fluid_synth() and you destroy
|
* You create a new synthesizer with new_fluid_synth() and you destroy
|
||||||
* if with delete_fluid_synth(). Use the settings structure to specify
|
* it with delete_fluid_synth(). Use the fluid_settings_t structure to specify
|
||||||
* the synthesizer characteristics.
|
* the synthesizer characteristics.
|
||||||
*
|
*
|
||||||
* You have to load a SoundFont in order to hear any sound. For that
|
* You have to load a SoundFont in order to hear any sound. For that
|
||||||
* you use the fluid_synth_sfload() function.
|
* you use the fluid_synth_sfload() function.
|
||||||
*
|
*
|
||||||
* You can use the audio driver functions described below to open
|
* You can use the audio driver functions to open
|
||||||
* the audio device and create a background audio thread.
|
* the audio device and create a background audio thread.
|
||||||
*
|
*
|
||||||
* The API for sending MIDI events is probably what you expect:
|
* The API for sending MIDI events is probably what you expect:
|
||||||
|
|
@ -244,7 +244,7 @@ const char *fluid_synth_error(fluid_synth_t *synth);
|
||||||
enum fluid_synth_add_mod
|
enum fluid_synth_add_mod
|
||||||
{
|
{
|
||||||
FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */
|
FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */
|
||||||
FLUID_SYNTH_ADD, /**< Add (sum) modulator amounts */
|
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_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode);
|
||||||
|
|
@ -296,7 +296,7 @@ enum fluid_iir_filter_type
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies optional settings to use for the custom IIR filter
|
* Specifies optional settings to use for the custom IIR filter. Can be bitwise ORed.
|
||||||
*/
|
*/
|
||||||
enum fluid_iir_filter_flags
|
enum fluid_iir_filter_flags
|
||||||
{
|
{
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -49,7 +49,6 @@ typedef enum
|
||||||
*/
|
*/
|
||||||
fluid_chorus_t *new_fluid_chorus(fluid_real_t sample_rate);
|
fluid_chorus_t *new_fluid_chorus(fluid_real_t sample_rate);
|
||||||
void delete_fluid_chorus(fluid_chorus_t *chorus);
|
void delete_fluid_chorus(fluid_chorus_t *chorus);
|
||||||
int fluid_chorus_init(fluid_chorus_t *chorus);
|
|
||||||
void fluid_chorus_reset(fluid_chorus_t *chorus);
|
void fluid_chorus_reset(fluid_chorus_t *chorus);
|
||||||
|
|
||||||
void fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
void fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
||||||
|
|
|
||||||
|
|
@ -23,66 +23,56 @@
|
||||||
#include "fluid_conv_tables.c"
|
#include "fluid_conv_tables.c"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fluid_ct2hz
|
* Converts absolute cents to Hertz
|
||||||
|
*
|
||||||
|
* As per sfspec section 9.3:
|
||||||
|
*
|
||||||
|
* ABSOLUTE CENTS - An absolute logarithmic measure of frequency based on a
|
||||||
|
* reference of MIDI key number scaled by 100.
|
||||||
|
* A cent is 1/1200 of an octave [which is the twelve hundredth root of two],
|
||||||
|
* and value 6900 is 440 Hz (A-440).
|
||||||
|
*
|
||||||
|
* Implemented below basically is the following:
|
||||||
|
* 440 * 2^((cents-6900)/1200)
|
||||||
|
* = 440 * 2^((int)((cents-6900)/1200)) * 2^(((int)cents-6900)%1200))
|
||||||
|
* = 2^((int)((cents-6900)/1200)) * (440 * 2^(((int)cents-6900)%1200)))
|
||||||
|
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
* This second factor is stored in the lookup table.
|
||||||
|
*
|
||||||
|
* The first factor can be implemented with a fast shift when the exponent
|
||||||
|
* is always an int. This is the case when using 440/2^6 Hz rather than 440Hz
|
||||||
|
* reference.
|
||||||
*/
|
*/
|
||||||
fluid_real_t
|
fluid_real_t
|
||||||
fluid_ct2hz_real(fluid_real_t cents)
|
fluid_ct2hz_real(fluid_real_t cents)
|
||||||
{
|
{
|
||||||
if(cents < 0)
|
if(FLUID_UNLIKELY(cents < 0))
|
||||||
{
|
{
|
||||||
return (fluid_real_t) 1.0;
|
return (fluid_real_t) 1.0;
|
||||||
}
|
}
|
||||||
else if(cents < 900)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int)(cents + 300)];
|
|
||||||
}
|
|
||||||
else if(cents < 2100)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int)(cents - 900)];
|
|
||||||
}
|
|
||||||
else if(cents < 3300)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int)(cents - 2100)];
|
|
||||||
}
|
|
||||||
else if(cents < 4500)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int)(cents - 3300)];
|
|
||||||
}
|
|
||||||
else if(cents < 5700)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int)(cents - 4500)];
|
|
||||||
}
|
|
||||||
else if(cents < 6900)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int)(cents - 5700)];
|
|
||||||
}
|
|
||||||
else if(cents < 8100)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int)(cents - 6900)];
|
|
||||||
}
|
|
||||||
else if(cents < 9300)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int)(cents - 8100)];
|
|
||||||
}
|
|
||||||
else if(cents < 10500)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int)(cents - 9300)];
|
|
||||||
}
|
|
||||||
else if(cents < 11700)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int)(cents - 10500)];
|
|
||||||
}
|
|
||||||
else if(cents < 12900)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int)(cents - 11700)];
|
|
||||||
}
|
|
||||||
else if(cents < 14100)
|
|
||||||
{
|
|
||||||
return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int)(cents - 12900)];
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
|
unsigned int mult, fac, rem;
|
||||||
|
unsigned int icents = (unsigned int)cents;
|
||||||
|
icents += 300u;
|
||||||
|
|
||||||
|
// don't use stdlib div() here, it turned out have poor performance
|
||||||
|
fac = icents / 1200u;
|
||||||
|
rem = icents % 1200u;
|
||||||
|
|
||||||
|
// Think of "mult" as the factor that we multiply (440/2^6)Hz with,
|
||||||
|
// or in other words mult is the "first factor" of the above
|
||||||
|
// functions comment.
|
||||||
|
//
|
||||||
|
// Assuming sizeof(uint)==4 this will give us a maximum range of
|
||||||
|
// 32 * 1200cents - 300cents == 38100 cents == 29,527,900,160 Hz
|
||||||
|
// which is much more than ever needed. For bigger values, just
|
||||||
|
// safely wrap around (the & is just a replacement for the quick
|
||||||
|
// modulo operation % 32).
|
||||||
|
mult = 1u << (fac & (sizeof(mult)*8u - 1u));
|
||||||
|
|
||||||
|
// don't use ldexp() either (poor performance)
|
||||||
|
return mult * fluid_ct2hz_tab[rem];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
/* See SFSpec21 $8.1.3 */
|
/* See SFSpec21 $8.1.3 */
|
||||||
static const fluid_gen_info_t fluid_gen_info[] =
|
static const fluid_gen_info_t fluid_gen_info[] =
|
||||||
{
|
{
|
||||||
/* number/name init scale min max def */
|
/* number/name init nrpn-scale min max def */
|
||||||
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
|
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
|
||||||
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
|
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
|
||||||
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
typedef struct _fluid_gen_info_t
|
typedef struct _fluid_gen_info_t
|
||||||
{
|
{
|
||||||
char num; /* Generator number */
|
char num; /* Generator number */
|
||||||
char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
|
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()) */
|
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
|
||||||
float min; /* The minimum value */
|
float min; /* The minimum value */
|
||||||
float max; /* The maximum value */
|
float max; /* The maximum value */
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ fluid_file_read_full(fluid_file fp, size_t *length)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLUID_LOG(FLUID_DBG, "File load: Allocating %d bytes", buflen);
|
FLUID_LOG(FLUID_DBG, "File load: Allocating %lu bytes", buflen);
|
||||||
buffer = FLUID_MALLOC(buflen);
|
buffer = FLUID_MALLOC(buflen);
|
||||||
|
|
||||||
if(buffer == NULL)
|
if(buffer == NULL)
|
||||||
|
|
@ -193,7 +193,7 @@ fluid_file_read_full(fluid_file fp, size_t *length)
|
||||||
|
|
||||||
if(n != buflen)
|
if(n != buflen)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Only read %d bytes; expected %d", n,
|
FLUID_LOG(FLUID_ERR, "Only read %lu bytes; expected %lu", n,
|
||||||
buflen);
|
buflen);
|
||||||
FLUID_FREE(buffer);
|
FLUID_FREE(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -75,25 +75,26 @@
|
||||||
* the building of a lot of resonances in the reverberation tail even when
|
* the building of a lot of resonances in the reverberation tail even when
|
||||||
* using only 8 delays lines (NBR_DELAYS = 8) (default).
|
* using only 8 delays lines (NBR_DELAYS = 8) (default).
|
||||||
*
|
*
|
||||||
* Although 8 lines give good result, using 12 delays lines brings the overall
|
* The frequency density (often called "modal density" is one property that
|
||||||
* frequency density quality a bit higher. This quality augmentation is noticeable
|
* contributes to sound quality. Although 8 lines give good result, using 12 delays
|
||||||
* particularly when using long reverb time (roomsize = 1) on solo instrument with
|
* lines brings the overall frequency density quality a bit higher.
|
||||||
* long release time. Of course the cpu load augmentation is +50% relatively
|
* This quality augmentation is noticeable particularly when using long reverb time
|
||||||
* to 8 lines.
|
* (roomsize = 1) on solo instrument with long release time. Of course the cpu load
|
||||||
|
* augmentation is +50% relatively to 8 lines.
|
||||||
*
|
*
|
||||||
* As a general rule the reverberation tail quality is easier to perceive by ear
|
* As a general rule the reverberation tail quality is easier to perceive by ear
|
||||||
* when using:
|
* when using:
|
||||||
* - percussive instruments (i.e piano and others).
|
* - percussive instruments (i.e piano and others).
|
||||||
* - long reverb time (roomsize = 1).
|
* - long reverb time (roomsize = 1).
|
||||||
* - no damping (damp = 0).
|
* - no damping (damp = 0).
|
||||||
*
|
* - Using headphone. Avoid using loud speaker, you will be quickly misguided by the
|
||||||
|
* natural reverberation of the room in which you are.
|
||||||
*
|
*
|
||||||
* The cpu load for 8 lines is a bit lower than for freeverb (- 3%),
|
* The cpu load for 8 lines is a bit lower than for freeverb (- 3%),
|
||||||
* but higher for 12 lines (+ 41%).
|
* but higher for 12 lines (+ 41%).
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* The memory consumption is less than for freeverb. This saves 147480 bytes
|
* The memory consumption is less than for freeverb
|
||||||
* for 8 lines (- 72%) and 110152 bytes for 12 lines (- 54 %).
|
|
||||||
* (see the results table below).
|
* (see the results table below).
|
||||||
*
|
*
|
||||||
* Two macros are usable at compiler time:
|
* Two macros are usable at compiler time:
|
||||||
|
|
@ -113,19 +114,23 @@
|
||||||
* Note: the cpu load in % are relative each to other. These values are
|
* Note: the cpu load in % are relative each to other. These values are
|
||||||
* given by the fluidsynth profile commands.
|
* given by the fluidsynth profile commands.
|
||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
* reverb | NBR_DELAYS | Performances | memory size | quality
|
* reverb | NBR_DELAYS | Performances | memory size | quality
|
||||||
* | | (cpu_load: %) | (bytes) |
|
* | | (cpu_load: %) | (bytes)(see note) |
|
||||||
* ==========================================================================
|
* ==========================================================================
|
||||||
* freeverb | 2 x 8 comb | 0.670 % | 204616 | ringing
|
* freeverb | 2 x 8 comb | 0.670 % | 204616 | ringing
|
||||||
* | 2 x 4 all-pass | | |
|
* | 2 x 4 all-pass | | |
|
||||||
* ----------|---------------------------------------------------------------
|
* ----------|---------------------------------------------------------------
|
||||||
* FDN | 8 | 0.650 % | 57136 | far less
|
* FDN | 8 | 0.650 % | 112160 | far less
|
||||||
* modulated | |(feeverb - 3%) |(freeverb - 72%) | ringing
|
* modulated | |(feeverb - 3%) | (55% freeverb) | ringing
|
||||||
* |---------------------------------------------------------------
|
* |---------------------------------------------------------------
|
||||||
* | 12 | 0.942 % | 94464 | best than
|
* | 12 | 0.942 % | 168240 | best than
|
||||||
* | |(freeverb + 41%) |(freeverb - 54%) | 8 lines
|
* | |(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).
|
||||||
|
*
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------------------
|
*----------------------------------------------------------------------------
|
||||||
* 'Denormalise' method to avoid loss of performance.
|
* 'Denormalise' method to avoid loss of performance.
|
||||||
|
|
@ -173,6 +178,8 @@
|
||||||
roomsize parameter.
|
roomsize parameter.
|
||||||
- DENORMALISING enable denormalising handling.
|
- DENORMALISING enable denormalising handling.
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
//#define INFOS_PRINT /* allows message to be printed on the console. */
|
||||||
|
|
||||||
/* Number of delay lines (must be only 8 or 12)
|
/* Number of delay lines (must be only 8 or 12)
|
||||||
8 is the default.
|
8 is the default.
|
||||||
12 produces a better quality but is +50% cpu expensive
|
12 produces a better quality but is +50% cpu expensive
|
||||||
|
|
@ -298,16 +305,6 @@ a flatter response on comb filter. So the input gain is set to 0.1 rather 1.0. *
|
||||||
#define DELAY_L11 1187
|
#define DELAY_L11 1187
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* 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
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* The FDN late feed back matrix: A
|
/* The FDN late feed back matrix: A
|
||||||
|
|
@ -612,6 +609,16 @@ static int set_mod_delay_line(mod_delay_line *mdl,
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
Return norminal delay length
|
||||||
|
|
||||||
|
@param mdl, pointer on modulated delay line.
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
static int get_mod_delay_line_length(mod_delay_line *mdl)
|
||||||
|
{
|
||||||
|
return (mdl->dl.size - mdl->mod_depth - INTERP_SAMPLES_NBR);
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
Reads the sample value out of the modulated delay line.
|
Reads the sample value out of the modulated delay line.
|
||||||
@param mdl, pointer on modulated delay line.
|
@param mdl, pointer on modulated delay line.
|
||||||
|
|
@ -738,6 +745,7 @@ static void update_rev_time_damping(fluid_late *late,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
fluid_real_t sample_period = 1 / late->samplerate; /* Sampling period */
|
fluid_real_t sample_period = 1 / late->samplerate; /* Sampling period */
|
||||||
|
int delay_length; /* delay length */
|
||||||
fluid_real_t dc_rev_time; /* Reverb time at 0 Hz (in seconds) */
|
fluid_real_t dc_rev_time; /* Reverb time at 0 Hz (in seconds) */
|
||||||
|
|
||||||
fluid_real_t alpha, alpha2;
|
fluid_real_t alpha, alpha2;
|
||||||
|
|
@ -756,8 +764,9 @@ static void update_rev_time_damping(fluid_late *late,
|
||||||
Computes dc_rev_time
|
Computes dc_rev_time
|
||||||
------------------------------------------*/
|
------------------------------------------*/
|
||||||
dc_rev_time = GET_DC_REV_TIME(roomsize);
|
dc_rev_time = GET_DC_REV_TIME(roomsize);
|
||||||
|
delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]);
|
||||||
/* computes gi_tmp from dc_rev_time using relation E2 */
|
/* computes gi_tmp from dc_rev_time using relation E2 */
|
||||||
gi_tmp = FLUID_POW(10, -3 * delay_length[NBR_DELAYS - 1] *
|
gi_tmp = FLUID_POW(10, -3 * delay_length *
|
||||||
sample_period / dc_rev_time); /* E2 */
|
sample_period / dc_rev_time); /* E2 */
|
||||||
#else
|
#else
|
||||||
/* roomsize parameters have the same response that Freeverb, that is:
|
/* roomsize parameters have the same response that Freeverb, that is:
|
||||||
|
|
@ -768,16 +777,18 @@ static void update_rev_time_damping(fluid_late *late,
|
||||||
Computes dc_rev_time
|
Computes dc_rev_time
|
||||||
------------------------------------------*/
|
------------------------------------------*/
|
||||||
fluid_real_t gi_min, gi_max;
|
fluid_real_t gi_min, gi_max;
|
||||||
|
|
||||||
/* values gi_min et gi_max are computed using E2 for the line with
|
/* values gi_min et gi_max are computed using E2 for the line with
|
||||||
maximum delay */
|
maximum delay */
|
||||||
gi_max = FLUID_POW(10, (-3 * delay_length[NBR_DELAYS - 1] / MAX_DC_REV_TIME) *
|
delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]);
|
||||||
sample_period); /* E2 */
|
gi_max = FLUID_POW(10, (-3 * delay_length / MAX_DC_REV_TIME) *
|
||||||
gi_min = FLUID_POW(10, (-3 * delay_length[NBR_DELAYS - 1] / MIN_DC_REV_TIME) *
|
sample_period); /* E2 */
|
||||||
sample_period); /* E2 */
|
gi_min = FLUID_POW(10, (-3 * delay_length / MIN_DC_REV_TIME) *
|
||||||
|
sample_period); /* E2 */
|
||||||
/* gi = f(roomsize, gi_max, gi_min) */
|
/* gi = f(roomsize, gi_max, gi_min) */
|
||||||
gi_tmp = gi_min + roomsize * (gi_max - gi_min);
|
gi_tmp = gi_min + roomsize * (gi_max - gi_min);
|
||||||
/* Computes T60DC from gi using inverse of relation E2.*/
|
/* Computes T60DC from gi using inverse of relation E2.*/
|
||||||
dc_rev_time = -3 * FLUID_M_LN10 * delay_length[NBR_DELAYS - 1] * sample_period / FLUID_LOGF(gi_tmp);
|
dc_rev_time = -3 * FLUID_M_LN10 * delay_length * sample_period / FLUID_LOGF(gi_tmp);
|
||||||
}
|
}
|
||||||
#endif /* ROOMSIZE_RESPONSE_LINEAR */
|
#endif /* ROOMSIZE_RESPONSE_LINEAR */
|
||||||
/*--------------------------------------------
|
/*--------------------------------------------
|
||||||
|
|
@ -809,12 +820,16 @@ static void update_rev_time_damping(fluid_late *late,
|
||||||
/* updates damping coefficients of all lines (gi , ai) from dc_rev_time, alpha */
|
/* updates damping coefficients of all lines (gi , ai) from dc_rev_time, alpha */
|
||||||
for(i = 0; i < NBR_DELAYS; i++)
|
for(i = 0; i < NBR_DELAYS; i++)
|
||||||
{
|
{
|
||||||
|
fluid_real_t gi, ai;
|
||||||
|
|
||||||
|
/* delay length */
|
||||||
|
delay_length = get_mod_delay_line_length(&late->mod_delay_lines[i]);
|
||||||
|
|
||||||
/* iir low pass filter gain */
|
/* iir low pass filter gain */
|
||||||
fluid_real_t gi = FLUID_POW(10, -3 * delay_length[i] *
|
gi = FLUID_POW(10, -3 * delay_length * sample_period / dc_rev_time);
|
||||||
sample_period / dc_rev_time);
|
|
||||||
|
|
||||||
/* iir low pass filter feedback gain */
|
/* iir low pass filter feedback gain */
|
||||||
fluid_real_t ai = (20.f / 80.f) * FLUID_LOGF(gi) * (1.f - 1.f / alpha2);
|
ai = (20.f / 80.f) * FLUID_LOGF(gi) * (1.f - 1.f / alpha2);
|
||||||
|
|
||||||
/* b0 = gi * (1 - ai), a1 = - ai */
|
/* b0 = gi * (1 - ai), a1 = - ai */
|
||||||
set_fdn_delay_lpf(&late->mod_delay_lines[i].dl.damping,
|
set_fdn_delay_lpf(&late->mod_delay_lines[i].dl.damping,
|
||||||
|
|
@ -830,6 +845,7 @@ static void update_rev_time_damping(fluid_late *late,
|
||||||
static void update_stereo_coefficient(fluid_late *late, fluid_real_t wet1)
|
static void update_stereo_coefficient(fluid_late *late, fluid_real_t wet1)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
fluid_real_t wet;
|
||||||
|
|
||||||
for(i = 0; i < NBR_DELAYS; i++)
|
for(i = 0; i < NBR_DELAYS; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -852,26 +868,23 @@ static void update_stereo_coefficient(fluid_late *late, fluid_real_t wet1)
|
||||||
11|-1 -1|
|
11|-1 -1|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
late->out_left_gain[i] = wet1;
|
/* for left line: 00, ,02, ,04, ,06, ,08, ,10, ,12,... left_gain = +1 */
|
||||||
|
/* for left line: ,01, ,03, ,05, ,07, ,09, ,11,... left_gain = -1 */
|
||||||
|
wet = wet1;
|
||||||
|
if(i & 1)
|
||||||
|
{
|
||||||
|
wet = -wet1;
|
||||||
|
}
|
||||||
|
late->out_left_gain[i] = wet;
|
||||||
|
|
||||||
/* Sets Left coefficients first */
|
/* for right line: 00,01, ,04,05, ,08,09, ,12,13 right_gain = +1 */
|
||||||
if(i % 2) /* Left is 1,-1, 1,-1, 1,-1,.... */
|
/* for right line: ,02 ,03, ,06,07, ,10,11,... right_gain = -1 */
|
||||||
|
wet = wet1;
|
||||||
|
if(i & 2)
|
||||||
{
|
{
|
||||||
late->out_left_gain[i] *= -1;
|
wet = -wet1;
|
||||||
}
|
|
||||||
|
|
||||||
/* Now sets right gain as function of Left */
|
|
||||||
/* for right line 1,2,5,6,9,10,13,14, right = - left */
|
|
||||||
if((i == 1) || (i == 2) || (i == 5) || (i == 6) || (i == 9) || (i == 10) || (i == 13) || (i == 14))
|
|
||||||
{
|
|
||||||
/* Right is reverse of Left */
|
|
||||||
late->out_right_gain[i] = -1 * late->out_left_gain[i];
|
|
||||||
}
|
|
||||||
else /* for Right : line 0,3,4,7,8,11,12,15 */
|
|
||||||
{
|
|
||||||
/* Right is same as Left */
|
|
||||||
late->out_right_gain[i] = late->out_left_gain[i];
|
|
||||||
}
|
}
|
||||||
|
late->out_right_gain[i] = wet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -892,29 +905,78 @@ static void delete_fluid_rev_late(fluid_late *late)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
Creates the fdn reverb.
|
Creates all modulated lines.
|
||||||
@param late, pointer on the fnd late reverb to initialize.
|
@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.
|
@return FLUID_OK if success, FLUID_FAILED otherwise.
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
static int create_fluid_rev_late(fluid_late *late, fluid_real_t sample_rate)
|
static int create_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate)
|
||||||
{
|
{
|
||||||
|
/* 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
|
||||||
|
};
|
||||||
|
|
||||||
int result; /* return value */
|
int result; /* return value */
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
FLUID_MEMSET(late, 0, sizeof(fluid_late));
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
late->samplerate = sample_rate;
|
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
|
||||||
First initialize the modulated delay lines
|
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;
|
||||||
for(i = 0; i < NBR_DELAYS; i++)
|
fluid_real_t mod_depth = MOD_DEPTH;
|
||||||
|
if(sample_rate > 44100.0f)
|
||||||
{
|
{
|
||||||
/* sets local delay lines's parameters */
|
fluid_real_t sample_rate_factor = sample_rate/44100.0f;
|
||||||
|
length_factor *= sample_rate_factor;
|
||||||
|
mod_depth *= sample_rate_factor;
|
||||||
|
}
|
||||||
|
#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++)
|
||||||
|
{
|
||||||
|
total_delay += length_factor * delay_length[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
}
|
||||||
|
#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],
|
result = set_mod_delay_line(&late->mod_delay_lines[i],
|
||||||
delay_length[i], MOD_DEPTH, MOD_RATE);
|
delay_length[i] * length_factor,
|
||||||
|
mod_depth, MOD_RATE);
|
||||||
|
|
||||||
if(result == FLUID_FAILED)
|
if(result == FLUID_FAILED)
|
||||||
{
|
{
|
||||||
|
|
@ -926,12 +988,33 @@ static int create_fluid_rev_late(fluid_late *late, fluid_real_t sample_rate)
|
||||||
*/
|
*/
|
||||||
set_mod_frequency(&late->mod_delay_lines[i].mod,
|
set_mod_frequency(&late->mod_delay_lines[i].mod,
|
||||||
MOD_FREQ * MOD_RATE,
|
MOD_FREQ * MOD_RATE,
|
||||||
sample_rate,
|
late->samplerate,
|
||||||
(float)(MOD_PHASE * i));
|
(float)(MOD_PHASE * i));
|
||||||
}
|
}
|
||||||
|
return FLUID_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
Creates the fdn reverb.
|
||||||
|
@param late, pointer on the fnd late reverb to initialize.
|
||||||
|
@param sample_rate the sample rate.
|
||||||
|
@return FLUID_OK if success, FLUID_FAILED otherwise.
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
static int create_fluid_rev_late(fluid_late *late, fluid_real_t sample_rate)
|
||||||
|
{
|
||||||
|
FLUID_MEMSET(late, 0, sizeof(fluid_late));
|
||||||
|
|
||||||
|
late->samplerate = sample_rate;
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
First initialize the modulated delay lines
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(create_mod_delay_lines(late, sample_rate) == FLUID_FAILED)
|
||||||
|
{
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
update_stereo_coefficient(late, 1.0f);
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -982,7 +1065,7 @@ fluid_revmodel_update(fluid_revmodel_t *rev)
|
||||||
/* integrates wet1 in stereo coefficient (this will save one multiply) */
|
/* integrates wet1 in stereo coefficient (this will save one multiply) */
|
||||||
update_stereo_coefficient(&rev->late, rev->wet1);
|
update_stereo_coefficient(&rev->late, rev->wet1);
|
||||||
|
|
||||||
if(rev->wet1 > 0.0)
|
if(rev->wet1 > 0.0f)
|
||||||
{
|
{
|
||||||
rev->wet2 /= rev->wet1;
|
rev->wet2 /= rev->wet1;
|
||||||
}
|
}
|
||||||
|
|
@ -996,7 +1079,10 @@ fluid_revmodel_update(fluid_revmodel_t *rev)
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a reverb.
|
* Creates a reverb. One 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 sample rate in Hz.
|
||||||
* @return pointer on the new reverb or NULL if memory error.
|
* @return pointer on the new reverb or NULL if memory error.
|
||||||
* Reverb API.
|
* Reverb API.
|
||||||
|
|
@ -1024,7 +1110,15 @@ new_fluid_revmodel(fluid_real_t sample_rate)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free the reverb.
|
* free the reverb.
|
||||||
* @param pointer on rev to free.
|
* Note that while the reverb is used by calling any fluid_revmodel_processXXX()
|
||||||
|
* function, calling delete_fluid_revmodel() isn't multi task safe because
|
||||||
|
* delay line are freed. To deal properly with this issue follow the steps:
|
||||||
|
*
|
||||||
|
* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().
|
||||||
|
* reverb functions.
|
||||||
|
* 2) Delete the reverb by calling delete_fluid_revmodel().
|
||||||
|
*
|
||||||
|
* @param rev pointer on reverb to free.
|
||||||
* Reverb API.
|
* Reverb API.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
|
@ -1036,7 +1130,14 @@ delete_fluid_revmodel(fluid_revmodel_t *rev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets one or more reverb parameters.
|
* Sets one or more reverb parameters. Note this must be called at least one
|
||||||
|
* time after calling new_fluid_revmodel().
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* fluid_revmodel_set().
|
||||||
|
*
|
||||||
* @param rev Reverb instance.
|
* @param rev Reverb instance.
|
||||||
* @param set One or more flags from #fluid_revmodel_set_t indicating what
|
* @param set One or more flags from #fluid_revmodel_set_t indicating what
|
||||||
* parameters to set (#FLUID_REVMODEL_SET_ALL to set all parameters).
|
* parameters to set (#FLUID_REVMODEL_SET_ALL to set all parameters).
|
||||||
|
|
@ -1084,31 +1185,43 @@ fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Applies a sample rate change on the reverb.
|
* Applies a sample rate change on the reverb.
|
||||||
|
* 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:
|
||||||
|
* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX().
|
||||||
|
* reverb functions.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Another solution is to substitute step (2):
|
||||||
|
* 2.1) delete the reverb by calling delete_fluid_revmodel().
|
||||||
|
* 2.2) create the reverb by calling new_fluid_revmodel().
|
||||||
|
*
|
||||||
* @param rev the reverb.
|
* @param rev the reverb.
|
||||||
* @param sample_rate new sample rate value.
|
* @param sample_rate new sample rate value.
|
||||||
*
|
* @return FLUID_OK if success, FLUID_FAILED otherwise (memory error).
|
||||||
* Reverb API.
|
* Reverb API.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)
|
fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)
|
||||||
{
|
{
|
||||||
int i;
|
rev->late.samplerate = sample_rate; /* new sample rate value */
|
||||||
|
|
||||||
/* updates modulator frequency according to sample rate change */
|
/* free all delay lines */
|
||||||
for(i = 0; i < NBR_DELAYS; i++)
|
delete_fluid_rev_late(&rev->late);
|
||||||
|
|
||||||
|
/* create all delay lines */
|
||||||
|
if(create_mod_delay_lines(&rev->late, sample_rate) == FLUID_FAILED)
|
||||||
{
|
{
|
||||||
set_mod_frequency(&rev->late.mod_delay_lines[i].mod,
|
return FLUID_FAILED; /* memory error */
|
||||||
MOD_FREQ * MOD_RATE,
|
|
||||||
sample_rate,
|
|
||||||
(float)(MOD_PHASE * i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* updates damping filter coefficients according to sample rate change */
|
/* updates damping filter coefficients according to sample rate change */
|
||||||
rev->late.samplerate = sample_rate;
|
|
||||||
update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);
|
update_rev_time_damping(&rev->late, rev->roomsize, rev->damp);
|
||||||
|
|
||||||
/* clears all delay lines */
|
return FLUID_OK;
|
||||||
fluid_revmodel_init(rev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,6 @@ void fluid_revmodel_reset(fluid_revmodel_t *rev);
|
||||||
void fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
|
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_real_t damping, fluid_real_t width, fluid_real_t level);
|
||||||
|
|
||||||
void fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate);
|
int fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate);
|
||||||
|
|
||||||
#endif /* _FLUID_REV_H */
|
#endif /* _FLUID_REV_H */
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
static void fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks);
|
static void fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return -1 if voice has finished, 0 if it's currently quiet, 1 otherwise
|
* @return -1 if voice is quiet, 0 if voice has finished, 1 otherwise
|
||||||
*/
|
*/
|
||||||
static FLUID_INLINE int
|
static FLUID_INLINE int
|
||||||
fluid_rvoice_calc_amp(fluid_rvoice_t *voice)
|
fluid_rvoice_calc_amp(fluid_rvoice_t *voice)
|
||||||
|
|
@ -357,7 +357,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
|
||||||
|
|
||||||
if(count <= 0)
|
if(count <= 0)
|
||||||
{
|
{
|
||||||
return count;
|
return count; /* return -1 if voice is quiet, 0 if voice has finished */
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************* phase **********************/
|
/******************* phase **********************/
|
||||||
|
|
|
||||||
|
|
@ -359,14 +359,14 @@ get_dest_buf(fluid_rvoice_buffers_t *buffers, int index,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mix data down to buffers
|
* Mix samples down from internal dsp_buf to output buffers
|
||||||
*
|
*
|
||||||
* @param buffers Destination buffer(s)
|
* @param buffers Destination buffer(s)
|
||||||
* @param dsp_buf Mono sample source
|
* @param dsp_buf Mono sample source
|
||||||
* @param start_block Block to start mixing at
|
* @param start_block starting sample in dsp_buf
|
||||||
* @param sample_count number of samples to mix following \c start_block
|
* @param sample_count number of samples to mix following \c start_block
|
||||||
* @param dest_bufs Array of buffers to mixdown to
|
* @param dest_bufs Array of buffers to mixdown to
|
||||||
* @param dest_bufcount Length of dest_bufs
|
* @param dest_bufcount Length of dest_bufs (i.e count of buffers)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
|
fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
|
||||||
|
|
@ -374,9 +374,11 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
|
||||||
int start_block, int sample_count,
|
int start_block, int sample_count,
|
||||||
fluid_real_t **dest_bufs, int dest_bufcount)
|
fluid_real_t **dest_bufs, int dest_bufcount)
|
||||||
{
|
{
|
||||||
|
/* buffers count to mixdown to */
|
||||||
int bufcount = buffers->count;
|
int bufcount = buffers->count;
|
||||||
int i, dsp_i;
|
int i, dsp_i;
|
||||||
|
|
||||||
|
/* if there is nothing to mix, return immediatly */
|
||||||
if(sample_count <= 0 || dest_bufcount <= 0)
|
if(sample_count <= 0 || dest_bufcount <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -385,6 +387,7 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
|
||||||
FLUID_ASSERT((uintptr_t)dsp_buf % FLUID_DEFAULT_ALIGNMENT == 0);
|
FLUID_ASSERT((uintptr_t)dsp_buf % FLUID_DEFAULT_ALIGNMENT == 0);
|
||||||
FLUID_ASSERT((uintptr_t)(&dsp_buf[start_block * FLUID_BUFSIZE]) % FLUID_DEFAULT_ALIGNMENT == 0);
|
FLUID_ASSERT((uintptr_t)(&dsp_buf[start_block * FLUID_BUFSIZE]) % FLUID_DEFAULT_ALIGNMENT == 0);
|
||||||
|
|
||||||
|
/* mixdown for each buffer */
|
||||||
for(i = 0; i < bufcount; i++)
|
for(i = 0; i < bufcount; i++)
|
||||||
{
|
{
|
||||||
fluid_real_t *FLUID_RESTRICT buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
|
fluid_real_t *FLUID_RESTRICT buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
|
||||||
|
|
@ -397,11 +400,17 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
|
||||||
|
|
||||||
FLUID_ASSERT((uintptr_t)buf % FLUID_DEFAULT_ALIGNMENT == 0);
|
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)
|
#pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
|
||||||
|
for(dsp_i = 0; dsp_i < sample_count; dsp_i++)
|
||||||
for(dsp_i = (start_block * FLUID_BUFSIZE); dsp_i < sample_count; dsp_i++)
|
|
||||||
{
|
{
|
||||||
buf[dsp_i] += amp * dsp_buf[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] += amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -416,30 +425,42 @@ fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers,
|
||||||
fluid_rvoice_t *rvoice, fluid_real_t **dest_bufs,
|
fluid_rvoice_t *rvoice, fluid_real_t **dest_bufs,
|
||||||
unsigned int dest_bufcount, fluid_real_t *src_buf, int blockcount)
|
unsigned int dest_bufcount, fluid_real_t *src_buf, int blockcount)
|
||||||
{
|
{
|
||||||
int i, total_samples = 0, start_block = 0;
|
int i, total_samples = 0, last_block_mixed = 0;
|
||||||
|
|
||||||
for(i = 0; i < blockcount; i++)
|
for(i = 0; i < blockcount; i++)
|
||||||
{
|
{
|
||||||
|
/* render one block in src_buf */
|
||||||
int s = fluid_rvoice_write(rvoice, &src_buf[FLUID_BUFSIZE * i]);
|
int s = fluid_rvoice_write(rvoice, &src_buf[FLUID_BUFSIZE * i]);
|
||||||
|
|
||||||
if(s == -1)
|
if(s == -1)
|
||||||
{
|
{
|
||||||
start_block += s;
|
/* the voice is silent, mix back all the previously rendered sound */
|
||||||
s = FLUID_BUFSIZE;
|
fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed,
|
||||||
|
total_samples - (last_block_mixed*FLUID_BUFSIZE),
|
||||||
|
dest_bufs, dest_bufcount);
|
||||||
|
|
||||||
|
last_block_mixed = i+1; /* future block start index to mix from */
|
||||||
|
total_samples += FLUID_BUFSIZE; /* accumulate samples count rendered */
|
||||||
}
|
}
|
||||||
|
else
|
||||||
total_samples += s;
|
|
||||||
|
|
||||||
if(s < FLUID_BUFSIZE)
|
|
||||||
{
|
{
|
||||||
break;
|
/* the voice wasn't quiet. Some samples have been rendered [0..FLUID_BUFSIZE] */
|
||||||
|
total_samples += s;
|
||||||
|
if(s < FLUID_BUFSIZE)
|
||||||
|
{
|
||||||
|
/* voice has finished */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, -start_block, total_samples - ((-start_block)*FLUID_BUFSIZE), dest_bufs, dest_bufcount);
|
/* 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),
|
||||||
|
dest_bufs, dest_bufcount);
|
||||||
|
|
||||||
if(total_samples < blockcount * FLUID_BUFSIZE)
|
if(total_samples < blockcount * FLUID_BUFSIZE)
|
||||||
{
|
{
|
||||||
|
/* voice has finished */
|
||||||
fluid_finish_rvoice(buffers, rvoice);
|
fluid_finish_rvoice(buffers, rvoice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -601,7 +622,7 @@ fluid_mixer_buffers_zero(fluid_mixer_buffers_t *buffers, int current_blockcount)
|
||||||
static int
|
static int
|
||||||
fluid_mixer_buffers_init(fluid_mixer_buffers_t *buffers, fluid_rvoice_mixer_t *mixer)
|
fluid_mixer_buffers_init(fluid_mixer_buffers_t *buffers, fluid_rvoice_mixer_t *mixer)
|
||||||
{
|
{
|
||||||
const int samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
static const int samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||||
|
|
||||||
buffers->mixer = mixer;
|
buffers->mixer = mixer;
|
||||||
buffers->buf_count = mixer->buffers.buf_count;
|
buffers->buf_count = mixer->buffers.buf_count;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@
|
||||||
#include <sndfile.h>
|
#include <sndfile.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LIBINSTPATCH_SUPPORT
|
||||||
|
#include <libinstpatch/libinstpatch.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*=================================sfload.c========================
|
/*=================================sfload.c========================
|
||||||
Borrowed from Smurf SoundFont Editor by Josh Green
|
Borrowed from Smurf SoundFont Editor by Josh Green
|
||||||
=================================================================*/
|
=================================================================*/
|
||||||
|
|
@ -326,11 +330,13 @@ static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int en
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a file is a SoundFont file.
|
* Check if a file is a SoundFont file.
|
||||||
* @param filename Path to the file to check
|
|
||||||
* @return TRUE if it could be a SoundFont, FALSE otherwise
|
|
||||||
*
|
*
|
||||||
* @note The current implementation only checks for the "RIFF" and "sfbk" headers in
|
* If fluidsynth was built with DLS support, this function will also identify DLS files.
|
||||||
* the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
|
* @param filename Path to the file to check
|
||||||
|
* @return TRUE if it could be a SF2, SF3 or DLS file, FALSE otherwise
|
||||||
|
*
|
||||||
|
* @note This function only checks whether header(s) in the RIFF chunk are present.
|
||||||
|
* A call to fluid_synth_sfload() might still fail.
|
||||||
*/
|
*/
|
||||||
int fluid_is_soundfont(const char *filename)
|
int fluid_is_soundfont(const char *filename)
|
||||||
{
|
{
|
||||||
|
|
@ -344,7 +350,7 @@ int fluid_is_soundfont(const char *filename)
|
||||||
{
|
{
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
|
if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|
@ -366,6 +372,21 @@ int fluid_is_soundfont(const char *filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
retcode = (fcc == SFBK_FCC);
|
retcode = (fcc == SFBK_FCC);
|
||||||
|
if(retcode)
|
||||||
|
{
|
||||||
|
break; // seems to be SF2, stop here
|
||||||
|
}
|
||||||
|
#ifdef LIBINSTPATCH_SUPPORT
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IpatchFileHandle *fhandle = ipatch_file_identify_open(filename, NULL);
|
||||||
|
if(fhandle != NULL)
|
||||||
|
{
|
||||||
|
retcode = (ipatch_file_identify(fhandle->file, NULL) == IPATCH_TYPE_DLS_FILE);
|
||||||
|
ipatch_file_close(fhandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
while(0);
|
while(0);
|
||||||
|
|
||||||
|
|
@ -775,7 +796,7 @@ static int process_info(SFData *sf, int size)
|
||||||
if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))
|
if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",
|
FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",
|
||||||
&chunk.id, chunk.size);
|
(char*)&chunk.id, chunk.size);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -909,19 +930,19 @@ static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChu
|
||||||
|
|
||||||
if(chunk->id != expid)
|
if(chunk->id != expid)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", &expid);
|
FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", (char*)&expid);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chunk->size % reclen) /* valid chunk size? */
|
if(chunk->size % reclen) /* valid chunk size? */
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", &expid, reclen);
|
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", (char*)&expid, reclen);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((*size -= chunk->size) < 0)
|
if((*size -= chunk->size) < 0)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", &expid);
|
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", (char*)&expid);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2580,7 +2601,7 @@ static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigne
|
||||||
sfdata.end = end_byte;
|
sfdata.end = end_byte;
|
||||||
sfdata.offset = 0;
|
sfdata.offset = 0;
|
||||||
|
|
||||||
memset(&sfinfo, 0, sizeof(sfinfo));
|
FLUID_MEMSET(&sfinfo, 0, sizeof(sfinfo));
|
||||||
|
|
||||||
/* Seek to beginning of Ogg Vorbis data in Soundfont */
|
/* Seek to beginning of Ogg Vorbis data in Soundfont */
|
||||||
if(sf->fcbs->fseek(sf->sffd, sf->samplepos + start_byte, SEEK_SET) == FLUID_FAILED)
|
if(sf->fcbs->fseek(sf->sffd, sf->samplepos + start_byte, SEEK_SET) == FLUID_FAILED)
|
||||||
|
|
@ -2594,12 +2615,12 @@ static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigne
|
||||||
|
|
||||||
if(!sndfile)
|
if(!sndfile)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
|
FLUID_LOG(FLUID_ERR, "%s", sf_strerror(sndfile));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty sample
|
// Empty sample
|
||||||
if(!sfinfo.frames || !sfinfo.channels)
|
if(sfinfo.frames <= 0 || sfinfo.channels <= 0)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_DBG, "Empty decompressed sample");
|
FLUID_LOG(FLUID_DBG, "Empty decompressed sample");
|
||||||
*data = NULL;
|
*data = NULL;
|
||||||
|
|
@ -2607,7 +2628,12 @@ static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigne
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: ensure that the decompressed WAV data is 16-bit mono? */
|
// Mono sample
|
||||||
|
if(sfinfo.channels != 1)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_DBG, "Unsupported channel count %d in ogg sample", sfinfo.channels);
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels);
|
wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels);
|
||||||
|
|
||||||
|
|
@ -2617,11 +2643,11 @@ static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigne
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Automatically decompresses the Ogg Vorbis data to 16-bit WAV */
|
/* Automatically decompresses the Ogg Vorbis data to 16-bit PCM */
|
||||||
if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames)
|
if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_DBG, "Decompression failed!");
|
FLUID_LOG(FLUID_DBG, "Decompression failed!");
|
||||||
FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
|
FLUID_LOG(FLUID_ERR, "%s", sf_strerror(sndfile));
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -609,7 +609,7 @@ fluid_sample_set_sound_data(fluid_sample_t *sample,
|
||||||
goto error_rec;
|
goto error_rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLUID_MEMSET(sample->data, 0, storedNbFrames);
|
FLUID_MEMSET(sample->data, 0, storedNbFrames * sizeof(short));
|
||||||
FLUID_MEMCPY(sample->data + SAMPLE_LOOP_MARGIN, data, nbframes * sizeof(short));
|
FLUID_MEMCPY(sample->data + SAMPLE_LOOP_MARGIN, data, nbframes * sizeof(short));
|
||||||
|
|
||||||
if(data24 != NULL)
|
if(data24 != NULL)
|
||||||
|
|
@ -628,7 +628,7 @@ fluid_sample_set_sound_data(fluid_sample_t *sample,
|
||||||
/* pointers */
|
/* pointers */
|
||||||
/* all from the start of data */
|
/* all from the start of data */
|
||||||
sample->start = SAMPLE_LOOP_MARGIN;
|
sample->start = SAMPLE_LOOP_MARGIN;
|
||||||
sample->end = SAMPLE_LOOP_MARGIN + storedNbFrames - 1;
|
sample->end = SAMPLE_LOOP_MARGIN + nbframes - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,6 @@ static int fluid_synth_set_important_channels(fluid_synth_t *synth, const char *
|
||||||
|
|
||||||
|
|
||||||
/* Callback handlers for real-time settings */
|
/* Callback handlers for real-time settings */
|
||||||
static void fluid_synth_handle_sample_rate(void *data, const char *name, double value);
|
|
||||||
static void fluid_synth_handle_gain(void *data, const char *name, double value);
|
static void fluid_synth_handle_gain(void *data, const char *name, double value);
|
||||||
static void fluid_synth_handle_polyphony(void *data, const char *name, int value);
|
static void fluid_synth_handle_polyphony(void *data, const char *name, int value);
|
||||||
static void fluid_synth_handle_device_id(void *data, const char *name, int value);
|
static void fluid_synth_handle_device_id(void *data, const char *name, int value);
|
||||||
|
|
@ -197,7 +196,7 @@ void fluid_synth_settings(fluid_settings_t *settings)
|
||||||
fluid_settings_register_int(settings, "synth.chorus.active", 1, 0, 1, FLUID_HINT_TOGGLED);
|
fluid_settings_register_int(settings, "synth.chorus.active", 1, 0, 1, FLUID_HINT_TOGGLED);
|
||||||
fluid_settings_register_int(settings, "synth.chorus.nr", FLUID_CHORUS_DEFAULT_N, 0, 99, 0);
|
fluid_settings_register_int(settings, "synth.chorus.nr", FLUID_CHORUS_DEFAULT_N, 0, 99, 0);
|
||||||
fluid_settings_register_num(settings, "synth.chorus.level", FLUID_CHORUS_DEFAULT_LEVEL, 0.0f, 10.0f, 0);
|
fluid_settings_register_num(settings, "synth.chorus.level", FLUID_CHORUS_DEFAULT_LEVEL, 0.0f, 10.0f, 0);
|
||||||
fluid_settings_register_num(settings, "synth.chorus.speed", FLUID_CHORUS_DEFAULT_SPEED, 0.29f, 5.0f, 0);
|
fluid_settings_register_num(settings, "synth.chorus.speed", FLUID_CHORUS_DEFAULT_SPEED, 0.1f, 5.0f, 0);
|
||||||
fluid_settings_register_num(settings, "synth.chorus.depth", FLUID_CHORUS_DEFAULT_DEPTH, 0.0f, 256.0f, 0);
|
fluid_settings_register_num(settings, "synth.chorus.depth", FLUID_CHORUS_DEFAULT_DEPTH, 0.0f, 256.0f, 0);
|
||||||
|
|
||||||
fluid_settings_register_int(settings, "synth.ladspa.active", 0, 0, 1, FLUID_HINT_TOGGLED);
|
fluid_settings_register_int(settings, "synth.ladspa.active", 0, 0, 1, FLUID_HINT_TOGGLED);
|
||||||
|
|
@ -431,6 +430,10 @@ fluid_synth_init(void)
|
||||||
|
|
||||||
|
|
||||||
/* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */
|
/* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */
|
||||||
|
/* Initial Pitch is not a "standard" generator, because it isn't mentioned in the
|
||||||
|
list of generators in the SF2 specifications. That's why destination Initial Pitch
|
||||||
|
is replaced here by fine tune generator.
|
||||||
|
*/
|
||||||
fluid_mod_set_source1(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEEL, /* Index=14 */
|
fluid_mod_set_source1(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEEL, /* Index=14 */
|
||||||
FLUID_MOD_GC /* CC =0 */
|
FLUID_MOD_GC /* CC =0 */
|
||||||
| FLUID_MOD_LINEAR /* type=0 */
|
| FLUID_MOD_LINEAR /* type=0 */
|
||||||
|
|
@ -443,7 +446,8 @@ fluid_synth_init(void)
|
||||||
| FLUID_MOD_UNIPOLAR /* P=0 */
|
| FLUID_MOD_UNIPOLAR /* P=0 */
|
||||||
| FLUID_MOD_POSITIVE /* D=0 */
|
| FLUID_MOD_POSITIVE /* D=0 */
|
||||||
);
|
);
|
||||||
fluid_mod_set_dest(&default_pitch_bend_mod, GEN_PITCH); /* Destination: Initial pitch */
|
/* Also see the comment in gen.h about GEN_PITCH */
|
||||||
|
fluid_mod_set_dest(&default_pitch_bend_mod, GEN_FINETUNE); /* Destination: Fine Tune */
|
||||||
fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */
|
fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -589,8 +593,10 @@ static FLUID_INLINE unsigned int fluid_synth_get_min_note_length_LOCAL(fluid_syn
|
||||||
* @param settings Configuration parameters to use (used directly).
|
* @param settings Configuration parameters to use (used directly).
|
||||||
* @return New FluidSynth instance or NULL on error
|
* @return New FluidSynth instance or NULL on error
|
||||||
*
|
*
|
||||||
* @note The settings parameter is used directly and should not be modified
|
* @note The @p settings parameter is used directly and should freed after
|
||||||
* or freed independently.
|
* the synth has been deleted. Further note that you may modify FluidSettings of the
|
||||||
|
* @p settings instance. However, only those FluidSettings marked as 'realtime' will
|
||||||
|
* affect the synth immediately.
|
||||||
*/
|
*/
|
||||||
fluid_synth_t *
|
fluid_synth_t *
|
||||||
new_fluid_synth(fluid_settings_t *settings)
|
new_fluid_synth(fluid_settings_t *settings)
|
||||||
|
|
@ -647,8 +653,6 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
fluid_settings_getnum_float(settings, "synth.overflow.important", &synth->overflow.important);
|
fluid_settings_getnum_float(settings, "synth.overflow.important", &synth->overflow.important);
|
||||||
|
|
||||||
/* register the callbacks */
|
/* register the callbacks */
|
||||||
fluid_settings_callback_num(settings, "synth.sample-rate",
|
|
||||||
fluid_synth_handle_sample_rate, synth);
|
|
||||||
fluid_settings_callback_num(settings, "synth.gain",
|
fluid_settings_callback_num(settings, "synth.gain",
|
||||||
fluid_synth_handle_gain, synth);
|
fluid_synth_handle_gain, synth);
|
||||||
fluid_settings_callback_int(settings, "synth.polyphony",
|
fluid_settings_callback_int(settings, "synth.polyphony",
|
||||||
|
|
@ -1126,6 +1130,10 @@ fluid_synth_error(fluid_synth_t *synth)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a note-on event to a FluidSynth object.
|
* Send a note-on event to a FluidSynth object.
|
||||||
|
*
|
||||||
|
* This function will take care of proper legato playing. If a note on channel @p chan is
|
||||||
|
* already playing at the given key @p key, it will be released (even if it is sustained).
|
||||||
|
* In other words, overlapping notes are not allowed.
|
||||||
* @param synth FluidSynth instance
|
* @param synth FluidSynth instance
|
||||||
* @param chan MIDI channel number (0 to MIDI channel count - 1)
|
* @param chan MIDI channel number (0 to MIDI channel count - 1)
|
||||||
* @param key MIDI note number (0-127)
|
* @param key MIDI note number (0-127)
|
||||||
|
|
@ -3046,20 +3054,31 @@ fluid_synth_update_presets(fluid_synth_t *synth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handler for synth.sample-rate setting. */
|
|
||||||
static void
|
|
||||||
fluid_synth_handle_sample_rate(void *data, const char *name, double value)
|
|
||||||
{
|
|
||||||
fluid_synth_t *synth = (fluid_synth_t *)data;
|
|
||||||
fluid_synth_set_sample_rate(synth, (float) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set sample rate of the synth.
|
* Set up an event to change the sample-rate of the synth during the next rendering call.
|
||||||
* @note This function should only be used when no voices or notes are active.
|
* @warning This function is broken-by-design! Don't use it! Instead, specify the sample-rate when creating the synth.
|
||||||
|
* @deprecated As of fluidsynth 2.1.0 this function has been deprecated.
|
||||||
|
* Changing the sample-rate is generally not considered to be a real-time use-case, as it always produces some audible artifact ("click", "pop") on the dry sound and effects (because LFOs for chorus and reverb need to be reinitialized).
|
||||||
|
* The sample-rate change may also require memory allocation deep down in the effect units.
|
||||||
|
* However, this memory allocation may fail and there is no way for the caller to know that, because the actual change of the sample-rate is executed during rendering.
|
||||||
|
* This function cannot (must not) do the sample-rate change itself, otherwise the synth needs to be locked down, causing rendering to block.
|
||||||
|
* Esp. do not use this function if this @p synth instance is used by an audio driver, because the audio driver cannot be notified by this sample-rate change.
|
||||||
|
* Long story short: don't use it.
|
||||||
|
* @code{.cpp}
|
||||||
|
fluid_synth_t* synth; // assume initialized
|
||||||
|
// [...]
|
||||||
|
// sample-rate change needed? Delete the audio driver, if any.
|
||||||
|
delete_fluid_audio_driver(adriver);
|
||||||
|
// then delete the synth
|
||||||
|
delete_fluid_synth(synth);
|
||||||
|
// update the sample-rate
|
||||||
|
fluid_settings_setnum(settings, "synth.sample-rate", 22050.0);
|
||||||
|
// and re-create objects
|
||||||
|
synth = new_fluid_synth(settings);
|
||||||
|
adriver = new_fluid_audio_driver(settings, synth);
|
||||||
|
* @endcode
|
||||||
* @param synth FluidSynth instance
|
* @param synth FluidSynth instance
|
||||||
* @param sample_rate New sample rate (Hz)
|
* @param sample_rate New sample-rate (Hz)
|
||||||
* @since 1.1.2
|
* @since 1.1.2
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
|
@ -3382,6 +3401,8 @@ fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
|
||||||
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail(left != NULL, FLUID_FAILED);
|
fluid_return_val_if_fail(left != NULL, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail(right != NULL, FLUID_FAILED);
|
fluid_return_val_if_fail(right != NULL, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len >= 0, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below
|
||||||
|
|
||||||
/* First, take what's still available in the buffer */
|
/* First, take what's still available in the buffer */
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
@ -3666,6 +3687,8 @@ fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[],
|
||||||
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail(nfx % 2 == 0, FLUID_FAILED);
|
fluid_return_val_if_fail(nfx % 2 == 0, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail(nout % 2 == 0, FLUID_FAILED);
|
fluid_return_val_if_fail(nout % 2 == 0, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len >= 0, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below
|
||||||
|
|
||||||
nfxchan = synth->effects_channels;
|
nfxchan = synth->effects_channels;
|
||||||
nfxunits = synth->effects_groups;
|
nfxunits = synth->effects_groups;
|
||||||
|
|
@ -3798,9 +3821,19 @@ fluid_synth_write_float(fluid_synth_t *synth, int len,
|
||||||
void *lout, int loff, int lincr,
|
void *lout, int loff, int lincr,
|
||||||
void *rout, int roff, int rincr)
|
void *rout, int roff, int rincr)
|
||||||
{
|
{
|
||||||
int i, j, k, l;
|
return fluid_synth_write_float_LOCAL(synth, len, lout, loff, lincr, rout, roff, rincr, fluid_synth_render_blocks);
|
||||||
float *left_out = (float *) lout;
|
}
|
||||||
float *right_out = (float *) rout;
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int n, cur, size;
|
||||||
|
float *left_out = (float *) lout + loff;
|
||||||
|
float *right_out = (float *) rout + roff;
|
||||||
fluid_real_t *left_in;
|
fluid_real_t *left_in;
|
||||||
fluid_real_t *right_in;
|
fluid_real_t *right_in;
|
||||||
double time = fluid_utime();
|
double time = fluid_utime();
|
||||||
|
|
@ -3811,28 +3844,60 @@ fluid_synth_write_float(fluid_synth_t *synth, int len,
|
||||||
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail(lout != NULL, FLUID_FAILED);
|
fluid_return_val_if_fail(lout != NULL, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail(rout != NULL, FLUID_FAILED);
|
fluid_return_val_if_fail(rout != NULL, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len >= 0, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below
|
||||||
|
|
||||||
fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
|
fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
|
||||||
l = synth->cur;
|
|
||||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||||
|
|
||||||
for(i = 0, j = loff, k = roff; i < len; i++, l++, j += lincr, k += rincr)
|
size = len;
|
||||||
|
cur = synth->cur;
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
/* fill up the buffers as needed */
|
/* fill up the buffers as needed */
|
||||||
if(l >= synth->curmax)
|
if(cur >= synth->curmax)
|
||||||
{
|
{
|
||||||
int blocksleft = (len - i + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
|
int blocksleft = (size + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
|
||||||
synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
|
synth->curmax = FLUID_BUFSIZE * block_render_func(synth, blocksleft);
|
||||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||||
|
cur = 0;
|
||||||
l = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
left_out[j] = (float) left_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + l];
|
/* calculate amount of available samples */
|
||||||
right_out[k] = (float) right_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + l];
|
n = synth->curmax - cur;
|
||||||
}
|
|
||||||
|
|
||||||
synth->cur = l;
|
/* keep track of emitted samples */
|
||||||
|
if(n > size)
|
||||||
|
{
|
||||||
|
n = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= n;
|
||||||
|
|
||||||
|
/* update pointers to current position */
|
||||||
|
left_in += cur + n;
|
||||||
|
right_in += cur + n;
|
||||||
|
|
||||||
|
/* set final cursor position */
|
||||||
|
cur += n;
|
||||||
|
|
||||||
|
/* reverse index */
|
||||||
|
n = 0 - n;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*left_out = (float) left_in[n];
|
||||||
|
*right_out = (float) right_in[n];
|
||||||
|
|
||||||
|
left_out += lincr;
|
||||||
|
right_out += rincr;
|
||||||
|
}
|
||||||
|
while(++n < 0);
|
||||||
|
}
|
||||||
|
while(size);
|
||||||
|
|
||||||
|
synth->cur = cur;
|
||||||
|
|
||||||
time = fluid_utime() - time;
|
time = fluid_utime() - time;
|
||||||
cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0);
|
cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0);
|
||||||
|
|
@ -3924,43 +3989,77 @@ fluid_synth_write_s16(fluid_synth_t *synth, int len,
|
||||||
void *lout, int loff, int lincr,
|
void *lout, int loff, int lincr,
|
||||||
void *rout, int roff, int rincr)
|
void *rout, int roff, int rincr)
|
||||||
{
|
{
|
||||||
int i, j, k, cur;
|
int di, n, cur, size;
|
||||||
int16_t *left_out = lout;
|
int16_t *left_out = (int16_t *)lout + loff;
|
||||||
int16_t *right_out = rout;
|
int16_t *right_out = (int16_t *)rout + roff;
|
||||||
fluid_real_t *left_in;
|
fluid_real_t *left_in;
|
||||||
fluid_real_t *right_in;
|
fluid_real_t *right_in;
|
||||||
double time = fluid_utime();
|
double time = fluid_utime();
|
||||||
int di;
|
|
||||||
float cpu_load;
|
float cpu_load;
|
||||||
|
|
||||||
fluid_profile_ref_var(prof_ref);
|
fluid_profile_ref_var(prof_ref);
|
||||||
|
|
||||||
|
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(lout != NULL, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(rout != NULL, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len >= 0, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below
|
||||||
|
|
||||||
fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
|
fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 1);
|
||||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||||
|
|
||||||
|
size = len;
|
||||||
cur = synth->cur;
|
cur = synth->cur;
|
||||||
di = synth->dither_index;
|
di = synth->dither_index;
|
||||||
|
|
||||||
for(i = 0, j = loff, k = roff; i < len; i++, cur++, j += lincr, k += rincr)
|
do
|
||||||
{
|
{
|
||||||
|
|
||||||
/* fill up the buffers as needed */
|
/* fill up the buffers as needed */
|
||||||
if(cur >= synth->curmax)
|
if(cur >= synth->curmax)
|
||||||
{
|
{
|
||||||
int blocksleft = (len - i + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
|
int blocksleft = (size + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
|
||||||
synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
|
synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft);
|
||||||
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
|
||||||
cur = 0;
|
cur = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
left_out[j] = round_clip_to_i16(left_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + cur] * 32766.0f + rand_table[0][di]);
|
/* calculate amount of available samples */
|
||||||
right_out[k] = round_clip_to_i16(right_in[0 * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + cur] * 32766.0f + rand_table[1][di]);
|
n = synth->curmax - cur;
|
||||||
|
|
||||||
if(++di >= DITHER_SIZE)
|
/* keep track of emitted samples */
|
||||||
|
if(n > size)
|
||||||
{
|
{
|
||||||
di = 0;
|
n = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size -= n;
|
||||||
|
|
||||||
|
/* update pointers to current position */
|
||||||
|
left_in += cur + n;
|
||||||
|
right_in += cur + n;
|
||||||
|
|
||||||
|
/* set final cursor position */
|
||||||
|
cur += n;
|
||||||
|
|
||||||
|
/* reverse index */
|
||||||
|
n = 0 - n;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*left_out = round_clip_to_i16(left_in[n] * 32766.0f + rand_table[0][di]);
|
||||||
|
*right_out = round_clip_to_i16(right_in[n] * 32766.0f + rand_table[1][di]);
|
||||||
|
|
||||||
|
left_out += lincr;
|
||||||
|
right_out += rincr;
|
||||||
|
|
||||||
|
if(++di >= DITHER_SIZE)
|
||||||
|
{
|
||||||
|
di = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(++n < 0);
|
||||||
}
|
}
|
||||||
|
while(size);
|
||||||
|
|
||||||
synth->cur = cur;
|
synth->cur = cur;
|
||||||
synth->dither_index = di; /* keep dither buffer continous */
|
synth->dither_index = di; /* keep dither buffer continous */
|
||||||
|
|
@ -5185,9 +5284,9 @@ fluid_synth_set_chorus_on(fluid_synth_t *synth, int on)
|
||||||
* @param nr Chorus voice count (0-99, CPU time consumption proportional to
|
* @param nr Chorus voice count (0-99, CPU time consumption proportional to
|
||||||
* this value)
|
* this value)
|
||||||
* @param level Chorus level (0.0-10.0)
|
* @param level Chorus level (0.0-10.0)
|
||||||
* @param speed Chorus speed in Hz (0.29-5.0)
|
* @param speed Chorus speed in Hz (0.1-5.0)
|
||||||
* @param depth_ms Chorus depth (max value depends on synth sample rate,
|
* @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)
|
* 0.0-21.0 is safe for sample-rate values up to 96KHz)
|
||||||
* @param type Chorus waveform type (#fluid_chorus_mod)
|
* @param type Chorus waveform type (#fluid_chorus_mod)
|
||||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||||
*/
|
*/
|
||||||
|
|
@ -5243,19 +5342,6 @@ int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type)
|
||||||
return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_TYPE, 0, 0, 0, 0, type);
|
return fluid_synth_set_chorus_full(synth, FLUID_CHORUS_SET_TYPE, 0, 0, 0, 0, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set one or more chorus parameters.
|
|
||||||
* @param synth FluidSynth instance
|
|
||||||
* @param set Flags indicating which chorus parameters to set (#fluid_chorus_set_t)
|
|
||||||
* @param nr Chorus voice count (0-99, CPU time consumption proportional to
|
|
||||||
* this value)
|
|
||||||
* @param level Chorus level (0.0-10.0)
|
|
||||||
* @param speed Chorus speed in Hz (0.29-5.0)
|
|
||||||
* @param depth_ms Chorus depth (max value depends on synth sample rate,
|
|
||||||
* 0.0-21.0 is safe for sample rate values up to 96KHz)
|
|
||||||
* @param type Chorus waveform type (#fluid_chorus_mod)
|
|
||||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
|
||||||
*/
|
|
||||||
int
|
int
|
||||||
fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level,
|
fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level,
|
||||||
double speed, double depth_ms, int type)
|
double speed, double depth_ms, int type)
|
||||||
|
|
@ -5312,7 +5398,7 @@ fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level,
|
||||||
/**
|
/**
|
||||||
* Get chorus voice number (delay line count) value.
|
* Get chorus voice number (delay line count) value.
|
||||||
* @param synth FluidSynth instance
|
* @param synth FluidSynth instance
|
||||||
* @return Chorus voice count (0-99)
|
* @return Chorus voice count
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_synth_get_chorus_nr(fluid_synth_t *synth)
|
fluid_synth_get_chorus_nr(fluid_synth_t *synth)
|
||||||
|
|
@ -5328,7 +5414,7 @@ fluid_synth_get_chorus_nr(fluid_synth_t *synth)
|
||||||
/**
|
/**
|
||||||
* Get chorus level.
|
* Get chorus level.
|
||||||
* @param synth FluidSynth instance
|
* @param synth FluidSynth instance
|
||||||
* @return Chorus level value (0.0-10.0)
|
* @return Chorus level value
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
fluid_synth_get_chorus_level(fluid_synth_t *synth)
|
fluid_synth_get_chorus_level(fluid_synth_t *synth)
|
||||||
|
|
@ -5344,7 +5430,7 @@ fluid_synth_get_chorus_level(fluid_synth_t *synth)
|
||||||
/**
|
/**
|
||||||
* Get chorus speed in Hz.
|
* Get chorus speed in Hz.
|
||||||
* @param synth FluidSynth instance
|
* @param synth FluidSynth instance
|
||||||
* @return Chorus speed in Hz (0.29-5.0)
|
* @return Chorus speed in Hz
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
fluid_synth_get_chorus_speed(fluid_synth_t *synth)
|
fluid_synth_get_chorus_speed(fluid_synth_t *synth)
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,11 @@ int fluid_synth_set_gen2(fluid_synth_t *synth, int chan,
|
||||||
int
|
int
|
||||||
fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[],
|
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));
|
||||||
/*
|
/*
|
||||||
* misc
|
* misc
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,29 @@ fluid_log(int level, const char *fmt, ...)
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* fluid_alloc(size_t len)
|
||||||
|
{
|
||||||
|
void* ptr = malloc(len);
|
||||||
|
|
||||||
|
#if defined(DEBUG) && !defined(_MSC_VER)
|
||||||
|
// garbage initialize allocated memory for debug builds to ease reproducing
|
||||||
|
// bugs like 44453ff23281b3318abbe432fda90888c373022b .
|
||||||
|
//
|
||||||
|
// MSVC++ already garbage initializes allocated memory by itself (debug-heap).
|
||||||
|
//
|
||||||
|
// 0xCC because
|
||||||
|
// * it makes pointers reliably crash when dereferencing them,
|
||||||
|
// * floating points are still some valid but insanely huge negative number, and
|
||||||
|
// * if for whatever reason this allocated memory is executed, it'll trigger
|
||||||
|
// INT3 (...at least on x86)
|
||||||
|
if(ptr != NULL)
|
||||||
|
{
|
||||||
|
memset(ptr, 0xCC, len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience wrapper for free() that satisfies at least C90 requirements.
|
* 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().
|
* Especially useful when using fluidsynth with programming languages that do not provide malloc() and free().
|
||||||
|
|
@ -291,22 +314,21 @@ void fluid_msleep(unsigned int msecs)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get time in milliseconds to be used in relative timing operations.
|
* Get time in milliseconds to be used in relative timing operations.
|
||||||
* @return Unix time in milliseconds.
|
* @return Monotonic time in milliseconds.
|
||||||
*/
|
*/
|
||||||
unsigned int fluid_curtime(void)
|
unsigned int fluid_curtime(void)
|
||||||
{
|
{
|
||||||
static glong initial_seconds = 0;
|
float now;
|
||||||
GTimeVal timeval;
|
static float initial_time = 0;
|
||||||
|
|
||||||
if(initial_seconds == 0)
|
if(initial_time == 0)
|
||||||
{
|
{
|
||||||
g_get_current_time(&timeval);
|
initial_time = (float)fluid_utime();
|
||||||
initial_seconds = timeval.tv_sec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_get_current_time(&timeval);
|
now = (float)fluid_utime();
|
||||||
|
|
||||||
return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
|
return (unsigned int)((now - initial_time) / 1000.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1460,7 +1482,7 @@ static fluid_thread_return_t fluid_server_socket_run(void *data)
|
||||||
{
|
{
|
||||||
if(server_socket->cont)
|
if(server_socket->cont)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
|
FLUID_LOG(FLUID_ERR, "Failed to accept connection: %d", fluid_socket_get_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
server_socket->cont = 0;
|
server_socket->cont = 0;
|
||||||
|
|
@ -1519,7 +1541,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
|
||||||
|
|
||||||
if(sock == INVALID_SOCKET)
|
if(sock == INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
|
FLUID_LOG(FLUID_ERR, "Failed to create server socket: %d", fluid_socket_get_error());
|
||||||
fluid_socket_cleanup();
|
fluid_socket_cleanup();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1534,7 +1556,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
|
||||||
|
|
||||||
if(sock == INVALID_SOCKET)
|
if(sock == INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
|
FLUID_LOG(FLUID_ERR, "Failed to create server socket: %d", fluid_socket_get_error());
|
||||||
fluid_socket_cleanup();
|
fluid_socket_cleanup();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1547,7 +1569,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
|
||||||
|
|
||||||
if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
|
if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
|
FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %d", fluid_socket_get_error());
|
||||||
fluid_socket_close(sock);
|
fluid_socket_close(sock);
|
||||||
fluid_socket_cleanup();
|
fluid_socket_cleanup();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -1555,7 +1577,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
|
||||||
|
|
||||||
if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
|
if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
|
FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %d", fluid_socket_get_error());
|
||||||
fluid_socket_close(sock);
|
fluid_socket_close(sock);
|
||||||
fluid_socket_cleanup();
|
fluid_socket_cleanup();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,8 @@ typedef gint32 int32_t;
|
||||||
typedef guint32 uint32_t;
|
typedef guint32 uint32_t;
|
||||||
typedef gint64 int64_t;
|
typedef gint64 int64_t;
|
||||||
typedef guint64 uint64_t;
|
typedef guint64 uint64_t;
|
||||||
|
typedef guintptr uintptr_t;
|
||||||
|
typedef gintptr intptr_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -168,10 +170,14 @@ typedef guint64 uint64_t;
|
||||||
|
|
||||||
|
|
||||||
#define FLUID_INLINE inline
|
#define FLUID_INLINE inline
|
||||||
#define FLUID_POINTER_TO_UINT GPOINTER_TO_UINT
|
|
||||||
#define FLUID_UINT_TO_POINTER GUINT_TO_POINTER
|
/* Integer<->pointer conversion */
|
||||||
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
|
#define FLUID_POINTER_TO_UINT(x) ((unsigned int)(uintptr_t)(x))
|
||||||
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
|
#define FLUID_UINT_TO_POINTER(x) ((void *)(uintptr_t)(x))
|
||||||
|
#define FLUID_POINTER_TO_INT(x) ((signed int)(intptr_t)(x))
|
||||||
|
#define FLUID_INT_TO_POINTER(x) ((void *)(intptr_t)(x))
|
||||||
|
|
||||||
|
/* Endian detection */
|
||||||
#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)
|
#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)
|
||||||
|
|
||||||
#define FLUID_LE32TOH(x) GINT32_FROM_LE(x)
|
#define FLUID_LE32TOH(x) GINT32_FROM_LE(x)
|
||||||
|
|
@ -198,6 +204,11 @@ char *fluid_strtok(char **str, const char *delim);
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Time functions
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
unsigned int fluid_curtime(void);
|
unsigned int fluid_curtime(void);
|
||||||
double fluid_utime(void);
|
double fluid_utime(void);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -825,7 +825,7 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
|
||||||
voice->root_pitch = voice->sample->origpitch * 100.0f - voice->sample->pitchadj;
|
voice->root_pitch = voice->sample->origpitch * 100.0f - voice->sample->pitchadj;
|
||||||
}
|
}
|
||||||
|
|
||||||
x = (fluid_ct2hz(voice->root_pitch) * ((fluid_real_t) voice->output_rate / voice->sample->samplerate));
|
x = (fluid_ct2hz_real(voice->root_pitch) * ((fluid_real_t) voice->output_rate / voice->sample->samplerate));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -838,7 +838,7 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
|
||||||
voice->root_pitch = 0;
|
voice->root_pitch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
x = fluid_ct2hz(voice->root_pitch);
|
x = fluid_ct2hz_real(voice->root_pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* voice->pitch depends on voice->root_pitch, so calculate voice->pitch now */
|
/* voice->pitch depends on voice->root_pitch, so calculate voice->pitch now */
|
||||||
|
|
|
||||||
|
|
@ -181,12 +181,14 @@ typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t pa
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Memory allocation */
|
/* Memory allocation */
|
||||||
#define FLUID_MALLOC(_n) malloc(_n)
|
#define FLUID_MALLOC(_n) fluid_alloc(_n)
|
||||||
#define FLUID_REALLOC(_p,_n) realloc(_p,_n)
|
#define FLUID_REALLOC(_p,_n) realloc(_p,_n)
|
||||||
#define FLUID_NEW(_t) (_t*)malloc(sizeof(_t))
|
|
||||||
#define FLUID_ARRAY_ALIGNED(_t,_n,_a) (_t*)malloc((_n)*sizeof(_t) + ((unsigned int)_a - 1u))
|
|
||||||
#define FLUID_ARRAY(_t,_n) FLUID_ARRAY_ALIGNED(_t,_n,1u)
|
|
||||||
#define FLUID_FREE(_p) fluid_free(_p)
|
#define FLUID_FREE(_p) fluid_free(_p)
|
||||||
|
#define FLUID_NEW(_t) (_t*)FLUID_MALLOC(sizeof(_t))
|
||||||
|
#define FLUID_ARRAY_ALIGNED(_t,_n,_a) (_t*)FLUID_MALLOC((_n)*sizeof(_t) + ((unsigned int)_a - 1u))
|
||||||
|
#define FLUID_ARRAY(_t,_n) FLUID_ARRAY_ALIGNED(_t,_n,1u)
|
||||||
|
|
||||||
|
void* fluid_alloc(size_t len);
|
||||||
|
|
||||||
/* File access */
|
/* File access */
|
||||||
#define FLUID_FOPEN(_f,_m) fopen(_f,_m)
|
#define FLUID_FOPEN(_f,_m) fopen(_f,_m)
|
||||||
|
|
@ -273,7 +275,7 @@ do { strncpy(_dst,_src,_n); \
|
||||||
#define FLUID_LOG fluid_log
|
#define FLUID_LOG fluid_log
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#if defined(DEBUG) && !defined(NDEBUG)
|
||||||
#define FLUID_ASSERT(a) g_assert(a)
|
#define FLUID_ASSERT(a) g_assert(a)
|
||||||
#else
|
#else
|
||||||
#define FLUID_ASSERT(a)
|
#define FLUID_ASSERT(a)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,16 @@
|
||||||
diff --git b/libs/fluidsynth/fluidsynth/synth.h a/libs/fluidsynth/fluidsynth/synth.h
|
diff --git b/libs/fluidsynth/fluidsynth/synth.h a/libs/fluidsynth/fluidsynth/synth.h
|
||||||
index 369a2c2615..87826809fd 100644
|
index f4802ee5b9..3003972542 100644
|
||||||
--- b/libs/fluidsynth/fluidsynth/synth.h
|
--- b/libs/fluidsynth/fluidsynth/synth.h
|
||||||
+++ a/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);
|
||||||
|
|
||||||
|
/* Synthesis parameters */
|
||||||
|
|
||||||
|
-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
|
@@ -233,7 +233,7 @@ FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int p
|
||||||
/* Misc */
|
/* Misc */
|
||||||
|
|
||||||
|
|
@ -78,7 +87,7 @@ index 946a873bbf..79f83a4583 100644
|
||||||
/*
|
/*
|
||||||
* fluid_hashtable_foreach_remove_or_steal:
|
* fluid_hashtable_foreach_remove_or_steal:
|
||||||
diff --git b/libs/fluidsynth/src/fluid_midi.c a/libs/fluidsynth/src/fluid_midi.c
|
diff --git b/libs/fluidsynth/src/fluid_midi.c a/libs/fluidsynth/src/fluid_midi.c
|
||||||
index cd0d23ced3..c92fb2fefa 100644
|
index ea1aff5202..844de01c8f 100644
|
||||||
--- b/libs/fluidsynth/src/fluid_midi.c
|
--- b/libs/fluidsynth/src/fluid_midi.c
|
||||||
+++ a/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);
|
@@ -77,7 +77,7 @@ static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
|
||||||
|
|
@ -139,7 +148,7 @@ index 3e7661741f..ec8e967a35 100644
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void fluid_dump_modulator(fluid_mod_t *mod);
|
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
|
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.c a/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||||
index 85c3fb9142..5ea08ff6fa 100644
|
index 257f0fbdec..d7fd2f541f 100644
|
||||||
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||||
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||||
@@ -23,7 +23,6 @@
|
@@ -23,7 +23,6 @@
|
||||||
|
|
@ -191,7 +200,7 @@ index 78532ad2a3..a825603a44 100644
|
||||||
|
|
||||||
static int
|
static int
|
||||||
diff --git b/libs/fluidsynth/src/fluid_synth.c a/libs/fluidsynth/src/fluid_synth.c
|
diff --git b/libs/fluidsynth/src/fluid_synth.c a/libs/fluidsynth/src/fluid_synth.c
|
||||||
index 3f602b88d1..570a2535cd 100644
|
index e03c64089f..382979f7f5 100644
|
||||||
--- b/libs/fluidsynth/src/fluid_synth.c
|
--- b/libs/fluidsynth/src/fluid_synth.c
|
||||||
+++ a/libs/fluidsynth/src/fluid_synth.c
|
+++ a/libs/fluidsynth/src/fluid_synth.c
|
||||||
@@ -25,7 +25,6 @@
|
@@ -25,7 +25,6 @@
|
||||||
|
|
@ -202,7 +211,7 @@ index 3f602b88d1..570a2535cd 100644
|
||||||
|
|
||||||
#ifdef TRAP_ON_FPE
|
#ifdef TRAP_ON_FPE
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
@@ -263,7 +262,7 @@ void fluid_version(int *major, int *minor, int *micro)
|
@@ -262,7 +261,7 @@ void fluid_version(int *major, int *minor, int *micro)
|
||||||
* @return FluidSynth version string, which is internal and should not be
|
* @return FluidSynth version string, which is internal and should not be
|
||||||
* modified or freed.
|
* modified or freed.
|
||||||
*/
|
*/
|
||||||
|
|
@ -211,7 +220,7 @@ index 3f602b88d1..570a2535cd 100644
|
||||||
fluid_version_str(void)
|
fluid_version_str(void)
|
||||||
{
|
{
|
||||||
return FLUIDSYNTH_VERSION;
|
return FLUIDSYNTH_VERSION;
|
||||||
@@ -5472,7 +5471,7 @@ fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method)
|
@@ -5558,7 +5557,7 @@ fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method)
|
||||||
}
|
}
|
||||||
|
|
||||||
FLUID_API_RETURN(FLUID_OK);
|
FLUID_API_RETURN(FLUID_OK);
|
||||||
|
|
@ -220,7 +229,7 @@ index 3f602b88d1..570a2535cd 100644
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the total count of MIDI channels.
|
* Get the total count of MIDI channels.
|
||||||
@@ -6410,6 +6409,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
|
@@ -6496,6 +6495,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
|
||||||
FLUID_API_RETURN(FLUID_OK);
|
FLUID_API_RETURN(FLUID_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,7 +237,7 @@ index 3f602b88d1..570a2535cd 100644
|
||||||
/**
|
/**
|
||||||
* Return the LADSPA effects instance used by FluidSynth
|
* Return the LADSPA effects instance used by FluidSynth
|
||||||
*
|
*
|
||||||
@@ -6422,6 +6422,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
|
@@ -6508,6 +6508,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
|
||||||
|
|
||||||
return synth->ladspa_fx;
|
return synth->ladspa_fx;
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +246,7 @@ index 3f602b88d1..570a2535cd 100644
|
||||||
/**
|
/**
|
||||||
* Configure a general-purpose IIR biquad filter.
|
* Configure a general-purpose IIR biquad filter.
|
||||||
diff --git b/libs/fluidsynth/src/fluid_synth.h a/libs/fluidsynth/src/fluid_synth.h
|
diff --git b/libs/fluidsynth/src/fluid_synth.h a/libs/fluidsynth/src/fluid_synth.h
|
||||||
index 0b9758bad5..fe222f7b6f 100644
|
index b649bcf340..955b3fa12e 100644
|
||||||
--- b/libs/fluidsynth/src/fluid_synth.h
|
--- b/libs/fluidsynth/src/fluid_synth.h
|
||||||
+++ a/libs/fluidsynth/src/fluid_synth.h
|
+++ a/libs/fluidsynth/src/fluid_synth.h
|
||||||
@@ -33,8 +33,6 @@
|
@@ -33,8 +33,6 @@
|
||||||
|
|
@ -260,10 +269,10 @@ index 0b9758bad5..fe222f7b6f 100644
|
||||||
enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */
|
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
|
diff --git b/libs/fluidsynth/src/fluid_sys.c a/libs/fluidsynth/src/fluid_sys.c
|
||||||
index 8128fbba91..f6c56d3995 100644
|
index 7454217dd2..c6300b90c2 100644
|
||||||
--- b/libs/fluidsynth/src/fluid_sys.c
|
--- b/libs/fluidsynth/src/fluid_sys.c
|
||||||
+++ a/libs/fluidsynth/src/fluid_sys.c
|
+++ a/libs/fluidsynth/src/fluid_sys.c
|
||||||
@@ -216,9 +216,10 @@ void fluid_free(void* ptr)
|
@@ -239,9 +239,10 @@ void fluid_free(void* ptr)
|
||||||
* @param delim String of delimiter chars.
|
* @param delim String of delimiter chars.
|
||||||
* @return Pointer to the next token or NULL if no more tokens.
|
* @return Pointer to the next token or NULL if no more tokens.
|
||||||
*/
|
*/
|
||||||
|
|
@ -277,10 +286,10 @@ index 8128fbba91..f6c56d3995 100644
|
||||||
|
|
||||||
if(str == NULL || delim == NULL || !*delim)
|
if(str == NULL || delim == NULL || !*delim)
|
||||||
diff --git b/libs/fluidsynth/src/fluid_sys.h a/libs/fluidsynth/src/fluid_sys.h
|
diff --git b/libs/fluidsynth/src/fluid_sys.h a/libs/fluidsynth/src/fluid_sys.h
|
||||||
index 6490359027..3bc0c5a40f 100644
|
index 24df6edb5b..b747e5676a 100644
|
||||||
--- b/libs/fluidsynth/src/fluid_sys.h
|
--- b/libs/fluidsynth/src/fluid_sys.h
|
||||||
+++ a/libs/fluidsynth/src/fluid_sys.h
|
+++ a/libs/fluidsynth/src/fluid_sys.h
|
||||||
@@ -128,8 +128,9 @@ typedef guint64 uint64_t;
|
@@ -130,8 +130,9 @@ typedef gintptr intptr_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(WIN32) && HAVE_WINDOWS_H
|
#if defined(WIN32) && HAVE_WINDOWS_H
|
||||||
|
|
@ -292,7 +301,7 @@ index 6490359027..3bc0c5a40f 100644
|
||||||
|
|
||||||
/* WIN32 special defines */
|
/* WIN32 special defines */
|
||||||
#define STDIN_FILENO 0
|
#define STDIN_FILENO 0
|
||||||
@@ -187,7 +188,7 @@ typedef guint64 uint64_t;
|
@@ -193,7 +194,7 @@ typedef gintptr intptr_t;
|
||||||
/*
|
/*
|
||||||
* Utility functions
|
* Utility functions
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue