Merge pull request #317 from FluidSynth/balance

Add support for balance control (CC 8)
This commit is contained in:
Tom M 2018-02-11 16:15:00 +01:00 committed by GitHub
commit 825216f0b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 98 additions and 13 deletions

View file

@ -100,6 +100,7 @@ enum fluid_gen_type {
* modulator. */ * modulator. */
GEN_PITCH, /**< Pitch @note Not a real SoundFont generator */ GEN_PITCH, /**< Pitch @note Not a real SoundFont generator */
GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
/* non-standard generator for an additional custom high- or low-pass filter */ /* non-standard generator for an additional custom high- or low-pass filter */
GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */ GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */
GEN_CUSTOM_FILTERQ, /**< Custom filter Q */ GEN_CUSTOM_FILTERQ, /**< Custom filter Q */

View file

@ -118,7 +118,9 @@ fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
continue; continue;
} }
if (i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB || if (i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB) { i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB ||
i == BALANCE_MSB || i == BALANCE_LSB
) {
continue; continue;
} }
@ -165,6 +167,10 @@ fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
fluid_channel_set_cc (chan, PAN_MSB, 64); fluid_channel_set_cc (chan, PAN_MSB, 64);
fluid_channel_set_cc (chan, PAN_LSB, 0); fluid_channel_set_cc (chan, PAN_LSB, 0);
/* Balance (MSB & LSB) */
fluid_channel_set_cc (chan, BALANCE_MSB, 64);
fluid_channel_set_cc (chan, BALANCE_LSB, 0);
/* Reverb */ /* Reverb */
/* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */ /* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */
/* Note: although XG standard specifies the default amount of reverb to /* Note: although XG standard specifies the default amount of reverb to

View file

@ -86,6 +86,7 @@ static const fluid_gen_info_t fluid_gen_info[] = {
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f }, { GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f }, { GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f }, { GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f },
{ GEN_CUSTOM_BALANCE, 1, 0, -960.0f, 960.0f, 0.0f },
{ GEN_CUSTOM_FILTERFC, 1, 2, 0.0f, 22050.0f, 0.0f }, { GEN_CUSTOM_FILTERFC, 1, 2, 0.0f, 22050.0f, 0.0f },
{ GEN_CUSTOM_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f } { GEN_CUSTOM_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f }
}; };

View file

@ -172,7 +172,26 @@ fluid_mod_get_source_value(const unsigned char mod_src,
if (mod_flags & FLUID_MOD_CC) if (mod_flags & FLUID_MOD_CC)
{ {
val = fluid_channel_get_cc(chan, mod_src); /* From MIDI Recommended Practice (RP-036) Default Pan Formula:
* "Since MIDI controller values range from 0 to 127, the exact center
* of the range, 63.5, cannot be represented. Therefore, the effective
* range for CC#10 is modified to be 1 to 127, and values 0 and 1 both
* pan hard left. The recommended method is to subtract 1 from the
* value of CC#10, and saturate the result to be non-negative."
*
* We treat the balance control in exactly the same way, as the same
* problem applies here as well.
*/
if (mod_src == PAN_MSB || mod_src == BALANCE_MSB) {
*range = 126;
val = fluid_channel_get_cc(chan, mod_src) - 1;
if (val < 0) {
val = 0;
}
}
else {
val = fluid_channel_get_cc(chan, mod_src);
}
} }
else else
{ {
@ -523,6 +542,7 @@ void fluid_dump_modulator(fluid_mod_t * mod){
case GEN_CHORUSSEND: printf("Chorus send"); break; case GEN_CHORUSSEND: printf("Chorus send"); break;
case GEN_REVERBSEND: printf("Reverb send"); break; case GEN_REVERBSEND: printf("Reverb send"); break;
case GEN_PAN: printf("pan"); break; case GEN_PAN: printf("pan"); break;
case GEN_CUSTOM_BALANCE: printf("balance"); break;
case GEN_ATTENUATION: printf("att"); break; case GEN_ATTENUATION: printf("att"); break;
default: printf("dest %i",dest); default: printf("dest %i",dest);
}; /* switch dest */ }; /* switch dest */

View file

@ -138,6 +138,7 @@ static fluid_mod_t default_expr_mod; /* SF2.01 section 8.4.7 */
static fluid_mod_t default_reverb_mod; /* SF2.01 section 8.4.8 */ static fluid_mod_t default_reverb_mod; /* SF2.01 section 8.4.8 */
static fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */ static fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */
static fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */ static fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */
static fluid_mod_t custom_balance_mod; /* Non-standard modulator */
/* reverb presets */ /* reverb presets */
@ -405,6 +406,19 @@ fluid_synth_init(void)
); );
fluid_mod_set_dest(&default_pitch_bend_mod, GEN_PITCH); /* Destination: Initial pitch */ fluid_mod_set_dest(&default_pitch_bend_mod, GEN_PITCH); /* Destination: Initial pitch */
fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */ fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */
/* Non-standard MIDI continuous controller 8 to channel stereo balance */
fluid_mod_set_source1(&custom_balance_mod, BALANCE_MSB, /* Index=8 */
FLUID_MOD_CC /* CC=1 */
| FLUID_MOD_CONCAVE /* type=1 */
| FLUID_MOD_BIPOLAR /* P=1 */
| FLUID_MOD_POSITIVE /* D=0 */
);
fluid_mod_set_source2(&custom_balance_mod, 0, 0);
fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */
/* Amount: 96 dB of attenuation (on the opposite channel) */
fluid_mod_set_amount(&custom_balance_mod, 960.0);
} }
static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t* synth) static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t* synth)
@ -672,7 +686,7 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_synth_add_default_mod(synth, &default_reverb_mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth, &default_reverb_mod, FLUID_SYNTH_ADD);
fluid_synth_add_default_mod(synth, &default_chorus_mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth, &default_chorus_mod, FLUID_SYNTH_ADD);
fluid_synth_add_default_mod(synth, &default_pitch_bend_mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth, &default_pitch_bend_mod, FLUID_SYNTH_ADD);
fluid_synth_add_default_mod(synth, &custom_balance_mod, FLUID_SYNTH_ADD);
/* Create and initialize the Fx unit.*/ /* Create and initialize the Fx unit.*/
fluid_settings_getint(settings, "synth.ladspa.active", &with_ladspa); fluid_settings_getint(settings, "synth.ladspa.active", &with_ladspa);

View file

@ -545,8 +545,9 @@ fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice)
/* GEN_FINETUNE [1] #52 */ /* GEN_FINETUNE [1] #52 */
GEN_OVERRIDEROOTKEY, /* #58 */ GEN_OVERRIDEROOTKEY, /* #58 */
GEN_PITCH, /* --- */ GEN_PITCH, /* --- */
GEN_CUSTOM_BALANCE, /* --- */
GEN_CUSTOM_FILTERFC, /* --- */ GEN_CUSTOM_FILTERFC, /* --- */
GEN_CUSTOM_FILTERQ, /* --- */ GEN_CUSTOM_FILTERQ /* --- */
}; };
/* When the voice is made ready for the synthesis process, a lot of /* When the voice is made ready for the synthesis process, a lot of
@ -696,14 +697,20 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
switch (gen) { switch (gen) {
case GEN_PAN: case GEN_PAN:
/* range checking is done in the fluid_pan function */ case GEN_CUSTOM_BALANCE:
voice->pan = x; /* range checking is done in the fluid_pan and fluid_balance functions */
voice->pan = fluid_voice_gen_value(voice, GEN_PAN);
voice->balance = fluid_voice_gen_value(voice, GEN_CUSTOM_BALANCE);
/* left amp */ /* left amp */
UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 0, fluid_voice_calculate_gain_amplitude(voice, fluid_pan(x, 1))); UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 0,
fluid_voice_calculate_gain_amplitude(voice,
fluid_pan(voice->pan, 1) * fluid_balance(voice->balance, 1)));
/* right amp */ /* right amp */
UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 1, fluid_voice_calculate_gain_amplitude(voice, fluid_pan(x, 0))); UPDATE_RVOICE_BUFFERS2(fluid_rvoice_buffers_set_amp, 1,
fluid_voice_calculate_gain_amplitude(voice,
fluid_pan(voice->pan, 0) * fluid_balance(voice->balance, 0)));
break; break;
case GEN_ATTENUATION: case GEN_ATTENUATION:
@ -1594,8 +1601,10 @@ int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain)
} }
voice->synth_gain = gain; voice->synth_gain = gain;
left = fluid_voice_calculate_gain_amplitude(voice, fluid_pan(voice->pan, 1)); left = fluid_voice_calculate_gain_amplitude(voice,
right = fluid_voice_calculate_gain_amplitude(voice, fluid_pan(voice->pan, 0)); fluid_pan(voice->pan, 1) * fluid_balance(voice->balance, 1));
right = fluid_voice_calculate_gain_amplitude(voice,
fluid_pan(voice->pan, 0) * fluid_balance(voice->balance, 0));
reverb = fluid_voice_calculate_gain_amplitude(voice, voice->reverb_send); reverb = fluid_voice_calculate_gain_amplitude(voice, voice->reverb_send);
chorus = fluid_voice_calculate_gain_amplitude(voice, voice->chorus_send); chorus = fluid_voice_calculate_gain_amplitude(voice, voice->chorus_send);

View file

@ -92,6 +92,9 @@ struct _fluid_voice_t
/* pan */ /* pan */
fluid_real_t pan; fluid_real_t pan;
/* balance */
fluid_real_t balance;
/* reverb */ /* reverb */
fluid_real_t reverb_send; fluid_real_t reverb_send;

View file

@ -252,15 +252,45 @@ fluid_pan(fluid_real_t c, int left)
if (left) { if (left) {
c = -c; c = -c;
} }
if (c < -500) { if (c <= -500) {
return (fluid_real_t) 0.0; return (fluid_real_t) 0.0;
} else if (c > 500) { } else if (c >= 500) {
return (fluid_real_t) 1.0; return (fluid_real_t) 1.0;
} else { } else {
return fluid_pan_tab[(int) (c + 500)]; return fluid_pan_tab[(int) (c + 500)];
} }
} }
/*
* Return the amount of attenuation based on the balance for the specified
* channel. If balance is negative (turned toward left channel, only the right
* channel is attenuated. If balance is positive, only the left channel is
* attenuated.
*
* @params balance left/right balance, range [-960;960] in absolute centibels
* @return amount of attenuation [0.0;1.0]
*/
fluid_real_t fluid_balance(fluid_real_t balance, int left)
{
/* This is the most common case */
if (balance == 0)
{
return 1.0f;
}
if ((left && balance < 0) || (!left && balance > 0))
{
return 1.0f;
}
if (balance < 0)
{
balance = -balance;
}
return fluid_cb2amp(balance);
}
/* /*
* fluid_concave * fluid_concave
*/ */

View file

@ -40,6 +40,7 @@ fluid_real_t fluid_tc2sec_release(fluid_real_t tc);
fluid_real_t fluid_act2hz(fluid_real_t c); fluid_real_t fluid_act2hz(fluid_real_t c);
fluid_real_t fluid_hz2ct(fluid_real_t c); fluid_real_t fluid_hz2ct(fluid_real_t c);
fluid_real_t fluid_pan(fluid_real_t c, int left); fluid_real_t fluid_pan(fluid_real_t c, int left);
fluid_real_t fluid_balance(fluid_real_t balance, int left);
fluid_real_t fluid_concave(fluid_real_t val); fluid_real_t fluid_concave(fluid_real_t val);
fluid_real_t fluid_convex(fluid_real_t val); fluid_real_t fluid_convex(fluid_real_t val);