Search Unity

Audio AudioMixer updated via slider, but non-linear?

Discussion in 'Audio & Video' started by Rob-Meade, Oct 4, 2018.

  1. Rob-Meade

    Rob-Meade

    Joined:
    Oct 27, 2016
    Posts:
    56
    Hi all,

    I was wondering whether anyone could help with the following query.

    I followed Unity's AudioMixer tutorial and am happy that I can influence the volume of an audio mixer via a slider, but if you move the slider to halfway, this isn't half of the volume.

    Having had a look around online there is mention of using
    Mathf.Log10(sliderValue) * 20
    , and having a slider value between 0.0001 and 1.

    What I find when using this approach is that the maximum volume, as displayed in dB in the AudioMixer will never be above 0, and having the volume drop to -80dB seems a little unnecessary as it seems to become inaudible in excess of -40dB.

    So, how can I apply a linear slider to a non-linear volume? I'm assuming someone must have already done this, although a quick search of the forums seemed to show a lot of examples just popping the float value straight in.

    Any help would be appreciated.

    ----------
    Have been referring to these;

     
  2. Docaroo

    Docaroo

    Joined:
    Nov 7, 2017
    Posts:
    82
    You can't ... unfortunately Unity devs are retarded with the units they use for Audio. There's literally no reason why they couldn't present the audio volume as a logarithmic dB scale instead of a float from 0.0f - 1.0f but because they are programmers they only care about floats!

    You have to manually convert dB to float in order to know the dB equivalent.

    Here's a Linear Float to Decibel calculator that you will have to use ...

    http://www.playdotsound.com/portfol...making-sense-of-linear-values-in-audio-tools/

    Going from 1.0f to 0.5f is only reducing the volume by -6 dB ... you get used to it eventually.

    Just wait until you see the units they use in the SFX_Reverb plugin on the audio mixers ... there are dB AND mB ... MilliBELS!
     
    matous_volf likes this.
  3. StephaneB7

    StephaneB7

    Joined:
    Oct 23, 2012
    Posts:
    5
    Here's how I did it.

    Open the Audio Mixer via: Window > Audio > Audio Mixer and doc it to the right pane (so it's visible when you play)
    Expose a parameter, call it "Volume"
    Drag the Audio Mixer (created in the root of Assets folder) to the following script
    Create a slider with MinValue=0, MaxValue=1 and set its OnValueChanged event to the SetVolume() of the script

    I made a small tweak to the slider's volume when it was 0, otherwise the volume would decrease until it reaches zero and then rose to maximal volume.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class OptionsMenu : MonoBehaviour
    4. {
    5.     public UnityEngine.Audio.AudioMixer audioMixer;
    6.  
    7.     public void SetVolume(float decimalVolume)
    8.     {
    9.         var dbVolume = Mathf.Log10(decimalVolume) * 20;
    10.         if (decimalVolume == 0.0f)
    11.         {
    12.             dbVolume = -80.0f;
    13.         }
    14.         audioMixer.SetFloat("Volume", dbVolume);
    15.     }
    16. }
    17.  
     
    Ali_V_Quest likes this.
  4. Rob-Meade

    Rob-Meade

    Joined:
    Oct 27, 2016
    Posts:
    56
    Hi Stephane,

    Thank you for the reply and code example, appreciated.

    I don't think the above solution covers exactly what I mean though. For example;

    When the slider value is at 1 the AudioMixer db register as 0db, instead of 20.
    When the slider value is at 0.5 the AudioMixer db registers as -6db

    I think what this perhaps needs is the ability to covert the slider value from the range of 0 to 1 to a correct value between 20 and -40db.
     
  5. Weendie-Games

    Weendie-Games

    Joined:
    Feb 17, 2015
    Posts:
    75
    If someone bump into this, i found a solution on another thread:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.Audio;
    4. public class MixerControl : MonoBehaviour
    5. {
    6.     public AudioMixer audioMixer;
    7.     public Slider volumeSlider;
    8.     private void Start() {
    9.         volumeSlider.onValueChanged.AddListener((sliderValue) => {
    10.             audioMixer.SetFloat("Volume", remap(sliderValue, 0f, 1f, -40f, 20f, false, false, false, false));
    11.         });
    12.     }
    13.     public static float remap(float val, float in1, float in2, float out1, float out2,
    14.         bool in1Clamped, bool in2Clamped, bool out1Clamped, bool out2Clamped) {
    15.         if (in1Clamped == true && val < in1) val = in1;
    16.         if (in2Clamped == true && val > in2) val = in2;
    17.  
    18.         float result = out1 + (val - in1) * (out2 - out1) / (in2 - in1);
    19.  
    20.         if (out1Clamped == true && result < out1) result = out1;
    21.         if (out2Clamped == true && result > out2) result = out2;
    22.  
    23.         return result;
    24.     }
    25. }
     
  6. Ali_V_Quest

    Ali_V_Quest

    Joined:
    Aug 2, 2015
    Posts:
    138
    I think you can simply multiply the sliderValue by 8, this will double the slider value 4 times ( 1,2,4,8 ), each doubling adds 6 db to the resulting db value ( from 0 to 6 to 12 to 18 )
    Mathf.Log10(sliderValue*8) * 20 // this will change your slider value to be from -80 db to 18 db
     
  7. Thygrrr

    Thygrrr

    Joined:
    Sep 23, 2013
    Posts:
    700
    Protip: You can approximate the f(x) = log(x) with g(x) = sqrt(x)-1
    Then that pesky logarithm becomes much less annoying, as the square root will hit the 0 axis.

    upload_2023-12-2_1-32-24.png

    Also, Unity.Mathematics has a nice remap function. And if you want to give your users the opportunity to boost their channels beyond 0 decibels, you can just use the remap's top value (the 0 next to the -80) from 0 to something like 7 (double perceived loudness) or even all the way to 20. I prefer 3 which is the average headroom I try to leave in my mix, allowing users to fill that if they want.

    Code (CSharp):
    1. using Unity.Mathematics;
    2. using UnityEngine;
    3. using UnityEngine.Audio;
    4. using UnityEngine.Serialization;
    5. using UnityEngine.UI;
    6.  
    7. [RequireComponent(typeof(Slider))]
    8. public class MixerGroupSlider : MonoBehaviour
    9. {
    10.     public AudioMixerGroup group;
    11.  
    12.     [Tooltip("The minimum decibel value of the slider")]
    13.     public float minDB = -80;
    14.  
    15.     [Tooltip("The maximum decibel value of the slider")]
    16.     public float maxDB = 3;
    17.  
    18.     [Tooltip("Additionally scale the slider along a nonlinear curve to give more precision in the middle to top range.")]
    19.     [Range(0.1f, 1f)]
    20.     public float linearity = 0.5f;
    21.  
    22.  
    23.     [SerializeField]
    24.     [HideInInspector]
    25.     private Slider _slider;
    26.  
    27.     private void Awake()
    28.     {
    29.         if (!_slider) _slider = GetComponent<Slider>();
    30.     }
    31.  
    32.     private void OnEnable()
    33.     {
    34.         LoadValue();
    35.         _slider.onValueChanged.AddListener(OnValueChanged);
    36.     }
    37.  
    38.     private void OnDisable()
    39.     {
    40.         _slider.onValueChanged.RemoveListener(OnValueChanged);
    41.     }
    42.  
    43.     private void Start()
    44.     {
    45.         OnValueChanged(_slider.value);
    46.     }
    47.  
    48.     private void LoadValue()
    49.     {
    50.         group.audioMixer.GetFloat(group.name, out var decibels);
    51.         var normalized = math.saturate(math.remap(minDB, maxDB, 0, 1, decibels));
    52.         var nonlinear = math.pow(normalized, 1f / linearity);
    53.         var exponential = math.pow(10f, nonlinear);
    54.         var remapped = math.remap(1, 10, 0, 1, exponential);
    55.         _slider.value = remapped;
    56.     }
    57.  
    58.     private void OnValueChanged(float sliderValue)
    59.     {
    60.         var remapped = math.remap(0, 1, 1, 10, sliderValue);
    61.         var logarithmic = math.saturate(math.log10(remapped));
    62.         var nonlinear = math.pow(logarithmic, linearity);
    63.         var decibels = math.remap(0f, 1f, minDB, maxDB, nonlinear);
    64.         group.audioMixer.SetFloat(group.name, decibels);
    65.     }
    66.  
    67.     private void OnValidate()
    68.     {
    69.         if (!_slider) _slider = GetComponent<Slider>();
    70.         _slider.minValue = 0;
    71.         _slider.maxValue = 1;
    72.     }
    73. }
    With these defaults, a MixerGroup at -7 dB(A), not an uncommon setting for games with rich mixes, will have its slider at around 75% of its range.

    To the user, this feels like fine-grained, intuitive control. If you don't want that, you can set the linearity exponent to 1 in the inspector.

    If you set +7 as the maxDB, 0 db sits near the middle of the slider (allowing the user to "up to double" the loudness by sliding it to the max. However, this can lead to some logistics issues with headroom, so plan ahead when you design your game's mix. :D

    I find +3 max the most user-friendly, and 0 max is the most safe (you 100% know your mix will be, at most, the loudest you ever mixed it to.

    Note: Technically this math is fudged, as we're using the properties of another interval of the logarithm curve to augment our essential polynomial (nonlinear) curve. However, I find this both robust and pleasant for the user.

    The green and red curve here are with linearity 0.5 and 1.0, respectively.

    The red line with 1.0 is exactly between the "ideal logarithm that crosses below 0 at 10%" and the "offset logarithm that starts at 0%, but ends at 90%". That would be the "best" log slider you can build that actually uses the whole length of the GUI slider value space.

    However, The 0.5 curve has this hump near the mouse cursor that protrudes and drastically improves the auditory response of the slider in that area, and makes it less harshly sensitive near the top (100%) end.

    upload_2023-12-2_14-23-5.png
     
    Last edited: Dec 3, 2023