ADXTutorialsUnreal Engine

Smooth musical transitions between levels [Part 2]

This is the last part of our tutorial in which we see how to play an intermediary music when switching between 2 main songs. In the previous post, we prepared an ADX Cue Sheet containing our main songs and transition Cues. We added markers to BeatSync tracks to enable smooth jumping between all these Cues. This time, we will import the data authored in AtomCraft into Unreal Engine and implement it in the game with Blueprints.

Importing the Atom Craft data into UE5

Let’s first import the binary Cue Sheet we built into our UE5 project.

In the dialogs that appear when importing the acf file, choose Yes both times.
This will automatically set the acf file for your project.

You can then open the acb file (i.e., your Cue Sheet) to check that the Cues play correctly.

Playing BGM from the Level Blueprint

For the moment, we will simply create two rooms and make the background music switch when moving between them.

Let’s open the Level Blueprint.

We will use a Spawn Sound 2D node when the BeginPlay event is triggered to play the BGM.
(The Set View Target with Blend node shown in the screenshot is only here for the camera.)

Right-click the input pin of the Spawn Sound 2D node and select Promote to Variable to create a variable.

Name it “BGM.”

Compile the graph, then set the default Cue for the variable in the Details panel.

Expand the Spawn Sound 2D node.

Uncheck Auto Destroy. Normally, an Atom component spawned by Spawn Sound 2D will automatically be destroyed once the playback ends. However, in this case, we want to reuse it later to play a different Cue, so we disable its automatic destruction.

We can now run the game to confirm that the BGM plays.

Monitoring Tempo and Triggering Events

Let’s add a new variable to store which room the player is currently. We will use an Int named CurrentRoom.

We then add two Box Trigger volumes to the level. Resize them, so that each covers one the rooms.

With one of the volumes selected, return to the Level Blueprint and add an On Actor Begin Overlap event.

Use a Branch node to check if the overlapping actor is the Player Character.
This will allow us to detect when the player moves between rooms. Repeat this setup for the second volume.

Every time the player moves to another room, we will update the CurrentRoom variable.

Return to the processing of the BeginPlay event.
Right-click the blue output pin of the Spawn Sound 2D node and select Promote to Variable.

Name this variable Atom BGM. From its output pin, drag out a line and choose Assign On Atom Sound Cue Beat Sync.

This will place both a Bind Event to On Atom Sound Cue Beat Sync node and an event node (named OnBeat).
This event will be triggered in sync with the BGM’s beat.

In order to test it, you can connect a Print String node to the OnBeat event to display a text for each beat.

When you play the game, you will see the beat count progress within each measure displayed in the top-left corner.

Playing a Transition Phrase and Switching the BGM

Let’s add another Int variable named CurrentBGM to store the index of the BGM that is currently playing.

We want the transition phrase to start at a good time musically (i.e., the beginning of a measure) so we monitor the Beat Count, and when it is back to 0, we check whether we need to switch the BGM.
A Branch node is used to check whether the current BGM matches the player’s current room.

We create a new variable to store all BGM Cues together.
We set the type to Atom Sound Cue, then click the icon next to Variable Type to make it an array. Call it BGMList.

Compile the Blueprint, then add the Cues to the array in the Default Value section.

If the current BGM and room do not match, we need to switch to a different BGM Cue. In that case, we specify a transition phrase (either ADX_BGM_AT or ADX_BGM_BT). We use a Select node to specify the index in the BGMList based on the value of CurrentBGM.(Even if the node’s logic looks a bit confusing at first, try replicating it as shown here.
You will get a clearer idea once you see it in action!)

After that, we assign the CurrentRoom value to CurrentBGM to make them match.

Since we want to start the next room’s BGM only after the transition phrase has stopped, let’s place a Bind Event to On Atom Sound Play State Changed node to get notified when the playback state changes.

The event triggered by Bind Event to On Atom Sound Play State Changed provides the current playback state.
We can add logic based on the playback state by connecting the event output pin to a Switch node.

Here, we want to continue the process only when the state is Stopped (i.e., when the playback ends).

Because this event is triggered every time the playback state changes, make sure to temporarily disable it after the process completes.

That’s it: now, when the player moves between rooms, a transition phrase will play before switching to the new room’s BGM. When the next BGM can be reasonably predicted, you can also consider using features such as Block Playback or REACT. We will talk about this in future tutorials!