2

I unfortunately hit a roadblock with this audio fading function I've made. It takes in a source, duration and a new clip. It is supposed to fade out the initial clip, replace the clip and lerp the volume back to 1.

public static IEnumerator FadeSwitchAudio(AudioSource audioSource, float duration, int clip)
{
    float firstTimer = 0;
    float secondTimer = 0;
    float start = audioSource.volume;

    // Fade audio out, works as intended 
    while (firstTimer < duration)
    {
        firstTimer += Time.deltaTime;
        audioSource.volume = Mathf.Lerp(start, 0.01f, firstTimer / duration);
        yield return null;
    }

    audioSource.clip = GameObject.FindWithTag("AudioManager").GetComponent<AudioManager>().clips[clip];

    // Fade audio back in, volume jumps immediately to 1 and audiosource stops having output
    yield return new WaitForSeconds(0.1f);
    while (secondTimer < duration)
    {
        secondTimer += Time.deltaTime;
        audioSource.volume = Mathf.Lerp(start, 1.0f, secondTimer / duration);
        yield return null;
    }
}

I have tried a lot of different timer functions, however, it seems that increasing the volume of an audiosource always breaks it. Is there a sure way to slowly increase the audio of a source without the source completely losing output? Here is a gif of the current behaviour in the inspector. Please excuse the low resolution but you can see the behaviour.

Unity Audio Lerping Issue

Thank you for your time!

  • I think issue with float start. try this `audioSource.volume = Mathf.Lerp(audioSource.volume, 1.0f, secondTimer / duration);` – Jaimin Aug 10 '21 at 05:24
  • @Jaimin nah that would be the wrong behavior. It would every frame interpolate between the current and target value. OP rather wants to interpolate linear between one start and target value ;) – derHugo Aug 10 '21 at 06:32

1 Answers1

1

Two issues here:

  • Only changing the AudioSource.clip doesn't do anything.

    Assigning clip with a new audio clip does not instantly change the clip that is being played

    You additionally need to start playing that new clip using AudioSource.Play.

  • Also as a new start for the second loop you do not want to use the original AudioSource.volume you have stored at the top of the Corouinte but rather the current one after fading out.

So just a little bit redactored I would use e.g.

private const float FADED_OUT_VOLUME = 0.01f;

public static IEnumerator FadeSwitchAudio(AudioSource audioSource, float duration, int clip)
{
    var originalVolume = audioSource.volume;

    // I prefer using for loops over while to eliminate the danger of infinite loops
    // and the need for "external" variables
    // I personally also find this better to read and maintain
    for(var timePassed = 0f; timePassed < duration; timePassed += Time.deltaTime)
    {
        audioSource.volume = Mathf.Lerp(originalVolume, FADED_OUT_VOLUME, timePassed / duration);

        yield return null;
    }

    // To be sure to end with clean values
    audioSource.volume = FADED_OUT_VOLUME;

    // If there is only one instance of `AudioManager` in your scene this is more efficient
    // in general you should fetch that AudioManager reference only ONCE and re-use it
    audioSource.clip = FindObjectOfType<AudioManager>().clips[clip];
    //audioSource.clip = GameObject.FindWithTag("AudioManager").GetComponent<AudioManager>().clips[clip];

    yield return new WaitForSeconds(0.1f);

    // Actually start playing the new clip
    audioSource.Play();

    for(var timePassed = 0f; timePassed < duration; timePassed += Time.deltaTime)
    {
        audioSource.volume = Mathf.Lerp(FADED_OUT_VOLUME, originalVolume, timePassed / duration);

        yield return null;
    }

    audioSource.volume = 1f;
}
derHugo
  • 83,094
  • 9
  • 75
  • 115