Handling many songs in a level

Hi there.

When the character reaches a new area, a new song starts playing. The issue is that when the new song starts, the old one doesn’t stop.

I have tried using boolean variables to turn songs on, and to avoid them repeating if triggered more than once but this got very complex very quickly and didn’t really solve the issue.

In a new approach, I’m now using one variable of String type, along with a “Switch on String” component to then play a particular song based on the value of the variable. On a trigger blueprint responsible for a song, I then set this String variable for that song.

This seems to work half way, in that the variable successfully updates/changes, but the new song doesn’t play. I have verified that the variable successfully updates every time the character steps on the trigger, but the song does not change.

I currently have this code on Event BeginPlay, and I suspect it needs to live elsewhere. I tried to stick it under Event Tick which does work, but the audio is very whacked out and replicates itself every second.


2022-06-27_21-45-39

Any help appreciated.

I’m not sure what you are doing exactly, but if you want the song to stop, you could save a reference to it from the Spawn Sound 2D and when starting the next song, feed that reference into Fade or Stop. A reference reachable from other actors could be placed as a publicly accessible variable in GameInstance, GameMode, or LevelScript. The GameInstance would be best if it is to carry over between levels. Be sure the AutoDestroy boolean it ticked so the Audio Component self destructs after it stops/fades (though when its reference is gone, I think it will be anyway).

As far as your BeginPlay, what actor is the BeginPlay in? If it is in an actor started when entering the trigger block, that might make sense, but otherwise, starting the new song (and stopping the old) on Overlap might make more sense. This also might be the place to check if your reference is valid and Stop/Fade it prior to Spawning the new song. The pseudo code would be:

OnOverlap of Box
if AudioComponentReference IsValid, Fade/Stop
Spawn Sound 2d for specific song replacing AudioComponentReference with new one

Each Box Actor will have a different song wave set in its Spawn Sound 2D, then you shouldn’t need the string variable.

The first song would be loaded at level/game start.

I think something like that would work if I understand the application. Beware hitting multiple occurrences of the same overlap or actor popping in and out.

Tick would probably not be useful in this application.

1 Like

Hey eagletree thanks for the response. I am not too sure what you mean with making a reference. Is that turning the sound node of the Spawn Sound 2D component into a variable? I have tried this (turns into a Sound Base variable type) and ticked Instance Editable but I cannot see this variable from the other trigger or my character.

The actor in BeginPlay is the main character called TestCharacter. What I want to achieve is simple. When this character moves to location A, song_1 should play. When this character moves to location B, song_2 should play. Location C = song_3, location D = song 4 etc. There are dozens of songs and areas.

If I have it set up like this on the box trigger, it works apart from the songs overlapping and playing simultaneously.

So in an attempt to avoid the songs playing simultaneously, I tired using one Sting variable like in my original post. This again works in that the variable changes, but the corresponding song does not change as well. I added a “Print to string” under event tick to display when the variable changes and it works, but the song doesn’t change.

When the character moves to location A, song_1 starts playing, and I can see the variable changes. When the character moves to location B, song_2 DOES NOT start playing, but I can indeed see that the variable changed.

This makes me think that even though the variable changes, it’s not being triggered in the game in real time, that’s why I though it should be elsewhere, like in EventTick, as this fires all the time while the game is running.

If you could please let me know how to create this reference, I’ll give it a go.

I created and tested an example of what I mean.

  1. open content drawer and select to Add Blueprint. Select it to be of type GameMode
  2. open New GameMode Blueprint and click Event Graph and press + to Add Variable. Select the type of Variable to be Audio Component → Reference
  3. pull off BeginPlay and create SpawnSound 2D, set song wave file
  4. Pull off Spawn Sound 2D Return Value and Set the variable name Created
  5. Compile and Save

Click on Level, pull down Settings and select Project Settings. In Maps and Modes, set Game mode base to be the new Game Mode class just selected. Close settings.

  1. Create box collider and in Event stack select OnComponentBeginOverlap
  2. Below this, create Get Game Mode, pull off that and cast to your new Game Mode
  3. Pull off cast return value and select your new AudioComponentRef Variable.
  4. Pull off that variable and create IsValid (the one with the ?)
  5. If Is Valid, pull off the AudioComponentRef Variable and find Fade or Stop
  6. if Isn’t Valid, create Spawn Sound 2D
  7. pull off the Cast Output and select Set making sure the Target is what it connects to
  8. Pull off Spawn Sound 2D Return Value to the other pin of Set, then make sure the control path arrows are all connected.

Examples:

Game Mode

Box Collider blueprint

Details:

What is happening here is we’ve created a game mode variable and initial Spawn Sound 2D in our own custom game mode. We’ve made our custom game mode the one that will be used when you hit play. We then created a BP with a box trigger and on collision, have checked to see if a sound is playing, and if so, fade it out. In any case then, we start a new sound.

If you want no sound playing to start with, then delete the Spawn Sound 2D in Game Mode. That’s only there to start a default sound before they hit any colliders.

Improvement:

Our Box Blueprint should have the song to be played specified as a variable rather than put right into the Spawn Sound 2D. This would then let us drop generic copies of the Box Blueprint in the level, and set the specific song wave on each one.

Wow thank you so much for going through all that trouble detailing it out. I will see where this takes me and report back, appreciated!

You’re welcome. A more comprehensive solution would end the song at an even measure as it starts the next. I have something like this in Metasounds but it’s far more difficult to implement. Since you have more control in Metasounds (or Quartz), you can do things like that and you don’t terminate (Fade/Stop) the Audio Component, but send it a message to close the close the song in a musically orderly fashion, then start the next within the same Audio Component.

Another improvement to this basic solution is to create a boolean to Ignore overlaps after the initial is received, then check that before responding to the OnOverlap so that any jitter (manually caused by player moving in and out momentarily, or glitchiness of the collider) will not cause the song to stop and start over and over. That would be something like this:

You also would need to be cautious about having the colliders overlap. That could create some issues.

Another effect to ponder would be sensing the exit of the collider and fading and clearing the reference at that point. This would be useful if you would like to have silence between songs or even better, have an overall song that starts at level start, then plays anywhere in the level that you aren’t in the collider triggered spaces. Such an effect would let you have an overall level theme, but then special themes for specific areas.

Just reporting back, your initial solution works for me so thank you very much! I don’t think I’ll have any need for your second solution but is valuable for some other community members. You raise very good points to ponder.

I planned to have around 200 different songs but after adding around a dozen or so, I discovered the project was growing in disk space quite drastically. Unreal blows up 1MB .ogg files into 20MB monsters for some reason so a limitation there. Your solution is just wat I wanted thanks again!

Don’t quote me (I’ve not messed with ogg), but I thought UE has to convert to wav from ogg to use them and that would explain why they get so large (going through a decompression). You might experiment with directly generating wav files from your DAW with a lower bit rate and see if they end up smaller than what the conversion produces. Probably not by much, but it’s worth a try.