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.
Thank you for your time!
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;
}