Change music on specific scene

I have an Music Manager on my mainMenu that is a singleton. The reason for the singleton is that I wan’t to play some songs through different scenes. So far so good…

But from the Music Manager I would also like to load different songs on specific scenes. So if a specific scene gets loaded the song should change.

How would I do this from within the Music Manager which is a singleton?

I tried it with checking which scene is loaded at that present moment but I can’t seem to figure out how to properly do this. Any suggestions are welcome.

Maybe you could define a public music update method in your Music Manager. Any other object that loads a scene should also ask the Music Manager to change tracks based on the scene being loaded.

Using the Music Manager to check the current scene is a good idea too, can you show us what you have so far? Maybe we can help you get that working. I think using the SceneManager events is probably a good method for this.

1 Like

This is how my simple Music Manager looks like as a singleton:

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;

public class MusicManager : MonoBehaviour {


    public static MusicManager instance;

    private AudioSource audioSource;


    private bool SongLoaded;




    void Awake () {
   
        MakeSingleton ();
        audioSource = GetComponent<AudioSource> ();
    }

    void Start () {

        if(!PlayerPrefs.HasKey ("Game Initialized")) {
            MusicState.SetMusicState (1);
       
            PlayerPrefs.SetInt(" Game Initialized", 123);
        }
           
    }




    void MakeSingleton () {
   
        if (instance != null) {
            Destroy (gameObject);
        } else {
            instance = this;
            DontDestroyOnLoad (gameObject);
        }
    }


    public void PlayMusic (bool play) {

   
        if (play) {
            if (!audioSource.isPlaying) {
                audioSource.Play();
            }
        } else {
            if (audioSource.isPlaying) {
            }
            audioSource.Stop ();
        }


    }
}

And this is part of the Main Menu Controller that also handles the music On/Off button:

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
using UnityEngine.UI;


public class MainMenuController : MonoBehaviour {


    [SerializeField]
    private Button musicButton;

    [SerializeField]
    private Sprite[] musicIcons;


    private Text highScoreMainText;



    void Awake ()
    {


        highScoreMainText = GameObject.Find("HighScoreTextAmountMain").GetComponent<Text> ();

        SetHighMain ();

    }

    void Start () {

        CheckToPlayTheMusic ();

    }



    public void PlayGame ()
    {
       
        SceneManager.LoadScene ("GameStartInfo");

    }


    public void SetHighMain ()
    {
        int score = PlayerPrefs.GetInt("HighScore");
        highScoreMainText.text = "" + score;
    }



    void CheckToPlayTheMusic () {
        if (MusicState.GetMusicState () == 1) {
            MusicManager.instance.PlayMusic (true);
            musicButton.image.sprite = musicIcons [0];
        } else {
            MusicManager.instance.PlayMusic (false);
            musicButton.image.sprite = musicIcons [1];
            }
        }

    public void MusicButton () {
        if (MusicState.GetMusicState () == 0) {
            MusicState.SetMusicState (1);
            MusicManager.instance.PlayMusic (true);
            musicButton.image.sprite = musicIcons [0];
        } else if (MusicState.GetMusicState () == 1) {
            MusicState.SetMusicState (0);
            MusicManager.instance.PlayMusic (false);
            musicButton.image.sprite = musicIcons [1];
        }
    }

    }

What is MusicState? It looks important.

Try making a SetMusic method in your MusicManager that will change the clip of the BGM AudioSource to the required song. Whenever you load a scene, you can also call MusicManager.SetMusic() to set the correct music clip.

You could make an array of all the songs in your MusicManager, and address them by index. This way, you could just pass an integer with SetMusic to define the song to play, like

MusicManager.SetMusic(5)

To play the song at index 5 in the list. If you do this, I recommend using Streaming for your BGM clips to reduce the memory overhead of the clips, otherwise every song will always be loaded, reducing available memory. Otherwise, you could instead define a list of asset locations and tell your MusicManager to load/unload them as needed.

I’m still new to programming and Unity so I don’t fully understand what you mean. I tried to switch songs by checking if the scene has changed. I tried to do this from within the Update function from within the Music Manager which is a singleton. Not sure how to correctly check if the scene has changed from the Music Manager (because of the singleton). Could you be a little more specific on how to do this from within a singleton script?

MusicState is for checking if the Music is playing or not, so I can switch it on and off with a menu button.

Two ways:
Nothing fancy: You’d store the name of the scene every frame, and if the name change, do something

//in your music manager

private string lastScene;
void Awake() {
    lastScene = SceneManager.GetActiveScene().name;
}

void Update() {
    var currentScene = SceneManager.GetActiveScene().name;
    if(currentScene != lastScene) {
        lastScene = currentScene;
        HandleSceneChangedTo(currentScene);
    }
}

Easier, more advanced concepts: Listen to the SceneChanged event:

//still in your music manager:

void Awake() {
    SceneManager.sceneLoaded += HandleSceneLoaded;
}

void HandleSceneLoaded(Scene scene, SceneLoadMode loadMode) {

}

A different alternative entirely is to have a script you can put in a scene that finds the scene manager on Awake and tells it to change music.

I tried the following in my singleton script. But it doesn’t seem to do anything. It only plays the title music.

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;

public class MusicManager : MonoBehaviour {


    public static MusicManager instance;

    // Vars for audio
    private AudioSource audioSource;
    public AudioClip MainMenuSongAU;
    public AudioClip GreenHillsSongAU;
    public AudioClip CaveSongAU;

    private bool SongLoaded;

    // Vars for checking which scene has been loaded at present moment
    private string lastScene;
    private string currentScene;



    void Awake () {
   
        MakeSingleton ();

        audioSource = GetComponent<AudioSource> ();

        //Getting the scenename
        lastScene = SceneManager.GetActiveScene().name;

   

        // Setting the music state standard to 1 so music starts playing on game load
        if(!PlayerPrefs.HasKey ("Game Initialized")) {
            MusicState.SetMusicState (1);

            PlayerPrefs.SetInt(" Game Initialized", 123);
        }
   
   
    }


    void Update() {

        // Checking which scene is loaded (for handling music)

        currentScene = SceneManager.GetActiveScene().name;

            if(currentScene != lastScene) {
            lastScene = currentScene;
            ChangeSong();
        }

    }

    // Changing the song when loading a specific level
    void ChangeSong() {


        if (lastScene == "GameStartInfo") {
            audioSource.PlayOneShot(GreenHillsSongAU, 0.4f);
        }
    }






    void MakeSingleton () {
   
        if (instance != null) {
            Destroy (gameObject);
        } else {
            instance = this;
            DontDestroyOnLoad (gameObject);
        }
    }


    public void PlayMusic (bool play) {

   
        if (play) {
            if (!audioSource.isPlaying) {
                //audioSource.Play();
                audioSource.PlayOneShot(MainMenuSongAU, 0.4f);
            }
        } else {
            if (audioSource.isPlaying) {
            }
            audioSource.Stop ();
        }


    }
}

Got it working. For anyone in the future that runs onto the same problem, this is part of my code:

// Changing the song when loading a specific level
    void ChangeSong() {

        if (MusicState.GetMusicState () == 1) {
            if (lastScene == "MainMenu") {
                audioSource.PlayOneShot (MainMenuSongAU, 0.4f);

                Debug.Log ("Var lastScene is now: " + lastScene);

            } else if (lastScene == "GameStartInfo") {
                audioSource.Stop ();
                audioSource.PlayOneShot (GreenHillsSongAU, 0.7f);

                Debug.Log ("Var lastScene is now: " + lastScene);
     
            } else if (lastScene == "GamePlay1") {
                audioSource.Stop ();
                audioSource.PlayOneShot (GreenHillsSongAU, 0.7f);

                Debug.Log ("Var lastScene is now: " + lastScene);
     
            } else if (lastScene == "GamePlay2") {
                audioSource.Stop ();
                audioSource.PlayOneShot (CaveSongAU, 0.7f);

                Debug.Log ("Var lastScene is now: " + lastScene);
     
            } else if (lastScene == "MainMenuLava") {
                audioSource.Stop ();
                audioSource.PlayOneShot (MainMenuSongAU, 0.4f);

                Debug.Log ("Var lastScene is now: " + lastScene);
            }
        } else {

            audioSource.Stop ();
        }

    }

    public void PlayMusic (bool play) {

 
        if (play) {
            if (!audioSource.isPlaying) {

                    ChangeSong();
         
 
            }
     
        } else {
            if (audioSource.isPlaying) {
            }
            audioSource.Stop ();
1 Like

hey, what does the meaning of MusicState in the line 37? can u post your whole script? would love if u post the whole script