Fade Out Audio Source

I feel like I am asking too much and not contribuing to this Community, so here is a little code that may be useful to someone of you. It fades out sound (audioSource) over time (seconds). :smile:

Just make this script named AudioFadeOut and you can call this function from anywhere you want:

using UnityEngine;
using System.Collections;

public static class AudioFadeOut {

    public static IEnumerator FadeOut (AudioSource audioSource, float FadeTime) {
        float startVolume = audioSource.volume;

        while (audioSource.volume > 0) {
            audioSource.volume -= startVolume * Time.deltaTime / FadeTime;

            yield return null;
        }

        audioSource.Stop ();
        audioSource.volume = startVolume;
    }

}

You could use somethnig like this ...

StartCoroutine (AudioFadeOut.FadeOut (sound_open, 0.1f));

//or:

public AudioSource Sound1;

IEnumerator fadeSound1 = AudioFadeOut.FadeOut (Sound1, 0.5f);
StartCoroutine (fadeSound1);
StopCoroutine (fadeSound1);
28 Likes

I can't seem to get this script to work, and what I need is my background music to fade out before next scene loads.

2 Likes

Thanks for posting :smile: Saved me some time

3 Likes

Thank you too! Exactly what I wanted.

The script will persist through the entire game allowing you to change your music on the go.
Full Inspector Image: https://postimg.org/image/xjjqemfp3/

How to Setup:
0: Go to your very first (scene)
1: Create an Empty Object and call it MediaPlayer
2: Create a script called MusicClass
3: Create Empty
4: Add AudioSource to the object you created (Make Volume ‘0’ & Loop ‘true’ if needed)
5: Put the music you want to play inside the AudioSource
6: Put all the Music Objects inside the MediaPlayer Object
If you want to add more music, start from (3)

To call the functions of MusicClass
EXAMPLE->>>PlayMusic(“MUSIC NAME - NAME OF THE TRANSFORM”);

FindObjectOfType<MusicClass>().PlayMusic("Beat"); // Transform name is called Beat
using System.Collections;
using UnityEngine;

public class MusicClass : MonoBehaviour
{
    private AudioSource[] _audioSources;
    public float fadeSpeed = 0.5f;
    public float fadeInOutMultiplier = 0.0f;
    public bool isPlaying;

    public string playingTrackName = "Nothing";
    public int playingTrackIndex;
    public float playingTrackVolume = 0.000f;

    public string lastTrackName = "Nothing";
    public int lastTrackIndex;
    public float lastTrackVolume = 0.000f;

    public IEnumerator FadeOutOldMusic_FadeInNewMusic()
    {
        _audioSources[playingTrackIndex].volume = 0.000f;
        _audioSources[playingTrackIndex].Play();
        while (_audioSources[playingTrackIndex].volume < 1f)
        {
            _audioSources[lastTrackIndex].volume -= fadeSpeed * 2;
            _audioSources[playingTrackIndex].volume += fadeSpeed * 2;
            //Debug.Log("Fade: " + lastTrackName + " " + _audioSources[lastTrackIndex].volume.ToString() + " Rise: " + playingTrackName + " " + _audioSources[playingTrackIndex].volume.ToString());
            yield return new WaitForSeconds(0.001f);
            lastTrackVolume = _audioSources[lastTrackIndex].volume;
            playingTrackVolume = _audioSources[playingTrackIndex].volume;
        }
        _audioSources[lastTrackIndex].volume = 0.000f; // Just In Case....
        _audioSources[lastTrackIndex].Stop();

        lastTrackIndex = playingTrackIndex;
        lastTrackName = playingTrackName;
        isPlaying = true;
    }

    public IEnumerator FadeInNewMusic()
    {
        _audioSources[playingTrackIndex].volume = 0.000f;
        _audioSources[playingTrackIndex].Play();
        while (_audioSources[playingTrackIndex].volume < 1f)
        {
            _audioSources[playingTrackIndex].volume += fadeSpeed * 2;
            //Debug.Log("Fading In: " + _audioSources[track_index].volume.ToString());
            yield return new WaitForSeconds(0.001f);
            playingTrackVolume = _audioSources[playingTrackIndex].volume;
        }
        lastTrackIndex = playingTrackIndex;
        lastTrackName = playingTrackName;
        isPlaying = true;
    }

    private void Awake()
    {
        DontDestroyOnLoad(transform.gameObject);
        _audioSources = GetComponentsInChildren<AudioSource>();
    }

    public void PlayMusic(string transformName)
    {
        for (int a = 0; a < _audioSources.Length; a++)
        {
            if (_audioSources[a].name == transformName)
            {
                Debug.Log("Found Track Name (" + transformName + ") at Index(" + a.ToString() + ")");
                playingTrackIndex = a;
                playingTrackName = transformName;
                break;
            }
        }
        if (playingTrackIndex == lastTrackIndex)
        {
            Debug.Log("Same Track Selected");
            return;
        } else {
            if (isPlaying)
            {
                Debug.Log("Fading in new music - Fading out old music");
                StartCoroutine(FadeOutOldMusic_FadeInNewMusic());
            } else {
                Debug.Log("Fading in new music");
                StartCoroutine(FadeInNewMusic());
            }
        }
    }
}
2 Likes

Hello,

Thanks Boris1998 for sharing, it helped me in my current project with audio.

I added another method for FadeIn, sharing back here my updated class:

public static class AudioFadeScript
{
    public static IEnumerator FadeOut(AudioSource audioSource, float FadeTime)
    {
        float startVolume = audioSource.volume;

        while (audioSource.volume > 0)
        {
            audioSource.volume -= startVolume * Time.deltaTime / FadeTime;

            yield return null;
        }

        audioSource.Stop();
        audioSource.volume = startVolume;
    }

    public static IEnumerator FadeIn(AudioSource audioSource, float FadeTime)
    {
        float startVolume = 0.2f;

        audioSource.volume = 0;
        audioSource.Play();

        while (audioSource.volume < 1.0f)
        {
            audioSource.volume += startVolume * Time.deltaTime / FadeTime;

            yield return null;
        }

        audioSource.volume = 1f;
    }
}

Using example:

            // stop menu music
            StartCoroutine(AudioFadeScript.FadeOut(audioMenuMusic, 0.5f));

            // start game music
            StartCoroutine(AudioFadeScript.FadeIn(audioGameMusic, 5f));

// chall3ng3r //

16 Likes

You can also create an extension class, to be able to call the fade out easily like this:

sound.FadeOut(0.5f);
using System.Collections;

namespace UnityEngine
{
    public static class AudioSourceExtensions
    {
        public static void FadeOut(this AudioSource a, float duration)
        {
            a.GetComponent<MonoBehaviour>().StartCoroutine(FadeOutCore(a, duration));
        }

        private static IEnumerator FadeOutCore(AudioSource a, float duration)
        {
            float startVolume = a.volume;

            while (a.volume > 0)
            {
                a.volume -= startVolume * Time.deltaTime / duration;
                yield return new WaitForEndOfFrame();
            }

            a.Stop();
            a.volume = startVolume;
        }
    }
}
4 Likes

yeah its 2 years old but saw your script and changed a couple things, first i added a max volume to fade in simple change, but second i added a check for if its fading as if you call fadeOut and fadeIn in relatively quick succession the coroutines fight for the volume and nothing gets called heres my simple fix

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class SoundFader
{
public static bool isFading;
public static IEnumerator FadeOut(AudioSource audioSource, float FadeTime)
{
isFading = true;
float startVolume = audioSource.volume;
while (audioSource.volume > 0)
{
audioSource.volume -= startVolume * Time.deltaTime / FadeTime;
yield return null;
}
audioSource.Stop();
audioSource.volume = startVolume;
isFading = false;
}
public static IEnumerator FadeIn(AudioSource audioSource, float FadeTime, float max)
{
while(isFading){
yield return new WaitForSeconds(0.5f);
}
float startVolume = 0.2f;
audioSource.volume = 0;
audioSource.Play();
while (audioSource.volume < max)
{
audioSource.volume += startVolume * Time.deltaTime / FadeTime;
yield return null;
}
isFading = false;
audioSource.volume = max;
}
}

3 Likes

Try this (via a variable adjustedVolume)

    public static IEnumerator FadeOut (AudioSource audioSource, float FadeTime) {
        float startVolume = audioSource.volume;
        float adjustedVolume = startVolume;

        while (adjustedVolume > 0) {
            adjustedVolume -= startVolume * Time.deltaTime / FadeTime;
            audioSource.volume = adjustedVolume;
            Debug.Log (adjustedVolume);
            yield return null;
        }

        audioSource.Stop ();
        audioSource.volume = startVolume;
    }

It seems that manipulating volume like audiosource.volume -= step doe not work for all.
I have 2017.4.2f2

2 Likes

This thread helped me alot so thank you to the OP and everyone who has contributed. Google also seems to like it alot too when searching for audio crossfading. If anyone needs “set and forget” crossfading between two audio sources, I made this snippet:

private bool audioBlendInprogress = false;
//----------------------------------
// AUDIO CROSSFADE
//----------------------------------
private IEnumerator CrossFadeAudio(AudioSource audioSource1, AudioSource audioSource2, float crossFadeTime, float audioSource2VolumeTarget)
{
    string debugStart = "<b><color=red>ERROR:</color></b> ";
    int maxLoopCount = 1;
    int loopCount = 0;
    float startAudioSource1Volume = audioSource1.volume;

    if(audioSource1 == null || audioSource2 == null)
    {
        Debug.Log(debugStart + transform.name + ".EngineControler.CrossFadeAudio recieved NULL value.\n*audioSource1=" + audioSource1.ToString() + "\n*audioSource2=" + audioSource2.ToString(), gameObject);
        yield return null;
    }
    else
    {
        audioBlendInprogress = true;

        audioSource2.volume = 0f;
        audioSource2.Play();

        while ((audioSource1.volume > 0f && audioSource2.volume < audioSource2VolumeTarget) && loopCount < maxLoopCount)
        {
            audioSource1.volume -= startAudioSource1Volume * Time.deltaTime / crossFadeTime;
            audioSource2.volume += audioSource2VolumeTarget * Time.deltaTime / crossFadeTime;
            loopCount++;
            yield return null;
        }

        if (loopCount < maxLoopCount)
        {
            audioSource1.Stop();
            audioSource1.volume = startAudioSource1Volume;
            audioBlendInprogress = false;
        }
        else
        {
            Debug.Log(debugStart + transform.name + ".EngineControler.CrossFadeAudio.loopCount reached max value.\nloopCount=" + loopCount + "\nmaxLoopCount=" + maxLoopCount, gameObject);
        }
    }
}

It simply takes the two audio sources and fades across the two audio sources. The benefit of this method is that it’s “set and forget” meaning it runs in a coroutine not in Update. Not that it’s any better than anything else mentioned here, it’s just another option. It also includes a safety switch (loopCount) that should be included in every “while” or “do” statement in my opinion.

Anyways, to call it you would use:

StartCoroutine(CrossFadeAudio(audioSource1, audioSource2, 10f, 1f));

The first parameter “audioSource1” is the currently playing audio source.
The second “audioSource2” is the audio source to crossfade too.
Third is the time in seconds to do the fade.
Forth is the target volume of audio source 2 (1f = 100%).

Also, the “audioBlendInprogress” can be used to check if a fade is in progress.

private bool audioBlendInprogress = false;

My real world example of using this method:

private void StartStopEngine()
{
        if (audioBlendInprogress == false)
        {
            if (engineIsRunning == false)
            {
                audioSource1.clip = engineData.audioEngineStart;
                audioSource1.loop = false;
                audioSource2.clip = engineData.audioEngineIdle;
                audioSource2.pitch = 0.5f;
                audioSource2.loop = true;

                audioSource1.Play();
                StartCoroutine(CrossFadeAudio(audioSource1, audioSource2, 10f, 1f));
                engineIsRunning = true;
            }
            else
            {
                audioSource1.clip = engineData.audioEngineShutDown;
                audioSource1.loop = false;
                StartCoroutine(CrossFadeAudio(audioSource2, audioSource1, 3f, 1f));
                engineIsRunning = false;
            }
        }
}

Here I have a audio clip of an engine start and an engine idle. I wanted to play the engine start then crossfade to the idle clip. I first check to see if a crossfade is in progress. Then check if the engine is running. If I made it past that, I then set up the audio sources and start playing the engine start clip. Then I call the “CrossFadeAudio()” coroutine to fade the audio from engine start, too engine idle.

The “else” for “engineIsRunning” is to fade between engine idle and the engine shutdown clip. I have a toggle input to start and stop the engines.

I hope this helps someone.

Edit: I noticed I left my debug info in the snippet and was going to remove it. But then decided to leave it in and make it self contained as it may help someone. So the main script may look more complicated than it really is lol ;-).

3 Likes

I feel like everything is being overcomplicated here. If you aren't crossfading two loops just use Invoke.

    Invoke("InvokeLoop", (introSource.clip.length - 3.5f));
    public void InvokeLoop()
    {
        musicLoopSource.clip = menuLoop;
        musicLoopSource.loop = true;
        musicLoopSource.Play();
    }

There’s also an official audio mixer from unity if you guys don’t mind starting from scratch. This tutorial helped me a ton.

Thanks a lot! Did save me some time and worked like a charm :slight_smile:

Cheers! If you only need to do this on one occasion then you can just take the coroutine out of it and place it in whatever script you like.

Up! This subject is great, thanks for sharing, Borris1998 ! :smile:

doesn’t work in unity 2018, my audiosource just decrease a little bit and then stop to decrease…

Thank you!

Works a treat for me - just remember that it won’t work if you change scene too quickly as the object will be destroyed and fading will stop.

I did some minor changes to what chall3ng3r proposed and used the power of coroutines and extensions. I hope this helps someone :slight_smile:

public static class AudioSourceExt
    {
        public static IEnumerator CrossFade(
            this AudioSource audioSource,
            AudioClip newSound,
            float finalVolume,
            float fadeTime)
        {
            // in here we wait until the FadeOut coroutine is done
            yield return FadeOut(audioSource, fadeTime);
            audioSource.clip = newSound;
            yield return FadeIn(audioSource, fadeTime, finalVolume);
        }
       
        public static IEnumerator FadeOut(this AudioSource audioSource, float fadeTime)
        {
            float startVolume = audioSource.volume;
            while (audioSource.volume > 0)
            {
                audioSource.volume -= startVolume * Time.deltaTime / fadeTime;
                yield return null;
            }
            audioSource.Stop();
            audioSource.volume = 0;
        }
        public static IEnumerator FadeIn(this AudioSource audioSource, float fadeTime, float finalVolume)
        {
            float startVolume = 0.2f;
            audioSource.volume = 0;
            audioSource.Play();
            while (audioSource.volume < finalVolume)
            {
                audioSource.volume += startVolume * Time.deltaTime / fadeTime;
                yield return null;
            }
            audioSource.volume = finalVolume;
        }
    }

Usage would be:

float finalVolume = 1.0f;
float fadeTime = 2f;

if (myAwesomeNewSoundClip != null)
                {
                    StartCoroutine(audioSource.CrossFade(
                        newSound: myAwesomeNewSoundClip,
                        finalVolume: finalVolume, 
                        fadeTime: fadeTime));
                }
                else
                {
                    StartCoroutine(audioSource.FadeOut(fadeTime));
                }
2 Likes

Hello folks... with the extension methods here... it's failing to get the Monobehaviour for me... even though it's getting the game object fine ... any ideas why?! "NullReferenceException: Object reference not set to an instance of an object"