Update Fluidsynth to v2.0.3
see https://github.com/FluidSynth/fluidsynth/releases/tag/v2.0.3
This commit is contained in:
parent
754591e2ee
commit
ac9329f907
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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 */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -34,76 +34,80 @@
|
||||
Borrowed from Smurf SoundFont Editor by Josh Green
|
||||
=================================================================*/
|
||||
|
||||
/* 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 */
|
||||
|
||||
#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 */
|
||||
|
||||
#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')
|
||||
|
||||
/* Set when the FCC code is unknown */
|
||||
#define UNKN_ID FLUID_N_ELEMENTS(idlist)
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
/* sf file chunk IDs */
|
||||
enum
|
||||
* This declares a uint32_t array containing the SF2 chunk identifiers.
|
||||
*/
|
||||
static const uint32_t idlist[] =
|
||||
{
|
||||
UNKN_ID,
|
||||
RIFF_ID,
|
||||
LIST_ID,
|
||||
SFBK_ID,
|
||||
INFO_ID,
|
||||
SDTA_ID,
|
||||
PDTA_ID, /* info/sample/preset */
|
||||
RIFF_FCC,
|
||||
LIST_FCC,
|
||||
SFBK_FCC,
|
||||
INFO_FCC,
|
||||
SDTA_FCC,
|
||||
PDTA_FCC,
|
||||
|
||||
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 */
|
||||
IFIL_FCC,
|
||||
ISNG_FCC,
|
||||
INAM_FCC,
|
||||
IROM_FCC,
|
||||
IVER_FCC,
|
||||
ICRD_FCC,
|
||||
IENG_FCC,
|
||||
IPRD_FCC,
|
||||
ICOP_FCC,
|
||||
ICMT_FCC,
|
||||
ISFT_FCC,
|
||||
|
||||
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
|
||||
SNAM_FCC,
|
||||
SMPL_FCC,
|
||||
PHDR_FCC,
|
||||
PBAG_FCC,
|
||||
PMOD_FCC,
|
||||
PGEN_FCC,
|
||||
IHDR_FCC,
|
||||
IBAG_FCC,
|
||||
IMOD_FCC,
|
||||
IGEN_FCC,
|
||||
SHDR_FCC,
|
||||
SM24_FCC
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
static const union fluid_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"
|
||||
};
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
@ -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++)
|
||||
@ -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];
|
||||
@ -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,7 +3875,8 @@ round_clip_to_i16(float x)
|
||||
else
|
||||
{
|
||||
i = (long)(x - 0.5f);
|
||||
if (FLUID_UNLIKELY(i < -32768))
|
||||
|
||||
if(FLUID_UNLIKELY(i < -32768))
|
||||
{
|
||||
i = -32768;
|
||||
}
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
||||
if(buf[0] != '\0')
|
||||
{
|
||||
add_history(buf);
|
||||
}
|
||||
|
||||
free(line);
|
||||
return 1;
|
||||
|
@ -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) \
|
||||
|
@ -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,43 +1162,66 @@ 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);
|
||||
|
||||
/* Skip if this generator has already been updated */
|
||||
if(!is_gen_updated(updated_gen_bit, gen))
|
||||
{
|
||||
modval = 0.0;
|
||||
|
||||
/* step 2: for every changed modulator, calculate the modulation
|
||||
* value of its associated generator */
|
||||
/* step 2: for every attached modulator, calculate the modulation
|
||||
* value for the generator gen */
|
||||
for(k = 0; k < voice->mod_count; k++)
|
||||
{
|
||||
if(fluid_mod_has_dest(&voice->mod[k], gen))
|
||||
@ -1208,10 +1232,13 @@ int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
|
||||
|
||||
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 */
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
|
@ -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 @@
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user