Hi! In my game I play different songs depending on what biome you are in (snow, forest, desert etc.) Currently, if the player walks into a different biome it will automatically transition into that biome’s music. However I would like to transition into the new biome’s music once the current song is finished, so it doesn’t switch songs so much.
This is what my music event looks like. The biome is a parameter and each one usually has a multi-instrument that shuffles through the songs.
I tried setting a callback on the music event but it just crashes the game and there’s seemingly no documentation on how these are supposed to work.
Unfortunately, using a parameter sheet to handle this probably isn’t the best way to go about it, because events can’t directly detect when an instrument has finished playing - therefore, there’s no direct way to wait for an instrument to finish before transitioning biomes.
There’s a number of ways to handle this problem, but a simple solution can be achieved without handling it programmatically. If the length of all songs for a given biome are the same, then you can set up a “logic point”:
Set up your instruments on a timeline with regions corresponding to each biome (leave a small gap between each region).
Set up destination markers for each biome at the start of their corresponding region of the timeline.
Set up a transition marker to your “logic point” at the end of each biome.
Set up a your “logic point” - a single point on the timeline with one destination marker, and a one transition marker for each biome. Have each of those transition markers check the value of
Biome, and transition to destination markers on corresponding areas of the timeline.
All set up, it might look something like this:
This way, whenever you change the value of
Biome, the instrument currently playing will finish and transition to the logic point, which will check against the value of
Biome and transition to the corresponding region.
If songs in a single biome have different lengths and you’re using a Multi Instrument, then this “logic point” method won’t work, as there will be a gap between when the shorter song ends and when the event hits the next transition marker. To work around this, for a given biome you can split songs of different lengths into seperate events, and handle picking which one to play in Unity.
All the songs are different lengths but I am fine to handle it programmatically in Unity. If I have a different event for each biome (or different event for each song?)
How can I detect when a song is finished to then potentially switch the song to a different biome’s song OR if the biome is the same shuffle to another song for that biome.
To be able to detect when each song has finished playing you would want to have each song in a separate event, to avoid the issue I mentioned in my previous response where one song is longer than another in a Multi Instrument. You can then check when an event has stopped with
Studio::EventInstance::getPlaybackState, and use the result of that to switch events.
Shuffling and picking a random song for a single biome is a little more complex - while you can basically mimic the “logic point” idea using C# to handle transitioning between events, you’ll have to handle sorting, shuffling, and picking from the events yourself. There are a couple of ways of doing this, but a good starting point would be to get an array containing all event descriptions in a bank with
Studio::Bank::getEventList so that you can sort/manipulate the list in whatever way you need. Event GUIDs and paths are what will be easiest to compare against, and you can grab those with
For example, after my
BGM bank has been loaded,
Start() I might sort the events by path into a 2D List, with the first dimension representing the biome, and the second representing each event in the biome. From there, when transitioning to a new biome, playing a new song would look something like this:
currentEventInstance.getPlaybackState(out FMOD.Studio.PLAYBACK_STATE playbackState);
if (playbackState == FMOD.Studio.PLAYBACK_STATE.STOPPED)
int randomSong = UnityEngine.Random.Range(0, eventList2D[biomeID].Count);
currentEventInstance = eventList2D[biomeID][randomSong];