UI Volume Control Graphic

The right way to make a volume slider in Unity (using logarithmic conversion)

In Articles by John22 Comments

Creating a UI slider volume control in Unity is straightforward, by using exposed parameters, the Audio Mixer and a simple script. This is useful for creating UI audio volume controls for your player.

There’s just one problem…

…Unity’s standard tutorial, although good, misses out on a crucial step that makes the slider control much too sensitive and difficult to use.

This happens because the slider value is linear but the audio mixer value (the attenuation) is logarithmic.

Luckily, however, there’s a very simple fix. In this post I’ll show you how to prevent the sensitive slider issue and make a, smooth, audio control slider:

If you haven’t already seen it, you can check out Unity’s official tutorial here, or my own tutorial video below, but if not, don’t worry, because you’ll also find step by step instructions later on in this post that include a fix for the sensitive slider issue.

The Sensitive Slider Issue: Why is this a problem?

If you create an audio slider using the standard method, and reduce the slider to about halfway, you’ll find that the audio isn’t half as loud (as you might expect), in fact it’s virtually silent.

This is because the volume range of the Audio Group fader, which is in decibels, is logarithmic meaning that the increments are exponential. Each increment on the scale represents a greater and greater value: e.g. 10, 100, 1000 and so on. In comparison the slider scale is linear and the increments are evenly spaced: e.g. 1, 2, 3.

Normally we perceive half volume to be at around -6db. However, moving the slider to halfway doesn’t do this. In fact, at halfway, it actually sets a value of -40db which is almost at the bottom.

To fix this, the linear slider value needs to be converted.

The difference this makes is clear when comparing the two methods side by side:

Unity Volume Slider Example
On the far right is the fader response using the standard ‘direct’ method. To the left of this is a fader using the ‘converted’ method

The quick & easy fix to prevent the sensitive slider issue

If you already have this issue, and you just want to fix it, here’s what to do:

  • Use a slider value range of 0.0001 – 1
    instead of -80db – 0db (the 0.0001 is important, and stops the slider breaking at zero)
  • When passing the slider value to the SetFloat function, convert it using Mathf.Log10(value) * 20;
    e.g. mixer.SetFloat(“MusicVol”, Mathf.Log10(sliderValue) * 20);

For full instructions, including this fix, follow the steps below.

How to create a UI volume control slider in Unity (that actually works)

Create the slider

  1. In the hierarchy select Create > UI > Slider to create a UI Slider for your volume control
  2. Select the Slider object and set the Min Value to 0.0001ย (the logarithmic conversion will not work correctly at zero)
  3. Set the Value to 1
    Unity Volume Slider Inspector Settings

Expose the Audio Mixer Group volume to scripting

  1. Select the Audio Mixer Group that you want to control with the slider
  2. In the inspector, under attenuation, right click on the volume label and select Expose ‘Volume (of Music)’ to script
    Expose Parameter in Unity
  3. In the Audio Mixer Panel, select the Exposed Parameters dropdown and give the, now exposed, volume parameter a name. e.g. “MusicVol”. You’ll need to use the parameter name given here when accessing it from a script.
    Exposed Parameters Menu

Connect the slider with a script

  1. Add a new C Sharp script to the slider object called SetVolume or similar.
  2. Open it for editing and type, or paste, the following script:
  3. Save the script and return to Unity.
  4. Use circle select to connect the mixer reference variable to the Mixer that contains the exposed parameter.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;

public class SetVolume : MonoBehaviour {

    public AudioMixer mixer;

    public void SetLevel (float sliderValue)
    {
        mixer.SetFloat("MusicVol", Mathf.Log10(sliderValue) * 20);
    }
}

Important: If you’re just copying the function, not the whole script, remember to add the using UnityEngine.Audio namespace at the top of the script. This is required to access Audio Mixer functions.

Add the function to the slider

  1. Select the slider object and add a new ‘On value changed’ event.
  2. Drag the SetVolume script to the field or set it by using circle select.
  3. Select the function dropdown, where it currently reads ‘no function’. Select the SetVolume script and then select the SetLevel function (listed under Dynamic float*).
    Connect slider to volume control function in Unity

* If the function doesn’t appear under the dynamic float list make sure that 1. the access modifier for the function is set to public and 2. that the function takes a single float parameter.

Save the scene and hit play to test

The slider should now control the Audio Mixer Group fader.

Repeat to create music and audio volume controls. You can even use multiple mixer groups to give players more granular control over voices, sound effects, music and other sound categories.

Extending the script: How to save and load the volume slider value

Now that you’ve created a volume control, you may wish to save the value whenever it’s changed so that the volume level, and the slider position, stay the same if you load a different scene or restart the game.

Thankfully, this is easy to do by using the PlayerPrefs class, which allows you to store and reload player preferences between games. By adding just a few new lines to the same script we will be able to:

  • Save the slider value whenever it’s changed (this sets the Player Preference, using a string value to identify it).
  • Recall the saved slider value whenever the script is loaded or, if there isn’t a saved value, load a default value instead.

Here’s how to use PlayerPrefs to save the volume slider value:

  1. Add the using UnityEngine.UI; namespace to the script.
  2. Declare a public Slider variable, call it slider or similar then connect it in the inspector
  3. In the SetLevel function, add a new line: PlayerPrefs.SetFloat(“MusicVolume”,sliderValue);
    This will save the value of the slider whenever it’s changed.
  4. In the Startย function, add a new line: slider.value = PlayerPrefs.GetFloat(“MusicVolume”, 0.75f);
    It’s important to include the default value parameter (in my case I’ve used 0.75f). Otherwise the default for the variable type will be used which, for a float, is 0.

Here’s what the new script looks like:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;

public class SetVolume : MonoBehaviour {

    public AudioMixer mixer;
    public Slider slider;

    public void Start
    {
        slider.value = PlayerPrefs.GetFloat("MusicVolume", 0.75f);
    }
    public void SetLevel (float sliderValue)
    {
	mixer.SetFloat("MusicVol", Mathf.Log10(sliderValue) * 20);
        PlayerPrefs.SetFloat("MusicVolume", sliderValue);
    }
}

Note that changing the slider value in Start also triggers the SetLevel function, so it updates the mixer to the correct loaded value too.

Comments

  1. Thank you so much for this! It’s so obvious once you’ve explained it so clearly ๐Ÿ™‚

  2. I was curious if you had a similar scaling function for a Low Pass filter cutoff. Since the values are in Herz and not decibels, the numbers are different but I can’t quite figure it out. Thanks!

  3. Just a heads up, using 0.001 as the slider minimum will only allow the minimum volume to go to -60 dB. You’ll want an extra zero in there to make it go all the way to -80 dB.

    log(0.001) = -3 * 20 = -60
    log(0.0001) = -4 * 20 = -80

    1. John Author

      Thanks for this. I actually hadn’t experienced this issue at all with Math.Log and a minimum value of 0.001 however this does happen when using Log10, as has been suggested in another comment so thank you for your advice, I’ve updated the article.

    1. John Author

      Thanks for this, I’ve now tried this and I’ve updated the article to use Log10 instead as, when used with a minimum value of 0.0001, which Marshall suggested in another comment, creates a slightly smoother slider travel than before with an exact -80db lower limit (my original method would bottom out at more than -100db). Thanks for your advice.

  4. Hi,

    Thanks for this article.

    Quick question – why prevent going above 0db on the audio mixer? The above solution is great but means that 100% on the slider is equal to 0db in the mixer.

    Rather than the game offering 0db as a maximum, what if I wanted to offer +20db as the maximum (100%) but set defaults to whatever percentage 0db would be. This would give the player the ability to go louder, or quieter.

    I’m not particularly familiar with all things acoustic, so my apologies if this is a daft question, or if I’ve missed something obvious.

    Thanks in advance for any response ๐Ÿ™‚

    1. John Author

      Hi there, to answer your question 0db is the upper limit for digital audio. An audio signal that tries to go above 0db will clip and distort (where clipping is the flattening of an audio signal).

      The fader value only represents how much an audio signal is attenuated or increased so a single audio signal passing through a fader that’s set to 0db would play at its original level, meaning it can’t clip. If you were to increase the fader level above 0db, then the signal runs the risk of clipping, depending on how loud the original audio signal is.

      Put simply, you can increase the fader above 0db without clipping but, in most cases, you shouldn’t. If you’re finding that your audio signal is too low at 0db then it’s likely that the audio file itself is too quiet.

      Hope that helps!

  5. Hi John, thank you for such a nice tutorial but I have a question. So, I previously had all my child mixers mixed to the levels I wanted and by doing this I had to get rid of it. For instance, I want one of them to start at -15dB and for that value to be the max possible at all times, so kind of equivalent to 0dB on the slider. I’ve played around but haven’t managed to find a good way to do it yet. Could you please recommend a solution? Thank you!

    1. John Author

      Hi Bruno, it’s possible to nest entire Mixers and Mixer Groups within one another which routes the audio through them. In theory you could keep all of your current mixers and settings as you want them and route the output into a separate mixer that’s just for player volume control. A -15db signal that’s routed into a fader set at 0db will stay at -15db, as no gain or attenuation is applied, making -15db the maximum for that signal in this example. I don’t know what’s best for your specific set up without seeing it but if you do want any advice email me@johnleonardfrench.com or keep an eye out for my upcoming post on managing Audio Mixers in Unity.

  6. Hello. This is such a nice tutorial but I also have a question. It’s about the OnValueChange. Well, I followed exactly what is stated in your tutorial, but in my dropdown function, only “No function” and “MonoScript” were the only choices available. Could you please recommend solution? Thank you in advance.

    1. John Author

      It sounds like you may have added the script asset from the project folder to the slider object, instead of the instance of the script that’s on the slider gameobject in the scene.

      If you’ve added the SetVolume script to the slider, as this example, be sure to drag that same instance of the script to the OnValueChange field.

      Hope that helps,
      John.

      1. Thank you for this. It helped me resolve my problem. But I have another question if you don’t mind. I’m really new to Unity and using this to create a school project that’s why. Lol. So here is my other question, I was wondering about how to this one… “Declare a public Slider variable, call it slider or similar then connect it in the inspector”. How do you connect the variable to the inspector? Thank you once again. ๐Ÿ™‚

        1. Also, last question. I have another error regarding the “value” in slider.value(PlayerPrefs.GetFloat(“musicVol”, 1.0f));.

          Error is: “Non-invocable member ‘Slider.value’ cannot be used like a method”

          Can you help me out again with this? It would really be another big help. Thank you

          1. John Author

            The error was a typo in the article (my bad) I’ve updated the article. The line needs to be:

            slider.value = PlayerPrefs.GetFloat(“MusicVol”, 0.75f);

        2. John Author

          The easiest way to do this is to select the object with the script on it, which may also be the slider, and then click and drag the slider object from the scene hierarchy to the slider variable field. You can also use the circle select button to select the slider (remember to select the scene tab, not assets).

  7. I was looking fo this info six months ago and found nothing as straightforward as this. Googled randomly again tonight and this popped up, not only answering my logarithmic slider question in general but also sending me to improve my audio sliders. Thanks for the helpful advice ๐Ÿ™‚

Leave a Comment