diff --git a/src/sfloader/fluid_defsfont.c b/src/sfloader/fluid_defsfont.c index 1931d4ee..b81aaca2 100644 --- a/src/sfloader/fluid_defsfont.c +++ b/src/sfloader/fluid_defsfont.c @@ -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). diff --git a/src/synth/fluid_mod.c b/src/synth/fluid_mod.c index 9a48ed45..db59642b 100644 --- a/src/synth/fluid_mod.c +++ b/src/synth/fluid_mod.c @@ -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; diff --git a/src/synth/fluid_voice.c b/src/synth/fluid_voice.c index 66337175..2bbe5de2 100644 --- a/src/synth/fluid_voice.c +++ b/src/synth/fluid_voice.c @@ -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); } } }