Issues Fading in Music on Scene Load

Hi People,

I am trying to get my game to fade in music when a scene loads.

I have an Audio Manager singleton that is being retained through scene loads. However I am having issues with the fading in working correctly. The FadeOut before the scene load works fine but the FadeIn has some odd issues.

I call the below IEmumerator from a function in the AudioManager.

        public IEnumerator IFadeIn(string _name, float _targetVolume, float _duration)
        {
            Music m = musics.Find(music => music.name == _name);

            if (m == null)
            {
                Debug.LogError("Music name" + _name + "not found!");
                yield return null;
            }
            else
            {
                if (fadeIn == false)
                {
                    fadeIn = true;
                    instance.fadeInUsedString = _name;

                    m.source.volume = 0f;
                    m.source.Play();
                    Debug.Log("Playing: " + _name);
                    while (m.source.volume < _targetVolume)
                    {
                        m.source.volume += Time.deltaTime / _duration;
                        yield return null;

                    }
                    yield return new WaitForSeconds(_duration);
                    fadeIn = false;
                }
                else
                {
                    Debug.Log("Unable to fade In 2 music tracks at the same time!");
                    StopMusic(fadeInUsedString);
                    PlayMusic(_name);
                }
            }
        }

The above is the FadeIn IEnumerator which should smoothly fade in the music from 0f Volume to the desired volume.

I am using this in my GameController script on the triggering of the SceneManager.SceneLoaded as below

        private void Start()
        {
            sceneChanged = true;
            player = Player.PlayerInstance;
            gameOver = Resources.FindObjectsOfTypeAll<GameObject>().FirstOrDefault(g => g.name == "GameOverUI");
            pauseUI = Resources.FindObjectsOfTypeAll<GameObject>().FirstOrDefault(g => g.name == "PauseUI");
        }

        private void Update()
        {
            SceneManager.sceneLoaded += startScene;
            if (sceneChanged)
            {
                AudioManager.FadeIn(SceneManager.GetActiveScene().name, 0.35f, 2f);
                sceneChanged = false;
            }
        }

        public void startScene(Scene scene, LoadSceneMode mode)
        {
            sceneChanged = true;
            gameOver.SetActive(false);
            PlayerReset();
        }

The issue is that the music does start and fade but it starts at a volume higher than 0 and then almosts jumps up to the desire volume.

Is this because I am calling a standard function from the update? Does it need to be an IEnumerator?

If anyone can help as I have been trying to fix it to no avail :frowning:

Thanks

James

You’re sure there isn’t any other code affecting the volume of the audio source? Maybe the Fade Out from the previous scene is still going?

So, a couple of things. Calling your parameter “duration” isn’t really accurate. It’s more of a speed multiplier. The way you’ve written the code, there’s no guarantee that it will take ‘duration’ seconds to reach the target volume. Just think about it like this: What if you called this against target volume .35 and target volume .7? It would take twice as long to reach .7, since you’re adding the same small amount of volume each frame. So, although it’s just a naming thing, I’d avoid thinking of that value as being the duration of time it will take for the volume change to complete.

And then why are you using “yield return new WaitForSeconds(_duration);” after you’ve adjusted the volume? That doesn’t seem to do anything other than wait for that many seconds, doing nothing, before claiming to be fully faded in?

Another thing to watch out for is that just using += and -= like this on the volume can result in it going too high or too low. Maybe not by much, but you can image if it reached volume 0.3499998 one one frame, it hasn’t quite gotten to 0.35 yet. So the next frame might get to 0.359, or something higher than the actual target. You might want to do something like this:

m.source.volume = Mathf.Min(_targetVolume, m.source.volume + Time.deltaTime / _duration);

That would keep it from exceeding max.

Anyway, if none of that helps, I’d recommend just putting some Debug.Log statements in your while loop, and just print the current volume. That might help point out when the volume doesn’t have the value you’d expect.

Ooops the yield return new WaitForSeconds(_duration) isn’t meant to be there missed that :frowning: That would explain why at some points it was thinking multiple fades were running.

It’s odd as I am setting the m.source.volume = 0 but when the clip starts to play its already higher than 0. Then it suddenly jumps to the target volume.

The volume on the music source is defaulted at 0 so should therefore be silent.

I’ll put a few Debug.Log entries in the while loop and see what the actual volume is doing.

Thanks for the advice on the duration as you’re right it’s not really a duration at all.

Hopefully I’ll get to the bottom of it!

Thanks