mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-01-18 23:41:36 +00:00
Add modulators checking at soundfont loading time (#467)
Actually some basic modulators check are done at noteon time (in fluid_voice_add_mod()). That means that we know if a modulator (modx) is invalid only when a MIDI noteon is received and only for a preset modx belongs to. This is not appropriate. This moves the modulator checking at soundfont loading time. Enhancements are: 1) A better verbose modulator integrity check, for any soundfont loaded at appropriate time. 1.1) All modulators are checked (preset zone (local/global), instrument zone (local/global). 1.2.1) Modulators check are enforced to source src1 and src2 (for non-CC and CC sources) (following SF specs (except for CC LSB) ( see comment in fluid_synth_cc_LOCAL()). Modulators CC sources checking is coherent with the actual behaviour in fluid_synth_cc_LOCAL() in regard of modulation triggering. 1.2.2) Also, identical modulator in the same zone are detected. 1.2.3) Any invalid modulator(sources invalid, or modulator identical) is removed at loading time with a warning message displaying the cause and name of the modulators. 2) This fix a bug in noteon, in the case of identical modulators in global preset zone. Assuming 2 identical modulator (m1 and m2) in a preset global zone, the actual noteon doesn't check this case (the actual code detect identical modulator in all others zones (instrument (local or global), preset(local)) but not preset global). 3) NoteOn is faster. 3.1)There is no more modulators checks at noteon making this more efficient. 3.2) As there are no identical modulator in the same zone, there is no more identity modulator check (i.e local zone against local zone), (i.e global zone against global zone). This result in a faster code and the bug described in (2) is gone. 4) Modulators sources checking as been added in API functions fluid_synth_add_default_mod() and fluid_voice_add_mod(). Please
This commit is contained in:
parent
2cef5b0587
commit
e9b0f0d24b
6 changed files with 517 additions and 157 deletions
|
@ -682,6 +682,140 @@ fluid_defpreset_next(fluid_defpreset_t *defpreset)
|
|||
return defpreset->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds global and local modulators list to the voice. This is done in 2 steps:
|
||||
* - Step 1: Local modulators replace identic global modulators.
|
||||
* - Step 2: global + local modulators are added to the voice using mode.
|
||||
*
|
||||
* Instrument zone list (local/global) must be added using FLUID_VOICE_OVERWRITE.
|
||||
* Preset zone list (local/global) must be added using FLUID_VOICE_ADD.
|
||||
*
|
||||
* @param voice voice instance.
|
||||
* @param global_mod global list of modulators.
|
||||
* @param local_mod local list of modulators.
|
||||
* @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,
|
||||
*/
|
||||
static void
|
||||
fluid_defpreset_noteon_add_mod_to_voice(fluid_voice_t *voice,
|
||||
fluid_mod_t *global_mod, fluid_mod_t *local_mod,
|
||||
int mode)
|
||||
{
|
||||
fluid_mod_t *mod;
|
||||
/* list for 'sorting' global/local modulators */
|
||||
fluid_mod_t *mod_list[FLUID_NUM_MOD];
|
||||
int mod_list_count, i;
|
||||
|
||||
/* identity_limit_count is the modulator upper limit number to handle with
|
||||
* existing identical modulators.
|
||||
* When identity_limit_count is below the actual number of modulators, this
|
||||
* will restrict identity check to this upper limit,
|
||||
* This is useful when we know by advance that there is no duplicate with
|
||||
* modulators at index above this limit. This avoid wasting cpu cycles at
|
||||
* noteon.
|
||||
*/
|
||||
int identity_limit_count;
|
||||
|
||||
/* Step 1: Local modulators replace identic global modulators. */
|
||||
|
||||
/* local (instrument zone/preset zone), modulators: Put them all into a list. */
|
||||
mod_list_count = 0;
|
||||
|
||||
while(local_mod)
|
||||
{
|
||||
/* As modulators number in local_mod list was limited to FLUID_NUM_MOD at
|
||||
soundfont loading time (fluid_limit_mod_list()), here we don't need
|
||||
to check if mod_list is full.
|
||||
*/
|
||||
mod_list[mod_list_count++] = local_mod;
|
||||
local_mod = local_mod->next;
|
||||
}
|
||||
|
||||
/* global (instrument zone/preset zone), modulators.
|
||||
* Replace modulators with the same definition in the global list:
|
||||
* (Instrument zone: SF 2.01 page 69, 'bullet' 8)
|
||||
* (Preset zone: SF 2.01 page 69, second-last bullet).
|
||||
*
|
||||
* mod_list contains local modulators. Now we know that there
|
||||
* is no global modulator identic to another global modulator (this has
|
||||
* been checked at soundfont loading time). So global modulators
|
||||
* are only checked against local modulators number.
|
||||
*/
|
||||
|
||||
/* Restrict identity check to the number of local modulators */
|
||||
identity_limit_count = mod_list_count;
|
||||
|
||||
while(global_mod)
|
||||
{
|
||||
/* 'Identical' global modulators are ignored.
|
||||
* SF2.01 section 9.5.1
|
||||
* page 69, 'bullet' 3 defines 'identical'. */
|
||||
|
||||
for(i = 0; i < identity_limit_count; i++)
|
||||
{
|
||||
if(fluid_mod_test_identity(global_mod, mod_list[i]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally add the new modulator to the list. */
|
||||
if(i >= identity_limit_count)
|
||||
{
|
||||
/* Although local_mod and global_mod lists was limited to
|
||||
FLUID_NUM_MOD at soundfont loading time, it is possible that
|
||||
local + global modulators exceeds FLUID_NUM_MOD.
|
||||
So, checks if mod_list_count reachs the limit.
|
||||
*/
|
||||
if(mod_list_count >= FLUID_NUM_MOD)
|
||||
{
|
||||
/* mod_list is full, we silently forget this modulator and
|
||||
next global modulators. When mod_list will be added to the
|
||||
voice, a warning will be displayed if the voice list is full.
|
||||
(see fluid_voice_add_mod_local()).
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
mod_list[mod_list_count++] = global_mod;
|
||||
}
|
||||
|
||||
global_mod = global_mod->next;
|
||||
}
|
||||
|
||||
/* Step 2: global + local modulators are added to the voice using mode. */
|
||||
|
||||
/*
|
||||
* mod_list contains local and global modulators, we know that:
|
||||
* - there is no global modulator identic to another global modulator,
|
||||
* - there is no local modulator identic to another local modulator,
|
||||
* So these local/global modulators are only checked against
|
||||
* actual number of voice modulators.
|
||||
*/
|
||||
|
||||
/* Restrict identity check to the actual number of voice modulators */
|
||||
/* Acual number of voice modulators : defaults + [instruments] */
|
||||
identity_limit_count = voice->mod_count;
|
||||
|
||||
for(i = 0; i < mod_list_count; i++)
|
||||
{
|
||||
|
||||
mod = mod_list[i];
|
||||
/* in mode FLUID_VOICE_OVERWRITE disabled instruments modulators CANNOT be skipped. */
|
||||
/* in mode FLUID_VOICE_ADD disabled preset modulators can be skipped. */
|
||||
|
||||
if((mode == FLUID_VOICE_OVERWRITE) || (mod->amount != 0))
|
||||
{
|
||||
/* Instrument modulators -supersede- existing (default) modulators.
|
||||
SF 2.01 page 69, 'bullet' 6 */
|
||||
|
||||
/* Preset modulators -add- to existing instrument modulators.
|
||||
SF2.01 page 70 first bullet on page */
|
||||
fluid_voice_add_mod_local(voice, mod, mode, identity_limit_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_defpreset_noteon
|
||||
|
@ -695,9 +829,6 @@ fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int c
|
|||
fluid_voice_zone_t *voice_zone;
|
||||
fluid_list_t *list;
|
||||
fluid_voice_t *voice;
|
||||
fluid_mod_t *mod;
|
||||
fluid_mod_t *mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */
|
||||
int mod_list_count;
|
||||
int i;
|
||||
|
||||
global_preset_zone = fluid_defpreset_get_global_zone(defpreset);
|
||||
|
@ -769,63 +900,12 @@ fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int c
|
|||
|
||||
} /* for all generators */
|
||||
|
||||
/* global instrument zone, modulators: Put them all into a
|
||||
* list. */
|
||||
|
||||
mod_list_count = 0;
|
||||
|
||||
if(global_inst_zone)
|
||||
{
|
||||
mod = global_inst_zone->mod;
|
||||
|
||||
while(mod)
|
||||
{
|
||||
mod_list[mod_list_count++] = mod;
|
||||
mod = mod->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* local instrument zone, modulators.
|
||||
* Replace modulators with the same definition in the list:
|
||||
* SF 2.01 page 69, 'bullet' 8
|
||||
*/
|
||||
mod = inst_zone->mod;
|
||||
|
||||
while(mod)
|
||||
{
|
||||
|
||||
/* 'Identical' modulators will be deleted by setting their
|
||||
* list entry to NULL. The list length is known, NULL
|
||||
* entries will be ignored later. SF2.01 section 9.5.1
|
||||
* page 69, 'bullet' 3 defines 'identical'. */
|
||||
|
||||
for(i = 0; i < mod_list_count; i++)
|
||||
{
|
||||
if(mod_list[i] && fluid_mod_test_identity(mod, mod_list[i]))
|
||||
{
|
||||
mod_list[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally add the new modulator to to the list. */
|
||||
mod_list[mod_list_count++] = mod;
|
||||
mod = mod->next;
|
||||
}
|
||||
|
||||
/* Add instrument modulators (global / local) to the voice. */
|
||||
for(i = 0; i < mod_list_count; i++)
|
||||
{
|
||||
|
||||
mod = mod_list[i];
|
||||
|
||||
if(mod != NULL) /* disabled modulators CANNOT be skipped. */
|
||||
{
|
||||
|
||||
/* Instrument modulators -supersede- existing (default)
|
||||
* modulators. SF 2.01 page 69, 'bullet' 6 */
|
||||
fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE);
|
||||
}
|
||||
}
|
||||
/* Adds instrument zone modulators (global and local) to the voice.*/
|
||||
fluid_defpreset_noteon_add_mod_to_voice(voice,
|
||||
/* global instrument modulators */
|
||||
global_inst_zone ? global_inst_zone->mod : NULL,
|
||||
inst_zone->mod, /* local instrument modulators */
|
||||
FLUID_VOICE_OVERWRITE); /* mode */
|
||||
|
||||
/* Preset level, generators */
|
||||
|
||||
|
@ -868,57 +948,12 @@ fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int c
|
|||
}
|
||||
} /* for all generators */
|
||||
|
||||
|
||||
/* Global preset zone, modulators: put them all into a
|
||||
* list. */
|
||||
mod_list_count = 0;
|
||||
|
||||
if(global_preset_zone)
|
||||
{
|
||||
mod = global_preset_zone->mod;
|
||||
|
||||
while(mod)
|
||||
{
|
||||
mod_list[mod_list_count++] = mod;
|
||||
mod = mod->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the modulators of the local preset zone. Kick
|
||||
* out all identical modulators from the global preset zone
|
||||
* (SF 2.01 page 69, second-last bullet) */
|
||||
|
||||
mod = preset_zone->mod;
|
||||
|
||||
while(mod)
|
||||
{
|
||||
for(i = 0; i < mod_list_count; i++)
|
||||
{
|
||||
if(mod_list[i] && fluid_mod_test_identity(mod, mod_list[i]))
|
||||
{
|
||||
mod_list[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally add the new modulator to the list. */
|
||||
mod_list[mod_list_count++] = mod;
|
||||
mod = mod->next;
|
||||
}
|
||||
|
||||
/* Add preset modulators (global / local) to the voice. */
|
||||
for(i = 0; i < mod_list_count; i++)
|
||||
{
|
||||
mod = mod_list[i];
|
||||
|
||||
if((mod != NULL) && (mod->amount != 0)) /* disabled modulators can be skipped. */
|
||||
{
|
||||
|
||||
/* Preset modulators -add- to existing instrument /
|
||||
* default modulators. SF2.01 page 70 first bullet on
|
||||
* page */
|
||||
fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD);
|
||||
}
|
||||
}
|
||||
/* Adds preset zone modulators (global and local) to the voice.*/
|
||||
fluid_defpreset_noteon_add_mod_to_voice(voice,
|
||||
/* global preset modulators */
|
||||
global_preset_zone ? global_preset_zone->mod : NULL,
|
||||
preset_zone->mod, /* local preset modulators */
|
||||
FLUID_VOICE_ADD); /* mode */
|
||||
|
||||
/* add the synthesis process to the synthesis loop. */
|
||||
fluid_synth_start_voice(synth, voice);
|
||||
|
@ -930,7 +965,6 @@ fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int c
|
|||
* class - for example when using stereo samples)
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1110,6 +1144,7 @@ new_fluid_preset_zone(char *name)
|
|||
static void delete_fluid_list_mod(fluid_mod_t *mod)
|
||||
{
|
||||
fluid_mod_t *tmp;
|
||||
|
||||
while(mod) /* delete the modulators */
|
||||
{
|
||||
tmp = mod;
|
||||
|
@ -1192,6 +1227,129 @@ static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if modulator mod is identic to another modulator in the list
|
||||
* (specs SF 2.0X 7.4, 7.8).
|
||||
* @param mod, modulator list.
|
||||
* @param name, if not NULL, pointer on a string displayed as warning.
|
||||
* @return TRUE if mod is identic to another modulator, FALSE otherwise.
|
||||
*/
|
||||
static int
|
||||
fluid_zone_is_mod_identic(fluid_mod_t *mod, char *name)
|
||||
{
|
||||
fluid_mod_t *next = mod->next;
|
||||
|
||||
while(next)
|
||||
{
|
||||
/* is mod identic to next ? */
|
||||
if(fluid_mod_test_identity(mod, next))
|
||||
{
|
||||
if(name)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Ignoring identic modulator %s", name);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the number of modulators in a modulator list.
|
||||
* This is appropriate to internal synthesizer modulators tables
|
||||
* which have a fixed size (FLUID_NUM_MOD).
|
||||
*
|
||||
* @param zone_name, zone name
|
||||
* @param list_mod, address of pointer on modulator list.
|
||||
*/
|
||||
static void fluid_limit_mod_list(char *zone_name, fluid_mod_t **list_mod)
|
||||
{
|
||||
int mod_idx = 0; /* modulator index */
|
||||
fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */
|
||||
fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */
|
||||
|
||||
while(mod)
|
||||
{
|
||||
if((mod_idx + 1) > FLUID_NUM_MOD)
|
||||
{
|
||||
/* truncation of list_mod */
|
||||
if(mod_idx)
|
||||
{
|
||||
prev_mod->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*list_mod = NULL;
|
||||
}
|
||||
|
||||
delete_fluid_list_mod(mod);
|
||||
FLUID_LOG(FLUID_WARN, "%s, modulators count limited to %d", zone_name,
|
||||
FLUID_NUM_MOD);
|
||||
break;
|
||||
}
|
||||
|
||||
mod_idx++;
|
||||
prev_mod = mod;
|
||||
mod = mod->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks and remove invalid modulators from a zone modulators list.
|
||||
* - checks valid modulator sources (specs SF 2.01 7.4, 7.8, 8.2.1).
|
||||
* - checks identic modulators in the list (specs SF 2.01 7.4, 7.8).
|
||||
* @param zone_name, zone name.
|
||||
* @param list_mod, address of pointer on modulators list.
|
||||
*/
|
||||
static void
|
||||
fluid_zone_check_mod(char *zone_name, fluid_mod_t **list_mod)
|
||||
{
|
||||
fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */
|
||||
fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */
|
||||
int mod_idx = 0; /* modulator index */
|
||||
|
||||
while(mod)
|
||||
{
|
||||
char zone_mod_name[256];
|
||||
fluid_mod_t *next = mod->next;
|
||||
|
||||
/* prepare modulator name: zonename/#modulator */
|
||||
FLUID_SNPRINTF(zone_mod_name, sizeof(zone_mod_name), "%s/mod%d", zone_name, mod_idx);
|
||||
|
||||
/* has mod invalid sources ? */
|
||||
if(!fluid_mod_check_sources(mod, zone_mod_name)
|
||||
/* or is mod identic to any following modulator ? */
|
||||
|| fluid_zone_is_mod_identic(mod, zone_mod_name))
|
||||
{
|
||||
/* the modulator is useless so we remove it */
|
||||
if(prev_mod)
|
||||
{
|
||||
prev_mod->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
*list_mod = next;
|
||||
}
|
||||
|
||||
delete_fluid_mod(mod); /* freeing */
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_mod = mod;
|
||||
}
|
||||
|
||||
mod = next;
|
||||
mod_idx++;
|
||||
}
|
||||
|
||||
/* limits the size of modulators list */
|
||||
fluid_limit_mod_list(zone_name, list_mod);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_zone_gen_import_sfont
|
||||
* Imports generators from sfzone to gen and range.
|
||||
|
@ -1205,7 +1363,7 @@ fluid_zone_gen_import_sfont(fluid_gen_t *gen, fluid_zone_range_t *range, SFZone
|
|||
fluid_list_t *r;
|
||||
SFGen *sfgen;
|
||||
|
||||
for( r = sfzone->gen; r != NULL; )
|
||||
for(r = sfzone->gen; r != NULL;)
|
||||
{
|
||||
sfgen = (SFGen *)fluid_list_get(r);
|
||||
|
||||
|
@ -1258,6 +1416,7 @@ fluid_zone_mod_source_import_sfont(unsigned char *src, unsigned char *flags, uns
|
|||
|
||||
/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/
|
||||
flags_dest = 0;
|
||||
|
||||
if(sf_source & (1 << 7))
|
||||
{
|
||||
flags_dest |= FLUID_MOD_CC;
|
||||
|
@ -1313,19 +1472,21 @@ fluid_zone_mod_source_import_sfont(unsigned char *src, unsigned char *flags, uns
|
|||
/* This shouldn't happen - unknown type! */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*flags = flags_dest;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_zone_mod_import_sfont
|
||||
* Imports modulators from sfzone to mod list.
|
||||
* @param mod, pointer on modulator list to return.
|
||||
* Imports modulators from sfzone to modulators list mod.
|
||||
* @param zone_name, zone name.
|
||||
* @param mod, address of pointer on modulators list to return.
|
||||
* @param sfzone, pointer on soundfont zone.
|
||||
* @return FLUID_OK if success, FLUID_FAILED otherwise.
|
||||
*/
|
||||
static int
|
||||
fluid_zone_mod_import_sfont(fluid_mod_t **mod, SFZone *sfzone)
|
||||
fluid_zone_mod_import_sfont(char *zone_name, fluid_mod_t **mod, SFZone *sfzone)
|
||||
{
|
||||
fluid_list_t *r;
|
||||
int count;
|
||||
|
@ -1353,7 +1514,8 @@ fluid_zone_mod_import_sfont(fluid_mod_t **mod, SFZone *sfzone)
|
|||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* *** Dest *** */
|
||||
mod_dest->dest = mod_src->dest; /* index of controlled generator */
|
||||
|
||||
|
@ -1363,7 +1525,7 @@ fluid_zone_mod_import_sfont(fluid_mod_t **mod, SFZone *sfzone)
|
|||
/* This shouldn't happen - unknown type!
|
||||
* Deactivate the modulator by setting the amount to 0. */
|
||||
mod_dest->amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* *** Transform *** */
|
||||
/* SF2.01 only uses the 'linear' transform (0).
|
||||
|
@ -1398,6 +1560,8 @@ fluid_zone_mod_import_sfont(fluid_mod_t **mod, SFZone *sfzone)
|
|||
r = fluid_list_next(r);
|
||||
} /* foreach modulator */
|
||||
|
||||
/* checks and removes invalid modulators in modulators list*/
|
||||
fluid_zone_check_mod(zone_name, mod);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
@ -1433,7 +1597,7 @@ fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_
|
|||
}
|
||||
|
||||
/* Import the modulators (only SF2.1 and higher) */
|
||||
return fluid_zone_mod_import_sfont(&zone->mod, sfzone);
|
||||
return fluid_zone_mod_import_sfont(zone->name, &zone->mod, sfzone);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1546,7 +1710,9 @@ fluid_inst_import_sfont(fluid_preset_zone_t *preset_zone, SFInst *sfinst, fluid_
|
|||
{
|
||||
|
||||
sfzone = (SFZone *)fluid_list_get(p);
|
||||
FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%d", inst->name, count);
|
||||
/* integrates preset zone name in instrument zone name */
|
||||
FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%s/%d", preset_zone->name,
|
||||
inst->name, count);
|
||||
|
||||
inst_zone = new_fluid_inst_zone(zone_name);
|
||||
|
||||
|
@ -1704,7 +1870,7 @@ fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid
|
|||
}
|
||||
|
||||
/* Import the modulators (only SF2.1 and higher) */
|
||||
return fluid_zone_mod_import_sfont(&inst_zone->mod, sfzone);
|
||||
return fluid_zone_mod_import_sfont(inst_zone->name, &inst_zone->mod, sfzone);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -486,6 +486,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, 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, char *name);
|
||||
|
||||
#ifdef DEBUG
|
||||
void fluid_dump_modulator(fluid_mod_t *mod);
|
||||
|
|
|
@ -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;
|
||||
|
@ -3369,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;
|
||||
|
@ -3522,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
|
||||
|
@ -3540,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];
|
||||
|
@ -3688,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);
|
||||
|
||||
|
@ -3731,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);
|
||||
}
|
||||
|
@ -3785,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);
|
||||
|
@ -3854,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;
|
||||
}
|
||||
|
@ -3865,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;
|
||||
}
|
||||
|
||||
|
@ -4348,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
|
||||
|
|
|
@ -1185,7 +1185,7 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
|
|||
*/
|
||||
|
||||
#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 (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)
|
||||
|
||||
|
@ -1209,7 +1209,7 @@ int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl)
|
|||
mod = &voice->mod[i];
|
||||
|
||||
/* step 1: find all the modulators that have the changed controller
|
||||
as input source. When ctrl is -1 all modulators destination
|
||||
as input source. When ctrl is -1 all modulators destination
|
||||
are updated */
|
||||
if(ctrl < 0 || fluid_mod_has_source(mod, cc, ctrl))
|
||||
{
|
||||
|
@ -1465,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
|
||||
|
@ -1476,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))
|
||||
{
|
||||
|
@ -1517,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))
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue