Merge pull request #487 from FluidSynth/min-attenuation

Fix minor bug in lower_boundary_for_attenuation()
This commit is contained in:
Tom M 2018-12-21 19:53:26 +01:00 committed by GitHub
commit d666515c31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 12 deletions

View file

@ -1354,7 +1354,20 @@ fluid_zone_mod_import_sfont(fluid_mod_t **mod, SFZone *sfzone)
* Deactivate the modulator by setting the amount to 0. */
mod_dest->amount = 0;
}
/* *** Dest *** */
/* Note: When primary source input (src1) is set to General Controller 'No Controller',
output will be forced to 0.0 at synthesis time (see fluid_mod_get_value()).
That means that the minimum value of the modulator will be always 0.0.
We need to force amount value to 0 to ensure a correct evaluation of the minimum
value later (see fluid_voice_get_lower_boundary_for_attenuation()).
*/
if(((mod_dest->flags1 & FLUID_MOD_CC) == FLUID_MOD_GC) &&
(mod_dest->src1 == FLUID_MOD_NONE))
{
mod_dest->amount = 0;
}
/* *** Dest *** */
mod_dest->dest = mod_src->dest; /* index of controlled generator */
/* *** Amount source *** */
@ -1364,6 +1377,17 @@ fluid_zone_mod_import_sfont(fluid_mod_t **mod, SFZone *sfzone)
* Deactivate the modulator by setting the amount to 0. */
mod_dest->amount = 0;
}
/* Note: When secondary source input (src2) is set to General Controller 'No Controller',
output will be forced to +1.0 at synthesis time (see fluid_mod_get_value()).
That means that this source will behave unipolar only. We need to force the
unipolar flag to ensure to ensure a correct evaluation of the minimum
value later (see fluid_voice_get_lower_boundary_for_attenuation()).
*/
if(((mod_dest->flags2 & FLUID_MOD_CC) == FLUID_MOD_GC) &&
(mod_dest->src2 == FLUID_MOD_NONE))
{
mod_dest->flags2 &= ~FLUID_MOD_BIPOLAR;
}
/* *** Transform *** */
/* SF2.01 only uses the 'linear' transform (0).

View file

@ -364,7 +364,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 +433,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 +455,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;

View file

@ -1695,9 +1695,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)
@ -1724,30 +1725,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);
}
}
}