Volume law
Posted: Wed Jan 17, 2024 6:14 pm
Having looked at Pan Law I thought I'd share my recent thoughts on Volume Law.
No doubt we've all at some point coded volume control as...
...where volume is a double between 0 and 1.
This obviously works but doesn't take into account how we perceive loudness.
Rather than linear gain we could use an equation in the form...
For a 60 dB dynamic range this becomes...
Here's a comparison between the linear and exponential curves...
As you can see there's a huge difference. In practice this means that the top half of the linear volume control has very little impact on the perceived volume.
But exponential curves are asymptotic, so a volume of zero still lets through a tiny unwanted amount of signal.
One way around this is to smoothly switch over to a linear response below 10% volume using code like this...
The transition is shown in close-up below...
I scaled the graphic too small but hopefully you can see how the green line neatly takes us down to minus infinity dB at zero volume.
However, there's a reasonable approximation that's far cheaper and automatically goes to zero and that's to use the sxith power of the volume...
Here are the two basic curves for comparison...
The sixth power isn't perfect but it's pretty good and can be coded using just four multiplications as follows...
If you are doing volume control just at UI speed then the method involving a comparison, potential branch, two multiplications and Math.exp() or pow( e, x ) isn't going to be a worry, but if you need to code exponential VCA's the x^6 approximation might be a winner.
No doubt we've all at some point coded volume control as...
Code: Select all
output = input * volume
This obviously works but doesn't take into account how we perceive loudness.
Rather than linear gain we could use an equation in the form...
Code: Select all
output = input * a * exp( volume * b )
Code: Select all
output = input * 0.001 * exp( volume * 6.908 )
As you can see there's a huge difference. In practice this means that the top half of the linear volume control has very little impact on the perceived volume.
But exponential curves are asymptotic, so a volume of zero still lets through a tiny unwanted amount of signal.
One way around this is to smoothly switch over to a linear response below 10% volume using code like this...
Code: Select all
if( volume > 0.1 )
output = input * 0.001 * Math.exp( volume * 6.908 )
else
output = input * volume * 0.019953
I scaled the graphic too small but hopefully you can see how the green line neatly takes us down to minus infinity dB at zero volume.
However, there's a reasonable approximation that's far cheaper and automatically goes to zero and that's to use the sxith power of the volume...
Code: Select all
output = input * volume ^ 6
The sixth power isn't perfect but it's pretty good and can be coded using just four multiplications as follows...
Code: Select all
double t = volume * volume * volume;
output = input * t * t