-
Notifications
You must be signed in to change notification settings - Fork 276
Add support for balance control (CC 8) #317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
As specified in MIDI Recommended Practice (RP-036)
src/synth/fluid_synth.c
Outdated
@@ -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_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_balance_mod; /* Non-standard modulator */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be called custom_balance_mod
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good idea. Will change it.
src/synth/fluid_synth.c
Outdated
); | ||
fluid_mod_set_source2(&default_balance_mod, 0, 0); | ||
fluid_mod_set_dest(&default_balance_mod, GEN_BALANCE); /* Destination: stereo balance */ | ||
fluid_mod_set_amount(&default_balance_mod, 1000.0); /* Amount: 1000 tens of a percent */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you not using the same amount as GEN_PAN
does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Soundfont specifies that generator ranges should be in real-world units. -500;500 makes perfect sense for pan, because it is defined as the position on a 180 degree half circle. So -500 is 50% of 180 left.
Balance is not expressed as position, but as volume. So 100% left makes much more sense to say "right channel is silent" than 50%.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm... Thinking about it, maybe balance volume should be expressed in centibels, like volume and expression. That would make the range -960;960, the modulator would get a concave shape and we would use fluid_cb2amp for conversion. Actually, that would also make volume changes much smoother in the extreme regions. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just thought that giving it a pure linear scale wouldnt be "smooth" enough. I thought using a sinus would be still somewhat linear but in a smoother manner. This is where we would end up in fluid_pan() again.
fluid_cb2amp() could work as well. What I dont like about that [centi|deci]bel scale is that it never turns off. Yes, the volume gets very silent, probably unhearable, but if I set CC8=127 I would expect the left chan to be completely off.
But sure when looking at volume and expression, perhaps we should really use fluid_cb2amp() to be somewhat "consistent"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sinus in pan is actually there to linearise the perceived volume, using equal power distribution. In listening tests I checked the perceived volume changes on a mono sample with pan and balance. With the current implementation, they are very similar, if not the same.
Using centibels, balance would be much smoother. Oh, and we could simply force -960 and 960 to be 0 (or 1 on the opposite channel)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright then fluid_cb2amp().
Oh, and we could simply force -960 and 960 to be 0 (or 1 on the opposite channel)
No special casing pls. 10^(960/-200)=0.000016 and that's how things should be then :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No special casing pls. 10^(960/-200)=0.000016 and that's how things should be then :)
In that case I would strongly prefer the current solution. A balance control that can't turn one channel off completely would be flawed, imho.
What's so bad about forcing the extreme values to 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A balance control that can't turn be channel off completely would be flawed, imho.
Same like a main volume control that cant turn off a channel completely, which currently seems to be the case (at least I experienced that).
What's so bad about forcing the extreme values to 0?
I dont like branches in math calculations. They cause hearable discontinuity and branch prediction failures. They just dont feel right. Where would you place these if clauses? Probably after modulator processing, a place where you would need to do a floating point comparison for x==960.0
. How likely is that to evaluate to true?
In that case I would strongly prefer the current solution.
Or we go with fluid_pan(), i.e. sin().
Hearable discontinuities are there in any case. Just listen to the steps in volume between pan 127 and pan 126 on a mono sample. And if we put the special casing into the setup of the conversion table (just like it's already been done for fluid_concave_tab and fluid_convex_tab where index 0 is forced to 0.0f and index 127 is forced to 1.0f), then we don't need any new branches. So just add the following after the fluid_cb2amp_tab setup:
That would have the added benefit that the volume and expression controls can also turn off (and on) completely. But incidentally... I wonder why FLUID_CB_AMP_SIZE is defined as 961?! |
Never mind... of course it's because the range is that long, from 0 - 960. Doh... |
Well ok, that's a necessary discontinuity due to the limited 7 bit resolution.
I think it should be
Yes I would be very happy with it. Still by the spec apparently volume and expression are not meant to turn channels off completely and I do not want to support such a change just because of my personal attitude. So we have these three options. From my personal musical perspective/preference I would go with fluid_pan(). OTOH to be consistent with volume calc. I would use fluid_cb2amp(). Difficult. Keeping it linear is not my favourite. But I would leave the decision to you, as you have more musical experience than I. |
Actually, I think the current behaviour is against the spec. From the Sound Font 2.04 document:
|
Oh, good spot. Well ok then, let's make us both happy with |
Hm... on the other hand, that is only specified for the final gain amplifier and doesn't express anything about intermediate calculations. Oh dear... :-) |
Argh, I intentionally over-read that ^^ Well, we could ask mrbumpy409 (S. Christian Collins), he owns some EMU hardware, perhaps a third opinion might help? |
That would be great, yes. However, reading the spec again and again, I come to the conclusion that Fluidsynths current implementation is actually not correct. The output of the final gain amplifier (per sample/voice) is meant to be mixed into the output and sent to the effect units. The amount of attenuation that a voice receives should only be considered at this stage, and here we should also check if the attenuation is 96db or greater and force it to be infinite (so an amp of 0), according to spec. So the best place to check this is IMHO
I've just tested this with s16 and s24 output and it does have the desired effect. And one more float comparison shouldn't affect performance, I think. |
Ah, no. It shouldn't take the final output gain into consideration. So the check should be on
|
Maybe I should think about this more before posting. Actually that only takes pan and balance into account, not the rest of the volume envelope. So the check should be in |
Ok, I think this "96 dB should be zero" problem is outside of the scope of this feature addition, as it also affects other attenuation sources like expression and volume. What about this: we change the balance to use centibels and live with not-completely-silent-channels problem for now. In addition, we open a ticket for the attenuation problem and solve that separately. |
Ok.
Feel free to do so. If you still need advice/review from mrbumpy409, he's on github, you could just ping him. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested and seems to works as expected. I would leave this open for a few days to give the mailing list community some time. You can merge this whenever you want.
Ok, thanks a lot for testing! Will wait a few days and then merge. |
@mawe42 I have done a quick look inside (not in depth). I only just wanted to get confirmation about the intended implementation.
So actually the implementation seems to be done in the right place (i.e on the MIDI side task) without impacting performance of the audio rendering function (i.e on the audio task side).
Thanks for your work. |
@jjceresa Sorry for the late answer! Yes, pan and balance both affect the voices amp values.
Yes, the initial balance value is neutral, so if you don't set a balance value, the sound is unaffected. The intended response behaviour is just like the stereo balance knob on any home hifi system. So "turning the knob" to the left makes the right channel quieter but leaves the left channel untouched.
Yes, pan behaviour is unaffected by this change. |
Yes , but please what is the response curve: |
The responsible function is fluid_balance(), which uses fluid_cb2amp(),
i.e. pow(10.0, (double) i / -200.0)
2018-02-04 22:48 GMT+01:00 jjceresa <[email protected]>:
… So "turning the knob" to the left makes the right channel quieter.
Yes , but please what is the response curve: left volume = f (from
balance center to balance left) ?.
(i.e the function fis it linear, logarithmic, or other ?)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#317 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHxloCUFJu2toEDQQ_xf9Aph_dUjZXH7ks5tRiWRgaJpZM4RSaj1>
.
|
As Tom said, it's using fluid_cb2amp at the moment. Which response curve to use has been subject to quite a bit of discussion already. But I would be very interested in your opinion on the subject! |
|
Let's merge this as well. |
This pull-request adds support for the balance control on CC 8, as discussed on the mailing list:
http://lists.nongnu.org/archive/html/fluid-dev/2018-01/msg00006.html
It also makes a slight change to the range of the panning control so that voices panned to the center are exactly the same value on both channels. It does this by reducing the range to 1 - 127, treating 0 and 1 as "hard left". This treatment is specified in the MIDI Recommended Practice (RP-036).
This special treatment is also used for the balance control, as it has the same problem with the non-representable center value on a 0 - 127 range.