From Unify Community Wiki
Revision as of 04:14, 11 April 2009 by Jessy (Talk | contribs)

Jump to: navigation, search

Author: Jessy



Unity's standard volume control uses a "linear taper", which does not correspond with human hearing. "Loudness", unlike the Audio Source's "Volume", will yield perceptually equivalent loudness changes for equivalent value changes. (Changing the Loudness from 0.2 to 0.3 will yield a similar difference in loudness between 0.7 to 0.8, etc.)

JavaScript - Loudness.js

<javascript> var loudness : float = 1;

private var exponent = Mathf.Log(Mathf.Sqrt(10), 2);

// I would not leave this in Update() for a release. // Put it wherever you need it, to change the volume in-game.

function Update () { audio.volume = Mathf.Pow(loudness, exponent); } </javascript>

Why this works

To simplify things a bit, a volume control is a multiplier for amplitude of audio waveforms. It makes intuitive sense for a volume control to output...

exactly what is input, for a value of 1,

half of the input, for a value of .5,

one fourth of the input, for a value of .25,


Unity's volume control does exactly this (see below for exceptions). The problem is that amplitude of a waveform does not correlate directly with human perception of loudness. Loudness perception is complex, but "experimentally it was found that a 10 dB increase in sound level corresponds approximately to a perceived doubling of loudness.". Therefore, it makes sense for a volume control to yield an amplitude that is...

exactly what is input, for a value of 1,

10 decibels below the input, for a value of .5,

20 decibels below the input, for a value of .25,


Amplitudinal difference, as a multiplicative factor, based on a difference in decibels, can be found with the expression 10^(dB / 20). Inputting the value of 10 dB results in 10^(10/20), which "Mathf.Sqrt(10)" in the code represents.

Raising this value to a base 2 logarithm gives exactly the behavior we want for a volume control. This expression would be "(10^.5)^log[2]loudness". However, the code will execute faster in the form that I gave in the code, which is "loudness^(log[2](10^.5))", due to only having to calculate a logarithm one time. I am still trying to find a proof for why this is a property of logarithms in exponents - please let me know if you have it.

  • AudioSource.volume only responds to values of 1 or less. There is the potential to easily induce digital distortion if non-clipped waveforms can be amplified, so apparently the choice was made to disallow this. I think this may have been done before it easily allows for 3D positional audio not to distort within a distance of less than one world meter, using the current distance model of volume = 1.0 / (1.0 + rolloff * (distance – 1.0)). Boosting the level of audio clips can only be done outside Unity at the moment. My conversion script will continue to function properly, above values of 1, if the restriction is ever dropped.
  • Values of less than zero, for either this loudness script, or audio.volume, both equate to multiplying the audio amplitude by zero. It is possible, that if Unity ever allows us the ability to invert the phase of a signal, that negative values could be useful, but this script would not account for that as is. I will update it if necessary, but hopefully, by the time Unity allows for phase inversion, this script will be obsolete.  ;-)

A more general script

This script gives finer control, so if you happen to disagree with the 10 dB for loudness doubling rule, you can design your own curves with this. It should be noted that Unity's volume control already matches what this script does, for certain cases. (e.g. dB_Increase = 20log2; loudness_Increase = 2)

Personally, I just use the simpler script above. <javascript> var loudness : float = 1; var dB_Increase : float = 10; // increase volume by this many dB when... var loudness_Increase : float = 2; // ..."loudness" is increased by this factor

function Update () { var exponent = Mathf.Log(Mathf.Pow(10, dB_Increase *.05), loudness_Increase); audio.volume = Mathf.Pow(loudness, exponent); } </javascript>

Personal tools