dB and semitone conversion

One of the first pieces of code I implement in any audio coding project are the conversion of dB (Decibel) to amplitude factor, semitones to playback rate and vice versa. In game audio we often increase the amount of variation by not just picking random sound assets, but also randomizing playback-volume and pitch of sound effects. I sometimes see people implementing these as amplitude factor (for volume) and playback rate (for pitch) but there are a few reasons we would want to do that in dB / semitones.

The human hearing works in a logarithmic scale where percieved volume is concerned. A sound requires exponentially more acoustic power to reached increased perceived loudness. The frequency needs to double each time to arrive at the human brain as an octave increase. The most likely scenario is that we want to randomize the volume of a sound on a predictable loudness / musical note scale and don’t care so much about the actual sound pressure or frequency.

The way the human ear percives frequency is also logarithmic albeit on a different scale. To perceive a pitch shift of an octave, the sound needs to play at twice the requency.

If we expose volume and random amount to our sound designers in Decibel format & pitch parameters in semitones, they will immediately understand which values have which effect on the loudness and pitch of a sound. If we present them with options to define amplitude- and pitch-factor there will be a disconnect between their work flow and our game audio implementation.

  • – 6 dB = factor of 0.5
  • – 10 dB = factor of 0.3162278
  • – 12 dB = factor of 0.2511886
  • – 18 dB = factor of 0.1258925
  • – 20 dB = factor of 0.1
  • – 30 dB = factor of 0.03162277
  • – 45 dB = factor of 0.005623413
  • – 72 dB = factor of 0.0002511887

The functions I’m using here (as seen below) introduce floating point errors. That’s why -12 dB is translated to such an off value…
Here is a visualization of how these values interact with each other in a little Unity GUI I use to check my sanity when working with volume factors:

an animation showing a conversion tool

Do these numbers look intuitive?

There is a certain logic to it but sound people already have trained an understanding of what certain dB & semitone values mean. They practices them every day using Digital Audio Workstations, plugins and tools for sound design and composition. There is established language for talking about loudness and pitch. I advocate for helping sound people create better mixes, manipulate sound in a intuitive fashion and work with formats they are comfortable with.

I here share the code I use in most game projects so our sound designers can interact with the tools I create for them in a comfortable fashion. It’s written in C# and depends on the Unity game engine but should be easy to translate to any language and platform. Please feel free to use and share them far and wide 🙂

using UnityEngine;
public class AudioConversionUtilities
{
  private static float twelfthRootOfTwo =
    Mathf.Pow(2, 1.0f / 12);
  // convert from semitones to pitch factor
  public static float StToPitch(float st)
  {
    return Mathf.Pow(twelfthRootOfTwo, st);
  }
  // convert from pitch factor to semitones
  public static float PitchToSt(float pitch)
  {
    return Mathf.Log(pitch, twelfthRootOfTwo);
  }
  // convert from dB to amplitude factor
  public static float DecibelToLin(float dB)
  {
    if (dB > -80)
      return Mathf.Clamp01(
        Mathf.Pow(10.0f, dB / 20.0f)
      );
    else
      return 0;
  }
  // convert from amplitude factor to dB
  public static float LinToDecibel(float linear)
  {
    if (linear > 0)
      return Mathf.Clamp(
        20.0f * Mathf.Log10(linear), -80f, 0f
      );
    else
      return -80.0f; 
  }
}

If you insist on using linear values (maybe you want to save all the CPU cycles), then beware that you cannot add them together. You may only multiply them to achieve predictable volume and pitch values.