Fixing sound pops when changing audio mixers volumes at runtime

Unity Audio is a bit cryptic, and changing volumes often results in artifacts (pops). The following function attached to an SR_Sound script on my SoundController game object fixes it. You can use the same technique with audio sources too, but those are a bit less cryptic. I will include that as well.

AudioMixer SoundMixer = SoundController.GetComponent<SR_Sound>().Mixer;
StartCoroutine(SR_Sound.MixerSetVolume(SoundMixer, "Thrusters", 30f));
//to avoid annoying clicks in audio mixer volume changes
    public static IEnumerator MixerSetVolume(AudioMixer _Mixer, string _WhichExposedParam, float _Vol = 0.001f, float _FadeLength = 0.1f)
    {
        //Debug.Log("Fading out soundfile" + _AudioSource.name);

        if(_Vol == 0f) { _Vol = 0.001f; }

        float _StartVolume;
        bool __IsMixerParamExposed = _Mixer.GetFloat(_WhichExposedParam, out _StartVolume);
        Extensions.Log(_WhichExposedParam + " mixer = " + _StartVolume);
        float _EndVolume = _Vol;

        float _StartTime = Time.time;

        if (_StartVolume > _EndVolume)
        {
            while (Time.time < _StartTime + _FadeLength)
            {
                _Mixer.SetFloat(_WhichExposedParam, _StartVolume - ((_StartVolume - _EndVolume) * ((Time.time - _StartTime) / _FadeLength)));
                yield return null;
            }
        }
        else
        {
            while (Time.time < _StartTime + _FadeLength)
            {
                _Mixer.SetFloat(_WhichExposedParam, _StartVolume + ((_EndVolume - _StartVolume) * ((Time.time - _StartTime) / _FadeLength)));
                yield return null;
            }
        }

    }

To tame Audio Sources:

public static IEnumerator VolumeFadeOut(AudioSource _AudioSource, float _FadeLength = 0.1f)
    {
        //Debug.Log("Fading out soundfile" + _AudioSource.name);

        if (MasterVolume == 0f) { yield break; }

        float _StartVolume = _AudioSource.volume;
        float _EndVolume = 0f;
        float _StartTime = Time.time;
        while (Time.time < _StartTime + _FadeLength)
        {
            _AudioSource.volume = _StartVolume + ((_EndVolume - _StartVolume) * ((Time.time - _StartTime) / _FadeLength));
            yield return null;
        }
        if (_EndVolume == 0) { _AudioSource.Stop(); }
    }

    public static IEnumerator VolumeFadeIn(AudioSource _AudioSource, float _EndVolume, float _FadeLength = 0.1f)
    {
        //Debug.Log("Fading in soundfile"+_AudioSource.name);

        if (MasterVolume == 0f) { yield break; }

        _AudioSource.volume = 0f;
        _AudioSource.Play();
        float _StartVolume = 0f;
        float _StartTime = Time.time;
        while (Time.time < _StartTime + _FadeLength)
        {
            _AudioSource.volume = _StartVolume + ((_EndVolume - _StartVolume) * ((Time.time - _StartTime) / _FadeLength));
            yield return null;
        }
    }

Aren’t these coroutines? I think you gotta StartCoroutine them or not much will happen…

1 Like

bah! you are right!

If I only had a dollar for every time I inadvertently “called” a coroutine without handing it off to StartCoroutine()… :slight_smile:

1 Like

Come to think of it, it really should be a compiler warning. I don’t think there can be any side effects from simply creating an IEnumerator and doing nothing with it… it’s truly just a no-op and unlikely to be what the engineer intended.