What algorithms could I use for audio volume level?

human perception in general is logarithmic, also when it comes to things as luminosity, etc. ... this enables us to register small changes to small "input signals" of our environement, or to put it another way: to always percieve a change of a perceivable physical quantity in relation to its value ...

thus, you should modify the volume to grow exponentially, like this:

y = (Math.exp(x)-1)/(Math.E-1)

you can try other bases as well:

y = (Math.pow(base,x)-1)/(base-1)

the bigger the value of base is, the stronger the effect, the slower volume starts growing in the beginning and the faster it grows in the end ...

a slighty simpler approach, giving you similar results (you are only in the interval between 0 and 1, so approximations are quite simple, actually), is to exponantiate the original value, as

y = Math.pow(x, exp);

for exp bigger than 1, the effect is, that the output (i.e. the volume in you case) first goes up slower, and then faster towards the end ... this is very similar to exponential functions ... the bigger exp, the stronger the effect ...


Hearing is complicated, the perceived loudness varies according to frequency, the duration of the sample, and from person to person. So this cannot be solved mathematically but by trying a variety of functions for the control and picking the one which 'feels' the best.

Do you find at the moment that varying the control at the low end of the range has little effect on the apparent volume, but that the volume increases rapidly at the upper end of the range? Or do you hear the reverse, the volume varies too quickly at the low end and not enough at the high end? Or would you like finer control over the volume at medium levels?

Increased low-volume sensitivity:

SoundTransform.volume = Math.sin(x * Math.PI / 2);

Increased high-volume sensitivity:

SoundTransform.volume = (Math.pow(base,x) - 1)/(base-1);

or

SoundTransform.volume = Math.pow(x, base);

Where base > 1, try different values and see how it feels. Or more drastically, a 90 degree circular arc:

SoundTransform.volume = 1 - Math.sqrt(1-(x * x));

Where x is slider.volume and is between 0 and 1.

Please do let us know how you get on!


Yes, human perception is logarithmic. Considering this, you should adjust a volume exponentially, so that the percieved increase becomes linear. See decibel on Wikipedia


Human hearing is logarithmic, so you want an exponential function (the inverse) to apply to the linear output of your slider. I don't know if human hearing is closer to ln or log:

For Ln:

e^x

For Log:

10^x

You could experiment with other bases too. You will then need to scale your output so that it covers the available range of values.

Update

After a bit of research it seems that base 2 would be appropriate since the power is related to the square of the pressure. If anyone knows better, please correct me.

I think what you want is:

v' = 2^v.a^v - 1
a  = ( 2^(log2(m+1)/n) )/2

v is your linear input value ranging from 0..n v' is your logarithmic value ranging from 0..m

The -1 in the first equation is to give you an output range from 0 instead of 1 (since k^0=1).

The m+1 is to compensate for this so you get 0..m not 0..m+1

You can of course get tweak this to suit your requirements.