Skip to content

Instantly share code, notes, and snippets.

@jamiebuilds
Created June 26, 2023 21:45
Show Gist options
  • Save jamiebuilds/da15b1272716708bcf7decc39b6cd1b8 to your computer and use it in GitHub Desktop.
Save jamiebuilds/da15b1272716708bcf7decc39b6cd1b8 to your computer and use it in GitHub Desktop.
/**
* If you have a volume input (0 to 1), such as a slider, use this to convert
* it to a logarithmic volume that is closer to human perception (0 to 1).
*
* A more robust approach would use a Fletcher-Munson curve, however this is a
* close enough approximation for most use cases.
*
* You can customize the curve to your liking, generally 3-4 is a good value.
*
* The inverse of this function is {@link convertVolumeToInput}.
*
* @example
* ```html
* <audio id="audio" hidden src="sound.mp3" />
* <input id="volume" type="range" min="0" max="1" step="0.01" value="0.5">
* <script type="module">
* import { createAudioManager, convertInputToVolume } from 'audioboy/volume'
* document.querySelector('#volume').addEventListener('change', () => {
* document.querySelector('#audio').volume = convertInputToVolume(volume.valueAsNumber)
* })
* </script>
* ```
*
* @see https://www.dr-lex.be/info-stuff/volumecontrols.html
*/
export function convertInputToVolume(input: number, curve = 4) {
return input ** curve
}
/**
* If you have a logarithmic volume you can use this to convert it to a linear
* volume. You should use the same curve value that you used to convert the
* input.
*
* This is the inverse of {@link convertInputToVolume}.
*
* @see https://www.dr-lex.be/info-stuff/volumecontrols.html
*/
export function convertVolumeToInput(volume: number, curve = 4) {
return volume ** (1 / curve)
}
/** @internal */
function convertDecibelToVolumeUnsafe(db: number) {
return 10 ** (db / 20)
}
/**
* Convert a volume into a decibel value.
*
* The inverse of this function is {@link convertDecibelToVolume}.
*
* Note: If you're unfamiliar, decibels work a bit differently than most units.
*
* Decibels are a logarithmic unit of measurement. This means that each 10db
* increase is approximately twice as loud as the previous 10db increase.
*
* For example:
* - 0db is the faintest sound that humans can hear.
* - 10db is approximately twice as loud as 0db.
* - 20db is approximately twice as loud as 10db.
* - and so on...
*
* Because 0db is the faintest sound that humans can hear, you can't have a
* negative decibel value, where each -10db decrease is approximately half as
* loud as the previous -10db decrease.
*
* If you had a volume of `0` then it would be `-Infinity` decibels. To avoid
* returning `-Infinity` we use `minDb` to set the minimum decibel value.
*
* If you want to display negative decibel values to the user, you can use
* `minDb` to set the minimum decibel value.
*
* The inverse of this function is {@link convertDecibelToVolume}.
*/
export function convertVolumeToDecibel(volume: number, minDb = 0): number {
return volume <= convertDecibelToVolumeUnsafe(minDb)
? minDb
: 20 * Math.log10(volume)
}
/**
* Convert a decibel value into a volume.
*
* The inverse of this function is {@link convertVolumeToDecibel}.
*/
export function convertDecibelToVolume(decibel: number, minDb = 0): number {
return decibel <= minDb ? 0 : convertDecibelToVolumeUnsafe(decibel)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment