13
0

Update Fluidsynth to v2.0.3

see https://github.com/FluidSynth/fluidsynth/releases/tag/v2.0.3
This commit is contained in:
Robin Gareus 2019-01-02 15:33:23 +01:00
parent 754591e2ee
commit ac9329f907
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
22 changed files with 2521 additions and 1380 deletions

View File

@ -1,7 +1,14 @@
This is a stripped down version of fluidsynth (library only)
from git://github.com/FluidSynth/fluidsynth.git
rev. v2.0.2 (6e9d84f02a7a0f7e436c2adffc4a065608f490ba)
rev. v2.0.3-16-g8b18205
fluidsynth is licensed in terms of the LGPL-2+, see individual source
files for (C) holders.
---
The source is imported in the repository in order to allow static linking,
with hidden visibility. This is required for a-fluidsynth.lv2 (plugin must
be self-contained and not rely on external shared libs) and to make it
available to to libardour on all platforms that Ardour is.

View File

@ -53,8 +53,12 @@ FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *dat
int size, int dynamic);
FLUIDSYNTH_API int fluid_midi_event_set_text(fluid_midi_event_t *evt,
void *data, int size, int dynamic);
FLUIDSYNTH_API int fluid_midi_event_get_text(fluid_midi_event_t *evt,
void **data, int *size);
FLUIDSYNTH_API int fluid_midi_event_set_lyrics(fluid_midi_event_t *evt,
void *data, int size, int dynamic);
FLUIDSYNTH_API int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt,
void **data, int *size);
/**
* MIDI router rule type.

View File

@ -184,12 +184,10 @@ typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t *sfont);
/**
* Virtual SoundFont preset iteration function.
* @param sfont Virtual SoundFont
* @param preset Caller supplied uninitialized buffer to fill in with current preset information
* @return NULL when no more presets are available, otherwise the a pointer to the current preset
*
* Should store preset information to the caller supplied \a preset structure
* and advance the internal iteration state to the next preset for subsequent
* calls.
* Returns preset information to the caller. The returned buffer is only valid until a subsequent
* call to this function.
*/
typedef fluid_preset_t *(*fluid_sfont_iteration_next_t)(fluid_sfont_t *sfont);

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,7 @@ static long fluid_getlength(unsigned char *s);
*/
static char *fluid_file_read_full(fluid_file fp, size_t *length);
static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic);
static void fluid_midi_event_get_sysex_LOCAL(fluid_midi_event_t *evt, void **data, int *size);
#define READ_FULL_INITIAL_BUFLEN 1024
static fluid_track_t *new_fluid_track(int num);
@ -81,6 +82,41 @@ static int fluid_midi_file_get_division(fluid_midi_file *midifile);
* MIDIFILE
*/
/**
* Check if a file is a MIDI file.
* @param filename Path to the file to check
* @return TRUE if it could be a MIDI file, FALSE otherwise
*
* The current implementation only checks for the "MThd" header in the file.
* It is useful only to distinguish between SoundFont and MIDI files.
*/
int fluid_is_midifile(const char *filename)
{
FILE *fp = FLUID_FOPEN(filename, "rb");
uint32_t id;
int retcode = FALSE;
do
{
if(fp == NULL)
{
return retcode;
}
if(FLUID_FREAD(&id, sizeof(id), 1, fp) != 1)
{
break;
}
retcode = (id == FLUID_FOURCC('M', 'T', 'h', 'd'));
}
while(0);
FLUID_FCLOSE(fp);
return retcode;
}
/**
* Return a new MIDI file handle for parsing an already-loaded MIDI file.
* @internal
@ -1271,8 +1307,6 @@ fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val)
* should be freed when the event is freed (only applies if event gets destroyed
* with delete_fluid_midi_event())
* @return Always returns #FLUID_OK
*
* @note Unlike the other event assignment functions, this one sets evt->type.
*/
int
fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, int size, int dynamic)
@ -1291,7 +1325,6 @@ fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, int size, int dy
* @return Always returns #FLUID_OK
*
* @since 2.0.0
* @note Unlike the other event assignment functions, this one sets evt->type.
*/
int
fluid_midi_event_set_text(fluid_midi_event_t *evt, void *data, int size, int dynamic)
@ -1300,6 +1333,25 @@ fluid_midi_event_set_text(fluid_midi_event_t *evt, void *data, int size, int dyn
return FLUID_OK;
}
/**
* Get the text of a MIDI event structure.
* @param evt MIDI event structure
* @param data Pointer to return text data on.
* @param size Pointer to return text size on.
* @return Returns #FLUID_OK if \p data and \p size previously set by
* fluid_midi_event_set_text() have been successfully retrieved.
* Else #FLUID_FAILED is returned and \p data and \p size are not changed.
* @since 2.0.3
*/
int fluid_midi_event_get_text(fluid_midi_event_t *evt, void **data, int *size)
{
fluid_return_val_if_fail(evt != NULL, FLUID_FAILED);
fluid_return_val_if_fail(evt->type == MIDI_TEXT, FLUID_FAILED);
fluid_midi_event_get_sysex_LOCAL(evt, data, size);
return FLUID_OK;
}
/**
* Assign lyric data to a MIDI event structure.
* @param evt MIDI event structure
@ -1310,7 +1362,6 @@ fluid_midi_event_set_text(fluid_midi_event_t *evt, void *data, int size, int dyn
* @return Always returns #FLUID_OK
*
* @since 2.0.0
* @note Unlike the other event assignment functions, this one sets evt->type.
*/
int
fluid_midi_event_set_lyrics(fluid_midi_event_t *evt, void *data, int size, int dynamic)
@ -1319,6 +1370,25 @@ fluid_midi_event_set_lyrics(fluid_midi_event_t *evt, void *data, int size, int d
return FLUID_OK;
}
/**
* Get the lyric of a MIDI event structure.
* @param evt MIDI event structure
* @param data Pointer to return lyric data on.
* @param size Pointer to return lyric size on.
* @return Returns #FLUID_OK if \p data and \p size previously set by
* fluid_midi_event_set_lyrics() have been successfully retrieved.
* Else #FLUID_FAILED is returned and \p data and \p size are not changed.
* @since 2.0.3
*/
int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt, void **data, int *size)
{
fluid_return_val_if_fail(evt != NULL, FLUID_FAILED);
fluid_return_val_if_fail(evt->type == MIDI_LYRIC, FLUID_FAILED);
fluid_midi_event_get_sysex_LOCAL(evt, data, size);
return FLUID_OK;
}
static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic)
{
evt->type = type;
@ -1327,6 +1397,19 @@ static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type,
evt->param2 = dynamic;
}
static void fluid_midi_event_get_sysex_LOCAL(fluid_midi_event_t *evt, void **data, int *size)
{
if(data)
{
*data = evt->paramptr;
}
if(size)
{
*size = evt->param1;
}
}
/******************************************************
*
* fluid_track_t
@ -1598,7 +1681,7 @@ new_fluid_player(fluid_synth_t *synth)
fluid_settings_getint(synth->settings, "player.reset-synth", &i);
fluid_player_handle_reset_synth(player, NULL, i);
fluid_settings_callback_int(synth->settings, "player.reset-synth",
fluid_player_handle_reset_synth, player);

View File

@ -245,10 +245,7 @@ fluid_mod_get_source_value(const unsigned char mod_src,
static fluid_real_t
fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, const fluid_real_t range)
{
/* normalized value, i.e. usually in the range [0;1]
*
* if val was retrieved from pitch_bend then [-0.5;0.5]
*/
/* normalized value, i.e. usually in the range [0;1] */
const fluid_real_t val_norm = val / range;
/* we could also only switch case the lower nibble of mod_flags, however
@ -364,7 +361,22 @@ fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, cons
}
/*
* fluid_mod_get_value
* fluid_mod_get_value.
* Computes and return modulator output following SF2.01
* (See SoundFont Modulator Controller Model Chapter 9.5).
*
* Output = Transform(Amount * Map(primary source input) * Map(secondary source input))
*
* Notes:
* 1)fluid_mod_get_value, ignores the Transform operator. The result is:
*
* Output = Amount * Map(primary source input) * Map(secondary source input)
*
* 2)When primary source input (src1) is set to General Controller 'No Controller',
* output is forced to 0.
*
* 3)When secondary source input (src2) is set to General Controller 'No Controller',
* output is forced to +1.0
*/
fluid_real_t
fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
@ -418,6 +430,9 @@ fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
/* transform the input value */
v1 = fluid_mod_transform_source_value(v1, mod->flags1, range1);
}
/* When primary source input (src1) is set to General Controller 'No Controller',
output is forced to 0.0
*/
else
{
return 0.0;
@ -437,6 +452,9 @@ fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
/* transform the second input value */
v2 = fluid_mod_transform_source_value(v2, mod->flags2, range2);
}
/* When secondary source input (src2) is set to General Controller 'No Controller',
output is forced to +1.0
*/
else
{
v2 = 1.0f;
@ -486,6 +504,177 @@ size_t fluid_mod_sizeof()
return sizeof(fluid_mod_t);
}
/**
* Checks if modulator with source 1 other than CC is FLUID_MOD_NONE.
*
* @param mod, modulator.
* @return TRUE if modulator source 1 other than cc is FLUID_MOD_NONE, FALSE otherwise.
*/
static int
fluid_mod_is_src1_none(const fluid_mod_t *mod)
{
return(((mod->flags1 & FLUID_MOD_CC) == 0) && (mod->src1 == FLUID_MOD_NONE));
}
/**
* Checks if modulators source other than CC source is invalid.
* (specs SF 2.01 7.4, 7.8, 8.2.1)
*
* @param mod, modulator.
* @param src1_select, source input selection to check.
* 1 to check src1 source.
* 0 to check src2 source.
* @return FALSE if selected modulator source other than cc is invalid, TRUE otherwise.
*/
static int
fluid_mod_check_non_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
{
unsigned char flags, src;
if(src1_select)
{
flags = mod->flags1;
src = mod->src1;
}
else
{
flags = mod->flags2;
src = mod->src2;
}
return(((flags & FLUID_MOD_CC) != 0) /* src is a CC */
/* SF2.01 section 8.2.1: Constant value */
|| ((src == FLUID_MOD_NONE)
|| (src == FLUID_MOD_VELOCITY) /* Note-on velocity */
|| (src == FLUID_MOD_KEY) /* Note-on key number */
|| (src == FLUID_MOD_KEYPRESSURE) /* Poly pressure */
|| (src == FLUID_MOD_CHANNELPRESSURE) /* Channel pressure */
|| (src == FLUID_MOD_PITCHWHEEL) /* Pitch wheel */
|| (src == FLUID_MOD_PITCHWHEELSENS) /* Pitch wheel sensitivity */
));
}
/**
* Checks if modulator CC source is invalid (specs SF 2.01 7.4, 7.8, 8.2.1).
* @param mod, modulator.
* @src1_select, source input selection:
* 1 to check src1 source or
* 0 to check src2 source.
* @return FALSE if selected modulator's source CC is invalid, TRUE otherwise.
*/
static int
fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
{
unsigned char flags, src;
if(src1_select)
{
flags = mod->flags1;
src = mod->src1;
}
else
{
flags = mod->flags2;
src = mod->src2;
}
return(((flags & FLUID_MOD_CC) == 0) /* src is non CC */
|| ((src != BANK_SELECT_MSB)
&& (src != BANK_SELECT_LSB)
&& (src != DATA_ENTRY_MSB)
&& (src != DATA_ENTRY_LSB)
/* is src not NRPN_LSB, NRPN_MSB, RPN_LSB, RPN_MSB */
&& ((src < NRPN_LSB) || (RPN_MSB < src))
/* is src not ALL_SOUND_OFF, ALL_CTRL_OFF, LOCAL_CONTROL, ALL_NOTES_OFF ? */
/* is src not OMNI_OFF, OMNI_ON, POLY_OFF, POLY_ON ? */
&& (src < ALL_SOUND_OFF)
/* CC lsb shouldn't allowed to modulate (spec SF 2.01 - 8.2.1)
However, as long fluidsynth will use only CC 7 bits resolution,
it is safe to ignore these SF recommendations on CC receive.
See explanations in fluid_synth_cc_LOCAL() */
/* uncomment next line to forbid CC lsb */
/* && ((src < 32) || (63 < src)) */
));
}
/**
* Checks valid modulator sources (specs SF 2.01 7.4, 7.8, 8.2.1)
* @param mod, modulator.
* @param name,if not NULL, pointer on a string displayed as a warning.
* @return TRUE if modulator sources src1, src2 are valid, FALSE otherwise.
*/
int fluid_mod_check_sources(const fluid_mod_t *mod, const char *name)
{
static const char *invalid_non_cc_src =
"Invalid modulator, using non-CC source %s.src%d=%d";
static const char *invalid_cc_src =
"Invalid modulator, using CC source %s.src%d=%d";
static const char *src1_is_none =
"Modulator with source 1 none %s.src1=%d";
/* checks valid non cc sources */
if(!fluid_mod_check_non_cc_source(mod, 1)) /* check src1 */
{
if(name)
{
FLUID_LOG(FLUID_WARN, invalid_non_cc_src, name, 1, mod->src1);
}
return FALSE;
}
/*
When src1 is non CC source FLUID_MOD_NONE, the modulator is valid but
the output of this modulator will be forced to 0 at synthesis time.
Also this modulator cannot be used to overwrite a default modulator (as
there is no default modulator with src1 source equal to FLUID_MOD_NONE).
Consequently it is useful to return FALSE to indicate this modulator
being useless. It will be removed later with others invalid modulators.
*/
if(fluid_mod_is_src1_none(mod))
{
if(name)
{
FLUID_LOG(FLUID_WARN, src1_is_none, name, mod->src1);
}
return FALSE;
}
if(!fluid_mod_check_non_cc_source(mod, 0)) /* check src2 */
{
if(name)
{
FLUID_LOG(FLUID_WARN, invalid_non_cc_src, name, 2, mod->src2);
}
return FALSE;
}
/* checks valid cc sources */
if(!fluid_mod_check_cc_source(mod, 1)) /* check src1 */
{
if(name)
{
FLUID_LOG(FLUID_WARN, invalid_cc_src, name, 1, mod->src1);
}
return FALSE;
}
if(!fluid_mod_check_cc_source(mod, 0)) /* check src2 */
{
if(name)
{
FLUID_LOG(FLUID_WARN, invalid_cc_src, name, 2, mod->src2);
}
return FALSE;
}
return TRUE;
}
/**
* Checks if two modulators are identical in sources, flags and destination.
* @param mod1 First modulator

View File

@ -44,6 +44,7 @@ struct _fluid_mod_t
};
fluid_real_t fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice);
int fluid_mod_check_sources(const fluid_mod_t *mod, const char *name);
#ifdef DEBUG
void fluid_dump_modulator(fluid_mod_t *mod);

File diff suppressed because it is too large Load Diff

View File

@ -305,6 +305,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
{
int ticks = voice->envlfo.ticks;
int count, is_looping;
fluid_real_t modenv_val;
/******************* sample sanity check **********/
@ -361,6 +362,12 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
/******************* phase **********************/
/* SF2.04 section 8.1.2 #26:
* attack of modEnv is convex ?!?
*/
modenv_val = (fluid_adsr_env_get_section(&voice->envlfo.modenv) == FLUID_VOICE_ENVATTACK)
? fluid_convex(127 * fluid_adsr_env_get_val(&voice->envlfo.modenv))
: fluid_adsr_env_get_val(&voice->envlfo.modenv);
/* Calculate the number of samples, that the DSP loop advances
* through the original waveform with each step in the output
* buffer. It is the ratio between the frequencies of original
@ -369,7 +376,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
voice->dsp.pitchoffset +
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch
+ fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch
+ fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_pitch)
+ modenv_val * voice->envlfo.modenv_to_pitch)
/ voice->dsp.root_pitch_hz;
/******************* portamento ****************/
@ -455,7 +462,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);
modenv_val * voice->envlfo.modenv_to_fc);
fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);
@ -585,7 +592,7 @@ fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks)
/* A voice is turned off during the attack section of the volume
* envelope. The attack section ramps up linearly with
* amplitude. The other sections use logarithmic scaling. Calculate new
* volenv_val to achieve equievalent amplitude during the release phase
* volenv_val to achieve equivalent amplitude during the release phase
* for seamless volume transition.
*/
if(fluid_adsr_env_get_val(&voice->envlfo.volenv) > 0)
@ -598,6 +605,24 @@ fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks)
}
}
if(fluid_adsr_env_get_section(&voice->envlfo.modenv) == FLUID_VOICE_ENVATTACK)
{
/* A voice is turned off during the attack section of the modulation
* envelope. The attack section use convex scaling with pitch and filter
* frequency cutoff (see fluid_rvoice_write(): modenv_val = fluid_convex(127 * modenv.val)
* The other sections use linear scaling: modenv_val = modenv.val
*
* Calculate new modenv.val to achieve equivalent modenv_val during the release phase
* for seamless pitch and filter frequency cutoff transition.
*/
if(fluid_adsr_env_get_val(&voice->envlfo.modenv) > 0)
{
fluid_real_t env_value = fluid_convex(127 * fluid_adsr_env_get_val(&voice->envlfo.modenv));
fluid_clip(env_value, 0.0, 1.0);
fluid_adsr_env_set_val(&voice->envlfo.modenv, env_value);
}
}
fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVRELEASE);
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVRELEASE);
}
@ -650,11 +675,12 @@ static FLUID_INLINE void fluid_rvoice_local_retrigger_attack(fluid_rvoice_t *voi
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack)
{
fluid_rvoice_t *voice = obj;
int section = fluid_adsr_env_get_section(&voice->envlfo.volenv);
int section; /* volume or modulation section */
/*-------------------------------------------------------------------------
Section skip for volume envelope
--------------------------------------------------------------------------*/
section = fluid_adsr_env_get_section(&voice->envlfo.volenv);
if(section >= FLUID_VOICE_ENVHOLD)
{
/* DECAY, SUSTAIN,RELEASE section use logarithmic scaling. Calculates new
@ -672,16 +698,30 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack)
/* skips to Attack section from any section */
/* Update vol and attack data */
fluid_rvoice_local_retrigger_attack(voice);
/*-------------------------------------------------------------------------
Section skip for modulation envelope
--------------------------------------------------------------------------*/
section = fluid_adsr_env_get_section(&voice->envlfo.modenv);
if(section >= FLUID_VOICE_ENVHOLD)
{
/* DECAY, SUSTAIN,RELEASE section use linear scaling.
Since v 2.1 , as recommended by soundfont 2.01/2.4 spec, ATTACK section
uses convex shape (see fluid_rvoice_write() - fluid_convex()).
Calculate new modenv value (new_value) for seamless attack transition.
Here we need the inverse of fluid_convex() function defined as:
new_value = pow(10, (1 - current_val) . FLUID_PEAK_ATTENUATION / -200 . 2.0)
For performance reason we use fluid_cb2amp(Val) = pow(10, val/-200) with
val = (1 current_val) . FLUID_PEAK_ATTENUATION / 2.0
*/
fluid_real_t new_value; /* new modenv value */
new_value = fluid_cb2amp((1.0f - fluid_adsr_env_get_val(&voice->envlfo.modenv))
* FLUID_PEAK_ATTENUATION / 2.0);
fluid_clip(new_value, 0.0, 1.0);
fluid_adsr_env_set_val(&voice->envlfo.modenv, new_value);
}
/* Skips from any section to ATTACK section */
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVATTACK);
/* Actually (v 1.1.6) all sections are linear, so there is no need to
correct val value. However soundfont 2.01/2.4 spec. says that Attack should
be convex (see issue #153 from Christian Collins). In the case Attack
section would be changed to a non linear shape it will be necessary to do
a correction for seamless val transition. Here is the place to do this */
}
/**

View File

@ -60,8 +60,10 @@ struct _fluid_samplecache_entry_t
static fluid_list_t *samplecache_list = NULL;
static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT;
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start,
unsigned int sample_end, int sample_type, time_t mtime);
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start,
unsigned int sample_end, int sample_type, time_t mtime);
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
@ -75,14 +77,20 @@ int fluid_samplecache_load(SFData *sf,
{
fluid_samplecache_entry_t *entry;
int ret;
time_t mtime;
fluid_mutex_lock(samplecache_mutex);
entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type);
if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
{
mtime = 0;
}
entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime);
if(entry == NULL)
{
entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type);
entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime);
if(entry == NULL)
{
@ -180,7 +188,8 @@ unlock_exit:
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
unsigned int sample_start,
unsigned int sample_end,
int sample_type)
int sample_type,
time_t mtime)
{
fluid_samplecache_entry_t *entry;
@ -202,12 +211,6 @@ static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
goto error_exit;
}
if(fluid_get_file_modification_time(entry->filename, &entry->modification_time) == FLUID_FAILED)
{
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
entry->modification_time = 0;
}
entry->sf_samplepos = sf->samplepos;
entry->sf_samplesize = sf->samplesize;
entry->sf_sample24pos = sf->sample24pos;
@ -215,6 +218,7 @@ static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
entry->sample_start = sample_start;
entry->sample_end = sample_end;
entry->sample_type = sample_type;
entry->modification_time = mtime;
entry->sample_count = fluid_sffile_read_sample_data(sf, sample_start, sample_end, sample_type,
&entry->sample_data, &entry->sample_data24);
@ -244,18 +248,12 @@ static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
unsigned int sample_start,
unsigned int sample_end,
int sample_type)
int sample_type,
time_t mtime)
{
time_t mtime;
fluid_list_t *entry_list;
fluid_samplecache_entry_t *entry;
if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
{
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
mtime = 0;
}
entry_list = samplecache_list;
while(entry_list)

View File

@ -34,75 +34,79 @@
Borrowed from Smurf SoundFont Editor by Josh Green
=================================================================*/
/*
functions for loading data from sfont files, with appropriate byte swapping
on big endian machines. Sfont IDs are not swapped because the ID read is
equivalent to the matching ID list in memory regardless of LE/BE machine
*/
/* FOURCC definitions */
#define RIFF_FCC FLUID_FOURCC('R','I','F','F')
#define LIST_FCC FLUID_FOURCC('L','I','S','T')
#define SFBK_FCC FLUID_FOURCC('s','f','b','k')
#define INFO_FCC FLUID_FOURCC('I','N','F','O')
#define SDTA_FCC FLUID_FOURCC('s','d','t','a')
#define PDTA_FCC FLUID_FOURCC('p','d','t','a') /* info/sample/preset */
/* sf file chunk IDs */
enum
{
UNKN_ID,
RIFF_ID,
LIST_ID,
SFBK_ID,
INFO_ID,
SDTA_ID,
PDTA_ID, /* info/sample/preset */
#define IFIL_FCC FLUID_FOURCC('i','f','i','l')
#define ISNG_FCC FLUID_FOURCC('i','s','n','g')
#define INAM_FCC FLUID_FOURCC('I','N','A','M')
#define IROM_FCC FLUID_FOURCC('i','r','o','m') /* info ids (1st byte of info strings) */
#define IVER_FCC FLUID_FOURCC('i','v','e','r')
#define ICRD_FCC FLUID_FOURCC('I','C','R','D')
#define IENG_FCC FLUID_FOURCC('I','E','N','G')
#define IPRD_FCC FLUID_FOURCC('I','P','R','D') /* more info ids */
#define ICOP_FCC FLUID_FOURCC('I','C','O','P')
#define ICMT_FCC FLUID_FOURCC('I','C','M','T')
#define ISFT_FCC FLUID_FOURCC('I','S','F','T') /* and yet more info ids */
IFIL_ID,
ISNG_ID,
INAM_ID,
IROM_ID, /* info ids (1st byte of info strings) */
IVER_ID,
ICRD_ID,
IENG_ID,
IPRD_ID, /* more info ids */
ICOP_ID,
ICMT_ID,
ISFT_ID, /* and yet more info ids */
#define SNAM_FCC FLUID_FOURCC('s','n','a','m')
#define SMPL_FCC FLUID_FOURCC('s','m','p','l') /* sample ids */
#define PHDR_FCC FLUID_FOURCC('p','h','d','r')
#define PBAG_FCC FLUID_FOURCC('p','b','a','g')
#define PMOD_FCC FLUID_FOURCC('p','m','o','d')
#define PGEN_FCC FLUID_FOURCC('p','g','e','n') /* preset ids */
#define IHDR_FCC FLUID_FOURCC('i','n','s','t')
#define IBAG_FCC FLUID_FOURCC('i','b','a','g')
#define IMOD_FCC FLUID_FOURCC('i','m','o','d')
#define IGEN_FCC FLUID_FOURCC('i','g','e','n') /* instrument ids */
#define SHDR_FCC FLUID_FOURCC('s','h','d','r') /* sample info */
#define SM24_FCC FLUID_FOURCC('s','m','2','4')
SNAM_ID,
SMPL_ID, /* sample ids */
PHDR_ID,
PBAG_ID,
PMOD_ID,
PGEN_ID, /* preset ids */
IHDR_ID,
IBAG_ID,
IMOD_ID,
IGEN_ID, /* instrument ids */
SHDR_ID, /* sample info */
SM24_ID
};
/* Set when the FCC code is unknown */
#define UNKN_ID FLUID_N_ELEMENTS(idlist)
/*
* This declares a char array containing the SF2 chunk identifiers. This
* array is being accessed like an uint32 below to simplify id comparison.
* To make sure it is suitably aligned for uint32 access, we must wrap it
* inside a union along with a uint32 telling the compiler to align it
* for integer access and avoiding undefined behaviour.
* This basically is the C89 equivalent to what is written in C11 as:
* alignas(uint32_t) static const char idlist[] = {};
*
* See: EXP36-C. Do not cast pointers into more strictly aligned pointer
* types - SEI CERT C Coding Standard
* This declares a uint32_t array containing the SF2 chunk identifiers.
*/
static const union fluid_idlist
static const uint32_t idlist[] =
{
/*
* Cannot be char c[ ], because in C89, arrays wraped in unions
* must have a fixed size. Otherwise the size of the union would depend
* on the initialization of its first member, which results in
* different sizes for different instances of the same union type.
*/
char c[116];
uint32_t i;
} idlist = {"RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD"
"ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdrsm24"
};
RIFF_FCC,
LIST_FCC,
SFBK_FCC,
INFO_FCC,
SDTA_FCC,
PDTA_FCC,
IFIL_FCC,
ISNG_FCC,
INAM_FCC,
IROM_FCC,
IVER_FCC,
ICRD_FCC,
IENG_FCC,
IPRD_FCC,
ICOP_FCC,
ICMT_FCC,
ISFT_FCC,
SNAM_FCC,
SMPL_FCC,
PHDR_FCC,
PBAG_FCC,
PMOD_FCC,
PGEN_FCC,
IHDR_FCC,
IBAG_FCC,
IMOD_FCC,
IGEN_FCC,
SHDR_FCC,
SM24_FCC
};
/* generator types */
typedef enum
@ -205,8 +209,6 @@ static const unsigned short invalid_preset_gen[] =
};
#define CHNKIDSTR(id) &idlist.c[(id - 1) * 4]
/* sfont file chunk sizes */
#define SF_PHDR_SIZE (38)
#define SF_BAG_SIZE (4)
@ -322,6 +324,56 @@ static void delete_zone(SFZone *zone);
static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);
static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);
/**
* 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
* the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
*/
int fluid_is_soundfont(const char *filename)
{
FILE *fp = FLUID_FOPEN(filename, "rb");
uint32_t fcc;
int retcode = FALSE;
do
{
if(fp == NULL)
{
return retcode;
}
if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
{
break;
}
if(fcc != RIFF_FCC)
{
break;
}
if(FLUID_FSEEK(fp, 4, SEEK_CUR))
{
break;
}
if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
{
break;
}
retcode = (fcc == SFBK_FCC);
}
while(0);
FLUID_FCLOSE(fp);
return retcode;
}
/*
* Open a SoundFont file and parse it's contents into a SFData structure.
*
@ -511,17 +563,17 @@ void fluid_sffile_close(SFData *sf)
static int chunkid(uint32_t id)
{
unsigned int i;
const uint32_t *p = &idlist.i;
for(i = 0; i < sizeof(idlist) / sizeof(idlist.i); i++, p += 1)
for(i = 0; i < FLUID_N_ELEMENTS(idlist); i++)
{
if(*p == id)
if(idlist[i] == id)
{
return (i + 1);
break;
}
}
return UNKN_ID;
/* Return chunk id or UNKN_ID if not found */
return i;
}
static int load_header(SFData *sf)
@ -530,7 +582,7 @@ static int load_header(SFData *sf)
READCHUNK(sf, &chunk); /* load RIFF chunk */
if(chunkid(chunk.id) != RIFF_ID)
if(chunk.id != RIFF_FCC)
{
/* error if not RIFF */
FLUID_LOG(FLUID_ERR, "Not a RIFF file");
@ -539,7 +591,7 @@ static int load_header(SFData *sf)
READID(sf, &chunk.id); /* load file ID */
if(chunkid(chunk.id) != SFBK_ID)
if(chunk.id != SFBK_FCC)
{
/* error if not SFBK_ID */
FLUID_LOG(FLUID_ERR, "Not a SoundFont file");
@ -558,7 +610,7 @@ static int load_header(SFData *sf)
return FALSE;
}
if(chunkid(chunk.id) != INFO_ID)
if(chunk.id != INFO_FCC)
{
FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk");
return FALSE;
@ -575,7 +627,7 @@ static int load_header(SFData *sf)
return FALSE;
}
if(chunkid(chunk.id) != SDTA_ID)
if(chunk.id != SDTA_FCC)
{
FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk");
return FALSE;
@ -592,7 +644,7 @@ static int load_header(SFData *sf)
return FALSE;
}
if(chunkid(chunk.id) != PDTA_ID)
if(chunk.id != PDTA_FCC)
{
FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk");
return FALSE;
@ -637,7 +689,7 @@ static int read_listchunk(SFData *sf, SFChunk *chunk)
{
READCHUNK(sf, chunk); /* read list chunk */
if(chunkid(chunk->id) != LIST_ID) /* error if ! list chunk */
if(chunk->id != LIST_FCC) /* error if ! list chunk */
{
FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse");
return FALSE;
@ -651,8 +703,11 @@ static int read_listchunk(SFData *sf, SFChunk *chunk)
static int process_info(SFData *sf, int size)
{
SFChunk chunk;
unsigned char id;
char *item;
union
{
char *chr;
uint32_t *fcc;
} item;
unsigned short ver;
while(size > 0)
@ -660,9 +715,7 @@ static int process_info(SFData *sf, int size)
READCHUNK(sf, &chunk);
size -= 8;
id = chunkid(chunk.id);
if(id == IFIL_ID)
if(chunk.id == IFIL_FCC)
{
/* sound font version chunk? */
if(chunk.size != 4)
@ -703,7 +756,7 @@ static int process_info(SFData *sf, int size)
return FALSE;
}
}
else if(id == IVER_ID)
else if(chunk.id == IVER_FCC)
{
/* ROM version chunk? */
if(chunk.size != 4)
@ -717,34 +770,35 @@ static int process_info(SFData *sf, int size)
READW(sf, ver);
sf->romver.minor = ver;
}
else if(id != UNKN_ID)
else if(chunkid(chunk.id) != UNKN_ID)
{
if((id != ICMT_ID && 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",
&chunk.id, chunk.size);
return FALSE;
}
/* alloc for chunk id and da chunk */
if(!(item = FLUID_MALLOC(chunk.size + 1)))
/* alloc for chunk fcc and da chunk */
if(!(item.fcc = FLUID_MALLOC(chunk.size + sizeof(uint32_t) + 1)))
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return FALSE;
}
/* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */
sf->info = fluid_list_append(sf->info, item);
sf->info = fluid_list_append(sf->info, item.fcc);
*(unsigned char *)item = id;
/* save chunk fcc and update pointer to data value */
*item.fcc++ = chunk.id;
if(sf->fcbs->fread(&item[1], chunk.size, sf->sffd) == FLUID_FAILED)
if(sf->fcbs->fread(item.chr, chunk.size, sf->sffd) == FLUID_FAILED)
{
return FALSE;
}
/* force terminate info item (don't forget uint8 info ID) */
*(item + chunk.size) = '\0';
/* force terminate info item */
item.chr[chunk.size] = '\0';
}
else
{
@ -777,7 +831,7 @@ static int process_sdta(SFData *sf, unsigned int size)
READCHUNK(sf, &chunk);
size -= 8;
if(chunkid(chunk.id) != SMPL_ID)
if(chunk.id != SMPL_FCC)
{
FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead");
return FALSE;
@ -810,7 +864,7 @@ static int process_sdta(SFData *sf, unsigned int size)
READCHUNK(sf, &chunk);
size -= 8;
if(chunkid(chunk.id) == SM24_ID)
if(chunk.id == SM24_FCC)
{
int sm24size, sdtahalfsize;
@ -850,29 +904,24 @@ ret:
static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size)
{
unsigned int id;
const char *expstr;
expstr = CHNKIDSTR(expid); /* in case we need it */
READCHUNK(sf, chunk);
*size -= 8;
if((id = chunkid(chunk->id)) != expid)
if(chunk->id != expid)
{
FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", expstr);
FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", &expid);
return FALSE;
}
if(chunk->size % reclen) /* valid chunk size? */
{
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", expstr, reclen);
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", &expid, reclen);
return FALSE;
}
if((*size -= chunk->size) < 0)
{
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", expstr);
FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", &expid);
return FALSE;
}
@ -883,7 +932,7 @@ static int process_pdta(SFData *sf, int size)
{
SFChunk chunk;
if(!pdtahelper(sf, PHDR_ID, SF_PHDR_SIZE, &chunk, &size))
if(!pdtahelper(sf, PHDR_FCC, SF_PHDR_SIZE, &chunk, &size))
{
return FALSE;
}
@ -893,7 +942,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, PBAG_ID, SF_BAG_SIZE, &chunk, &size))
if(!pdtahelper(sf, PBAG_FCC, SF_BAG_SIZE, &chunk, &size))
{
return FALSE;
}
@ -903,7 +952,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, PMOD_ID, SF_MOD_SIZE, &chunk, &size))
if(!pdtahelper(sf, PMOD_FCC, SF_MOD_SIZE, &chunk, &size))
{
return FALSE;
}
@ -913,7 +962,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, PGEN_ID, SF_GEN_SIZE, &chunk, &size))
if(!pdtahelper(sf, PGEN_FCC, SF_GEN_SIZE, &chunk, &size))
{
return FALSE;
}
@ -923,7 +972,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, IHDR_ID, SF_IHDR_SIZE, &chunk, &size))
if(!pdtahelper(sf, IHDR_FCC, SF_IHDR_SIZE, &chunk, &size))
{
return FALSE;
}
@ -933,7 +982,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, IBAG_ID, SF_BAG_SIZE, &chunk, &size))
if(!pdtahelper(sf, IBAG_FCC, SF_BAG_SIZE, &chunk, &size))
{
return FALSE;
}
@ -943,7 +992,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, IMOD_ID, SF_MOD_SIZE, &chunk, &size))
if(!pdtahelper(sf, IMOD_FCC, SF_MOD_SIZE, &chunk, &size))
{
return FALSE;
}
@ -953,7 +1002,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, IGEN_ID, SF_GEN_SIZE, &chunk, &size))
if(!pdtahelper(sf, IGEN_FCC, SF_GEN_SIZE, &chunk, &size))
{
return FALSE;
}
@ -963,7 +1012,7 @@ static int process_pdta(SFData *sf, int size)
return FALSE;
}
if(!pdtahelper(sf, SHDR_ID, SF_SHDR_SIZE, &chunk, &size))
if(!pdtahelper(sf, SHDR_FCC, SF_SHDR_SIZE, &chunk, &size))
{
return FALSE;
}

View File

@ -512,9 +512,13 @@ delete_fluid_sample(fluid_sample_t *sample)
/**
* Returns the size of the fluid_sample_t structure.
*
* Useful in low latency scenarios e.g. to allocate a sample on the stack.
* Useful in low latency scenarios e.g. to allocate a pool of samples.
*
* @return Size of fluid_sample_t in bytes
*
* @note It is recommend to zero initialize the memory before using the object.
*
* @warning Do NOT allocate samples on the stack and assign them to a voice!
*/
size_t fluid_sample_sizeof()
{
@ -563,16 +567,17 @@ fluid_sample_set_sound_data(fluid_sample_t *sample,
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
fluid_return_val_if_fail(data != NULL, FLUID_FAILED);
fluid_return_val_if_fail(nbframes == 0, FLUID_FAILED);
fluid_return_val_if_fail(nbframes != 0, FLUID_FAILED);
/* in case we already have some data */
if((sample->data != NULL || sample->data24 != NULL) && sample->auto_free)
{
FLUID_FREE(sample->data);
FLUID_FREE(sample->data24);
sample->data = NULL;
sample->data24 = NULL;
}
sample->data = NULL;
sample->data24 = NULL;
if(copy_data)
{
@ -635,6 +640,8 @@ error_rec:
FLUID_LOG(FLUID_ERR, "Out of memory");
FLUID_FREE(sample->data);
FLUID_FREE(sample->data24);
sample->data = NULL;
sample->data24 = NULL;
return FLUID_FAILED;
#undef SAMPLE_LOOP_MARGIN

View File

@ -183,8 +183,6 @@ struct _fluid_sample_t
* @return Should return #FLUID_OK
*/
int (*notify)(fluid_sample_t *sample, int reason);
void *userdata; /**< User defined data */
};

View File

@ -227,7 +227,7 @@ void fluid_synth_settings(fluid_settings_t *settings)
#else
fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 1, 0);
#endif
fluid_settings_register_int(settings, "synth.min-note-length", 10, 0, 65535, 0);
fluid_settings_register_int(settings, "synth.threadsafe-api", 1, 0, 1, FLUID_HINT_TOGGLED);
@ -1331,6 +1331,13 @@ fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mo
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail(mod != NULL, FLUID_FAILED);
/* Checks if modulators sources are valid */
if(!fluid_mod_check_sources(mod, "api fluid_synth_add_default_mod mod"))
{
return FLUID_FAILED;
}
fluid_synth_api_enter(synth);
default_mod = synth->default_mod;
@ -1902,7 +1909,7 @@ fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, int len,
int bank = 0, prog, channels;
double tunedata[128];
int keys[128];
char name[17];
char name[17]={0};
int note, frac, frac2;
uint8_t chksum;
int i, count, index;
@ -1973,7 +1980,8 @@ fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, int len,
}
*resptr++ = prog;
FLUID_STRNCPY(resptr, name, 16);
/* copy 16 ASCII characters (potentially not null terminated) to the sysex buffer */
FLUID_MEMCPY(resptr, name, 16);
resptr += 16;
for(i = 0; i < 128; i++)
@ -3368,7 +3376,7 @@ fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
fluid_return_val_if_fail(left != NULL, FLUID_FAILED);
fluid_return_val_if_fail(right != NULL, FLUID_FAILED);
/* First, take what's still available in the buffer */
count = 0;
num = synth->cur;
@ -3521,7 +3529,7 @@ fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
/**
* mixes the samples of \p in to \p out
*
*
* @param out the output sample buffer to mix to
* @param ooff sample offset in \p out
* @param in the rvoice_mixer input sample buffer to mix from
@ -3539,6 +3547,7 @@ static FLUID_INLINE void fluid_synth_mix_single_buffer(float *FLUID_RESTRICT out
if(out != NULL)
{
int j;
for(j = 0; j < num; j++)
{
out[j + ooff] += (float) in[buf_idx * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + ioff];
@ -3687,7 +3696,7 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
for(i = 0; i < nfxchan; i++)
{
int buf_idx = f * nfxchan + i;
float *out_buf = fx[(buf_idx * 2) % nfx];
fluid_synth_mix_single_buffer(out_buf, 0, fx_left_in, synth->cur, buf_idx, num);
@ -3730,10 +3739,10 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
for(i = 0; i < nfxchan; i++)
{
int buf_idx = f * nfxchan + i;
float *out_buf = fx[(buf_idx * 2) % nfx];
fluid_synth_mix_single_buffer(out_buf, count, fx_left_in, 0, buf_idx, num);
out_buf = fx[(buf_idx * 2 + 1) % nfx];
fluid_synth_mix_single_buffer(out_buf, count, fx_right_in, 0, buf_idx, num);
}
@ -3784,7 +3793,7 @@ fluid_synth_write_float(fluid_synth_t *synth, int len,
float cpu_load;
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);
@ -3853,10 +3862,12 @@ static FLUID_INLINE int16_t
round_clip_to_i16(float x)
{
long i;
if(x >= 0.0f)
{
i = (long)(x + 0.5f);
if (FLUID_UNLIKELY(i > 32767))
if(FLUID_UNLIKELY(i > 32767))
{
i = 32767;
}
@ -3864,12 +3875,13 @@ round_clip_to_i16(float x)
else
{
i = (long)(x - 0.5f);
if (FLUID_UNLIKELY(i < -32768))
if(FLUID_UNLIKELY(i < -32768))
{
i = -32768;
}
}
return (int16_t)i;
}
@ -4347,11 +4359,11 @@ fluid_synth_alloc_voice_LOCAL(fluid_synth_t *synth, fluid_sample_t *sample, int
)
{
// Replacement of default_vel2att modulator by custom_breath2att_modulator
fluid_voice_add_mod(voice, &custom_breath2att_mod, FLUID_VOICE_DEFAULT);
fluid_voice_add_mod_local(voice, &custom_breath2att_mod, FLUID_VOICE_DEFAULT, 0);
}
else
{
fluid_voice_add_mod(voice, default_mod, FLUID_VOICE_DEFAULT);
fluid_voice_add_mod_local(voice, default_mod, FLUID_VOICE_DEFAULT, 0);
}
// Next default modulator to add to the voice

View File

@ -275,71 +275,6 @@ fluid_error()
return fluid_errbuf;
}
/**
* Check if a file is a MIDI file.
* @param filename Path to the file to check
* @return TRUE if it could be a MIDI file, FALSE otherwise
*
* The current implementation only checks for the "MThd" header in the file.
* It is useful only to distinguish between SoundFont and MIDI files.
*/
int
fluid_is_midifile(const char *filename)
{
FILE *fp = fopen(filename, "rb");
char id[4];
if(fp == NULL)
{
return 0;
}
if(fread((void *) id, 1, 4, fp) != 4)
{
fclose(fp);
return 0;
}
fclose(fp);
return FLUID_STRNCMP(id, "MThd", 4) == 0;
}
/**
* 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
* the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
*/
int
fluid_is_soundfont(const char *filename)
{
FILE *fp = fopen(filename, "rb");
char riff_id[4], sfbk_id[4];
if(fp == NULL)
{
return 0;
}
if((fread((void *) riff_id, 1, sizeof(riff_id), fp) != sizeof(riff_id)) ||
(fseek(fp, 4, SEEK_CUR) != 0) ||
(fread((void *) sfbk_id, 1, sizeof(sfbk_id), fp) != sizeof(sfbk_id)))
{
goto error_rec;
}
fclose(fp);
return (FLUID_STRNCMP(riff_id, "RIFF", sizeof(riff_id)) == 0) &&
(FLUID_STRNCMP(sfbk_id, "sfbk", sizeof(sfbk_id)) == 0);
error_rec:
fclose(fp);
return 0;
}
/**
* Suspend the execution of the current thread for the specified amount of time.
* @param milliseconds to wait.
@ -1280,7 +1215,11 @@ fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt,
FLUID_SNPRINTF(buf, len, "%s", line);
buf[len - 1] = 0;
add_history(buf);
if(buf[0] != '\0')
{
add_history(buf);
}
free(line);
return 1;

View File

@ -77,6 +77,14 @@
#define FLUID_LE32TOH(x) GINT32_FROM_LE(x)
#define FLUID_LE16TOH(x) GINT16_FROM_LE(x)
#if FLUID_IS_BIG_ENDIAN
#define FLUID_FOURCC(_a, _b, _c, _d) \
(uint32_t)(((uint32_t)(_a) << 24) | ((uint32_t)(_b) << 16) | ((uint32_t)(_c) << 8) | (uint32_t)(_d))
#else
#define FLUID_FOURCC(_a, _b, _c, _d) \
(uint32_t)(((uint32_t)(_d) << 24) | ((uint32_t)(_c) << 16) | ((uint32_t)(_b) << 8) | (uint32_t)(_a))
#endif
#define fluid_return_if_fail(cond) \
if(cond) \

View File

@ -516,7 +516,6 @@ fluid_voice_calculate_gen_pitch(fluid_voice_t *voice)
voice->gen[GEN_PITCH].val = fluid_voice_calculate_pitch(voice, fluid_voice_get_actual_key(voice));
}
/*
* fluid_voice_calculate_runtime_synthesis_parameters
*
@ -1153,7 +1152,9 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
* Recalculate voice parameters for a given control.
* @param voice the synthesis voice
* @param cc flag to distinguish between a continous control and a channel control (pitch bend, ...)
* @param ctrl the control number
* @param ctrl the control number:
* when >=0, only modulators's destination having ctrl as source are updated.
* when -1, all modulators's destination are updated (regardless of ctrl).
*
* In this implementation, I want to make sure that all controllers
* are event based: the parameter values of the DSP algorithm should
@ -1161,57 +1162,83 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
* iteration of the audio cycle (which would probably be feasible if
* the synth was made in silicon).
*
* The update is done in three steps:
* The update is done in two steps:
*
* - first, we look for all the modulators that have the changed
* controller as a source. This will yield a list of generators that
* will be changed because of the controller event.
* - step 1: first, we look for all the modulators that have the changed
* controller as a source. This will yield a generator that will be changed
* because of the controller event.
*
* - For every changed generator, calculate its new value. This is the
* sum of its original value plus the values of al the attached
* modulators.
*
* - For every changed generator, convert its value to the correct
* unit of the corresponding DSP parameter
* - step 2: For this generator, calculate its new value. This is the
* sum of its original value plus the values of all the attached modulators.
* The generator flag is set to indicate the parameters must be updated.
* This avoid the risk to call 'fluid_voice_update_param' several
* times for the same generator if several modulators have that generator as
* destination. So every changed generators are updated only once.
*/
/* bit table for each generator being updated. The bits are packed in variables
Each variable have NBR_BIT_BY_VAR bits represented by NBR_BIT_BY_VAR_LN2.
The size of the table is the number of variables: SIZE_UPDATED_GEN_BIT.
Note: In this implementation NBR_BIT_BY_VAR_LN2 is set to 5 (convenient for 32 bits cpu)
but this could be set to 6 for 64 bits cpu.
*/
#define NBR_BIT_BY_VAR_LN2 5 /* for 32 bits variables */
#define NBR_BIT_BY_VAR (1 << NBR_BIT_BY_VAR_LN2)
#define NBR_BIT_BY_VAR_ANDMASK (NBR_BIT_BY_VAR - 1)
#define SIZE_UPDATED_GEN_BIT ((GEN_LAST + NBR_BIT_BY_VAR_ANDMASK) / NBR_BIT_BY_VAR)
#define is_gen_updated(bit,gen) (bit[gen >> NBR_BIT_BY_VAR_LN2] & (1 << (gen & NBR_BIT_BY_VAR_ANDMASK)))
#define set_gen_updated(bit,gen) (bit[gen >> NBR_BIT_BY_VAR_LN2] |= (1 << (gen & NBR_BIT_BY_VAR_ANDMASK)))
int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
{
int i, k;
fluid_mod_t *mod;
int gen;
uint32_t gen;
fluid_real_t modval;
/* Clears registered bits table of updated generators */
uint32_t updated_gen_bit[SIZE_UPDATED_GEN_BIT] = {0};
/* printf("Chan=%d, CC=%d, Src=%d, Val=%d\n", voice->channel->channum, cc, ctrl, val); */
for(i = 0; i < voice->mod_count; i++)
{
mod = &voice->mod[i];
/* step 1: find all the modulators that have the changed controller
* as input source. */
if(fluid_mod_has_source(mod, cc, ctrl))
as input source. When ctrl is -1 all modulators destination
are updated */
if(ctrl < 0 || fluid_mod_has_source(mod, cc, ctrl))
{
gen = fluid_mod_get_dest(mod);
modval = 0.0;
/* step 2: for every changed modulator, calculate the modulation
* value of its associated generator */
for(k = 0; k < voice->mod_count; k++)
/* Skip if this generator has already been updated */
if(!is_gen_updated(updated_gen_bit, gen))
{
if(fluid_mod_has_dest(&voice->mod[k], gen))
modval = 0.0;
/* step 2: for every attached modulator, calculate the modulation
* value for the generator gen */
for(k = 0; k < voice->mod_count; k++)
{
modval += fluid_mod_get_value(&voice->mod[k], voice);
if(fluid_mod_has_dest(&voice->mod[k], gen))
{
modval += fluid_mod_get_value(&voice->mod[k], voice);
}
}
fluid_gen_set_mod(&voice->gen[gen], modval);
/* now recalculate the parameter values that are derived from the
generator */
fluid_voice_update_param(voice, gen);
/* set the bit that indicates this generator is updated */
set_gen_updated(updated_gen_bit, gen);
}
fluid_gen_set_mod(&voice->gen[gen], modval);
/* step 3: now that we have the new value of the generator,
* recalculate the parameter values that are derived from the
* generator */
fluid_voice_update_param(voice, gen);
}
}
@ -1222,47 +1249,11 @@ int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
* Update all the modulators. This function is called after a
* ALL_CTRL_OFF MIDI message has been received (CC 121).
*
* All destination of all modulators must be updated.
*/
int fluid_voice_modulate_all(fluid_voice_t *voice)
{
fluid_mod_t *mod;
int i, k, gen;
fluid_real_t modval;
/* Loop through all the modulators.
FIXME: we should loop through the set of generators instead of
the set of modulators. We risk to call 'fluid_voice_update_param'
several times for the same generator if several modulators have
that generator as destination. It's not an error, just a wast of
energy (think polution, global warming, unhappy musicians,
...) */
for(i = 0; i < voice->mod_count; i++)
{
mod = &voice->mod[i];
gen = fluid_mod_get_dest(mod);
modval = 0.0;
/* Accumulate the modulation values of all the modulators with
* destination generator 'gen' */
for(k = 0; k < voice->mod_count; k++)
{
if(fluid_mod_has_dest(&voice->mod[k], gen))
{
modval += fluid_mod_get_value(&voice->mod[k], voice);
}
}
fluid_gen_set_mod(&voice->gen[gen], modval);
/* Update the parameter values that are depend on the generator
* 'gen' */
fluid_voice_update_param(voice, gen);
}
return FLUID_OK;
return fluid_voice_modulate(voice, 0, -1);
}
/** legato update functions --------------------------------------------------*/
@ -1474,10 +1465,10 @@ fluid_voice_stop(fluid_voice_t *voice)
}
/**
* Adds a modulator to the voice.
* @param voice Voice instance
* @param mod Modulator info (copied)
* @param mode Determines how to handle an existing identical modulator
* Adds a modulator to the voice if the modulator has valid sources.
* @param voice Voice instance.
* @param mod Modulator info (copied).
* @param mode Determines how to handle an existing identical modulator.
* #FLUID_VOICE_ADD to add (offset) the modulator amounts,
* #FLUID_VOICE_OVERWRITE to replace the modulator,
* #FLUID_VOICE_DEFAULT when adding a default modulator - no duplicate should
@ -1485,33 +1476,43 @@ fluid_voice_stop(fluid_voice_t *voice)
*/
void
fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode)
{
/* Ignore the modulator if its sources inputs are invalid */
if(fluid_mod_check_sources(mod, "api fluid_voice_add_mod mod"))
{
fluid_voice_add_mod_local(voice, mod, mode, FLUID_NUM_MOD);
}
}
/**
* Adds a modulator to the voice.
* local version of fluid_voice_add_mod function. Called at noteon time.
* @param voice, mod, mode, same as for fluid_voice_add_mod() (see above).
* @param check_limit_count is the modulator number limit to handle with existing
* identical modulator(i.e mode FLUID_VOICE_OVERWRITE, FLUID_VOICE_ADD).
* - When FLUID_NUM_MOD, all the voices modulators (since the previous call)
* are checked for identity.
* - When check_count_limit is below the actual number of voices modulators
* (voice->mod_count), this will restrict identity check to this number,
* This is usefull when we know by advance that there is no duplicate with
* modulators at index above this limit. This avoid wasting cpu cycles at noteon.
*/
void
fluid_voice_add_mod_local(fluid_voice_t *voice, fluid_mod_t *mod, int mode, int check_limit_count)
{
int i;
/*
* Some soundfonts come with a huge number of non-standard
* controllers, because they have been designed for one particular
* sound card. Discard them, maybe print a warning.
*/
if(((mod->flags1 & FLUID_MOD_CC) == 0)
&& ((mod->src1 != FLUID_MOD_NONE) /* SF2.01 section 8.2.1: Constant value */
&& (mod->src1 != FLUID_MOD_VELOCITY) /* Note-on velocity */
&& (mod->src1 != FLUID_MOD_KEY) /* Note-on key number */
&& (mod->src1 != FLUID_MOD_KEYPRESSURE) /* Poly pressure */
&& (mod->src1 != FLUID_MOD_CHANNELPRESSURE) /* Channel pressure */
&& (mod->src1 != FLUID_MOD_PITCHWHEEL) /* Pitch wheel */
&& (mod->src1 != FLUID_MOD_PITCHWHEELSENS)))/* Pitch wheel sensitivity */
/* check_limit_count cannot be above voice->mod_count */
if(check_limit_count > voice->mod_count)
{
FLUID_LOG(FLUID_WARN, "Ignoring invalid controller, using non-CC source %i.", mod->src1);
return;
check_limit_count = voice->mod_count;
}
if(mode == FLUID_VOICE_ADD)
{
/* if identical modulator exists, add them */
for(i = 0; i < voice->mod_count; i++)
for(i = 0; i < check_limit_count; i++)
{
if(fluid_mod_test_identity(&voice->mod[i], mod))
{
@ -1526,7 +1527,7 @@ fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode)
{
/* if identical modulator exists, replace it (only the amount has to be changed) */
for(i = 0; i < voice->mod_count; i++)
for(i = 0; i < check_limit_count; i++)
{
if(fluid_mod_test_identity(&voice->mod[i], mod))
{
@ -1704,9 +1705,10 @@ int fluid_voice_get_velocity(const fluid_voice_t *voice)
* A lower boundary for the attenuation (as in 'the minimum
* attenuation of this voice, with volume pedals, modulators
* etc. resulting in minimum attenuation, cannot fall below x cB) is
* calculated. This has to be called during fluid_voice_init, after
* calculated. This has to be called during fluid_voice_start, after
* all modulators have been run on the voice once. Also,
* voice->attenuation has to be initialized.
* (see fluid_voice_calculate_runtime_synthesis_parameters())
*/
static fluid_real_t
fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t *voice)
@ -1733,30 +1735,42 @@ fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t *voice)
{
fluid_real_t current_val = fluid_mod_get_value(mod, voice);
fluid_real_t v = fabs(mod->amount);
/* min_val is the possible minimum value for this modulator.
it depends of 3 things :
1)the minimum values of src1,src2 (i.e -1 if mapping is bipolar
or 0 if mapping is unipolar).
2)the sign of amount.
3)absolute value of amount.
if((mod->src1 == FLUID_MOD_PITCHWHEEL)
|| (mod->flags1 & FLUID_MOD_BIPOLAR)
When at least one source mapping is bipolar:
min_val is -|amount| regardless the sign of amount.
When both sources mapping are unipolar:
min_val is -|amount|, if amount is negative.
min_val is 0, if amount is positive
*/
fluid_real_t min_val = fabs(mod->amount);
/* Can this modulator produce a negative contribution? */
if((mod->flags1 & FLUID_MOD_BIPOLAR)
|| (mod->flags2 & FLUID_MOD_BIPOLAR)
|| (mod->amount < 0))
{
/* Can this modulator produce a negative contribution? */
v *= -1.0;
min_val *= -1.0; /* min_val = - |amount|*/
}
else
{
/* No negative value possible. But still, the minimum contribution is 0. */
v = 0;
min_val = 0;
}
/* For example:
* - current_val=100
* - min_val=-4000
* - possible_att_reduction_cB += 4100
* - possible reduction contribution of this modulator = current_val - min_val = 4100
*/
if(current_val > v)
if(current_val > min_val)
{
possible_att_reduction_cB += (current_val - v);
possible_att_reduction_cB += (current_val - min_val);
}
}
}

View File

@ -157,6 +157,7 @@ void fluid_voice_release(fluid_voice_t *voice);
void fluid_voice_noteoff(fluid_voice_t *voice);
void fluid_voice_off(fluid_voice_t *voice);
void fluid_voice_stop(fluid_voice_t *voice);
void fluid_voice_add_mod_local(fluid_voice_t *voice, fluid_mod_t *mod, int mode, int check_limit_count);
void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice);
int fluid_voice_kill_excl(fluid_voice_t *voice);

View File

@ -103,7 +103,7 @@
#endif
#if HAVE_IO_H
#include <io.h>
#include <io.h> // _open(), _close(), read(), write() on windows
#endif
#if HAVE_SIGNAL_H
@ -262,7 +262,7 @@ typedef FILE *fluid_file;
#define FLUID_STRNCPY(_dst,_src,_n) \
do { strncpy(_dst,_src,_n); \
(_dst)[(_n)-1]=0; \
(_dst)[(_n)-1]='\0'; \
}while(0)
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)

View File

@ -65,7 +65,7 @@ def build(bld):
'src/fluid_synth_monopoly.c',
'src/fluid_sys.c'
],
cflags = [ bld.env['compiler_flags_dict']['pic'], '-fvisibility=hidden', '-std=gnu99' ],
cflags = [ bld.env['compiler_flags_dict']['pic'], '-fvisibility=hidden', '-std=gnu99', '-Wno-unused-function' ],
includes = ['.', 'src/' ],
target = 'libfluidsynth',
use = 'libfluidsynth_includes',

View File

@ -78,10 +78,10 @@ index 37b0a06a4..b6586895b 100644
/*
* fluid_hashtable_foreach_remove_or_steal:
diff --git b/libs/fluidsynth/src/fluid_midi.c a/libs/fluidsynth/src/fluid_midi.c
index 4795fceb3..b82bfdf61 100644
index 1a394f811..8deb0b0d1 100644
--- b/libs/fluidsynth/src/fluid_midi.c
+++ a/libs/fluidsynth/src/fluid_midi.c
@@ -75,7 +75,7 @@ static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
@@ -76,7 +76,7 @@ static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
static int fluid_midi_file_eot(fluid_midi_file *mf);
static int fluid_midi_file_get_division(fluid_midi_file *midifile);
@ -90,7 +90,7 @@ index 4795fceb3..b82bfdf61 100644
/***************************************************************
*
* MIDIFILE
@@ -1011,6 +1011,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
@@ -1047,6 +1047,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
{
return midifile->division;
}
@ -98,7 +98,7 @@ index 4795fceb3..b82bfdf61 100644
/******************************************************
*
@@ -1330,7 +1331,7 @@ static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type,
@@ -1413,7 +1414,7 @@ static void fluid_midi_event_get_sysex_LOCAL(fluid_midi_event_t *evt, void **dat
*
* fluid_track_t
*/
@ -107,35 +107,39 @@ index 4795fceb3..b82bfdf61 100644
/*
* new_fluid_track
*/
@@ -2434,3 +2435,4 @@ fluid_midi_event_length(unsigned char event)
@@ -2517,3 +2518,4 @@ fluid_midi_event_length(unsigned char event)
return 1;
}
+#endif
diff --git b/libs/fluidsynth/src/fluid_rev.c a/libs/fluidsynth/src/fluid_rev.c
index 198a06e58..894afc5a0 100644
--- b/libs/fluidsynth/src/fluid_rev.c
+++ a/libs/fluidsynth/src/fluid_rev.c
@@ -51,7 +51,7 @@ void fluid_allpass_init(fluid_allpass *allpass);
void fluid_allpass_setfeedback(fluid_allpass *allpass, fluid_real_t val);
fluid_real_t fluid_allpass_getfeedback(fluid_allpass *allpass);
-void
+static void
fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
diff --git b/libs/fluidsynth/src/fluid_mod.c a/libs/fluidsynth/src/fluid_mod.c
index 84e97731e..5e57455d4 100644
--- b/libs/fluidsynth/src/fluid_mod.c
+++ a/libs/fluidsynth/src/fluid_mod.c
@@ -603,7 +603,7 @@ fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select)
* @param name,if not NULL, pointer on a string displayed as a warning.
* @return TRUE if modulator sources src1, src2 are valid, FALSE otherwise.
*/
-int fluid_mod_check_sources(const fluid_mod_t *mod, char *name)
+int fluid_mod_check_sources(const fluid_mod_t *mod, const char *name)
{
allpass->bufidx = 0;
@@ -59,7 +59,7 @@ fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
allpass->bufsize = size;
}
static const char *invalid_non_cc_src =
"Invalid modulator, using non-CC source %s.src%d=%d";
diff --git b/libs/fluidsynth/src/fluid_mod.h a/libs/fluidsynth/src/fluid_mod.h
index 3e7661741..ec8e967a3 100644
--- b/libs/fluidsynth/src/fluid_mod.h
+++ a/libs/fluidsynth/src/fluid_mod.h
@@ -44,7 +44,7 @@ struct _fluid_mod_t
};
-void
+static void
fluid_allpass_release(fluid_allpass *allpass)
{
FLUID_FREE(allpass->buffer);
fluid_real_t fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice);
-int fluid_mod_check_sources(const fluid_mod_t *mod, char *name);
+int fluid_mod_check_sources(const fluid_mod_t *mod, const char *name);
#ifdef DEBUG
void fluid_dump_modulator(fluid_mod_t *mod);
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.c a/libs/fluidsynth/src/fluid_rvoice_mixer.c
index af0ef75d1..9e7b164bb 100644
index af0ef75d1..9acc5f830 100644
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.c
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.c
@@ -24,7 +24,6 @@
@ -146,7 +150,6 @@ index af0ef75d1..9e7b164bb 100644
#include "fluid_synth.h"
// If less than x voices, the thread overhead is larger than the gain,
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.h a/libs/fluidsynth/src/fluid_rvoice_mixer.h
index 4ee072e4b..1b3fceb34 100644
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.h
@ -188,7 +191,7 @@ index 02be9a033..9207ab063 100644
static int
diff --git b/libs/fluidsynth/src/fluid_synth.c a/libs/fluidsynth/src/fluid_synth.c
index faadefb27..79c5a9c87 100644
index 07bfc0427..b4524a2ac 100644
--- b/libs/fluidsynth/src/fluid_synth.c
+++ a/libs/fluidsynth/src/fluid_synth.c
@@ -267,7 +267,7 @@ void fluid_version(int *major, int *minor, int *micro)
@ -200,7 +203,7 @@ index faadefb27..79c5a9c87 100644
fluid_version_str(void)
{
return FLUIDSYNTH_VERSION;
@@ -6430,6 +6430,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
@@ -6442,6 +6442,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
FLUID_API_RETURN(FLUID_OK);
}
@ -208,7 +211,7 @@ index faadefb27..79c5a9c87 100644
/**
* Return the LADSPA effects instance used by FluidSynth
*
@@ -6442,6 +6443,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
@@ -6454,6 +6455,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
return synth->ladspa_fx;
}
@ -240,7 +243,7 @@ index 156424af1..58869730c 100644
enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */
};
diff --git b/libs/fluidsynth/src/fluid_sys.c a/libs/fluidsynth/src/fluid_sys.c
index 3df88fc23..cce778b3c 100644
index d686737f6..28911ee7f 100644
--- b/libs/fluidsynth/src/fluid_sys.c
+++ a/libs/fluidsynth/src/fluid_sys.c
@@ -202,9 +202,10 @@ fluid_log(int level, const char *fmt, ...)
@ -257,10 +260,10 @@ index 3df88fc23..cce778b3c 100644
if(str == NULL || delim == NULL || !*delim)
diff --git b/libs/fluidsynth/src/fluid_sys.h a/libs/fluidsynth/src/fluid_sys.h
index 47cc95c11..d95f6159f 100644
index 72b323029..122938655 100644
--- b/libs/fluidsynth/src/fluid_sys.h
+++ a/libs/fluidsynth/src/fluid_sys.h
@@ -91,7 +91,7 @@ else \
@@ -99,7 +99,7 @@ else \
/*
* Utility functions
*/
@ -270,7 +273,7 @@ index 47cc95c11..d95f6159f 100644
#if defined(__OS2__)
diff --git b/libs/fluidsynth/src/fluidsynth_priv.h a/libs/fluidsynth/src/fluidsynth_priv.h
index d5dbdf7e9..5de758dc0 100644
index 4df590e21..384785fcc 100644
--- b/libs/fluidsynth/src/fluidsynth_priv.h
+++ a/libs/fluidsynth/src/fluidsynth_priv.h
@@ -26,10 +26,6 @@

View File

@ -23,6 +23,11 @@ cd $TMP
#git clone git://git.code.sf.net/p/fluidsynth/code-git fs-git
git clone git://github.com/FluidSynth/fluidsynth.git fs-git
cd fs-git;
git describe --tags
git log | head
cd $TMP
FSR=fs-git/
rsync -auc --info=progress2 \