+2 votes

I have set a stage music but I have also set a audio stream in the character scene to play when the character dies. But whenever I try running both the sounds merge and sound awful. Is there any way to stop an audio stream of other scene when another stream is being played?

asked Jun 23, 2019 in Engine by Nanogines (28 points)

1 Answer

+1 vote

What I usually do is differentiate every type of audio. BGMs from SFX, etc... and I have a Singleton that I call passing two arguments, "path" that holds a string for the audio path and "type", a string specifying the type of audio that is going to be played. The singleton instances an AudioStream scene with a Timer node, the path is add and play() is on ready(). The AudioStream, then adds itself to the group(type). Here is where you can make the previous sound stop. On _ready() you could check for every node in the group(type) and queuefree, stop(), or pause, every one of them.

The Timer.waittime() is set as the audio length time. When the timer ends, queuefree().

answered Jun 23, 2019 by Somar (19 points)

I am quiet new so can you explain it a bit more easily
In my case my background music is in my stage scene and my death sound is in my player scene. My Background is set to autoplay and my death sound is set to play in my player's code when the player dies in the func _dead(). Now both the sounds are colliding with each other. This is the problem.

Sure can. We are going to create an automatic audio player. That not only erases itself after the audio has finished, but also stores the current playing audios in a group so that you can free then when necessary.

For this you will be using "groups", and "singletons".
SceneTree - group methods
Singletons[AutoLoad]

You can make a scene that consists of only an AudioStreamPlayer and name the node Audio. Attach a script to it and only put in this:

func _on_Audio_finished(): #by the way this is a signal connection

queue_free()

The next step is creating an autoload script, that can be called from anywhere just by using it's prefix. In this autoload script you are going to preload the previously created scene using:

var Audio = preload("res://Audio.tscn") 

Keep in mind that the path to the file may be different for your project, so just copy the path from your editor at the FileSystem's dock.

Next create a function "_play(filepath, type)" these are going to receive the arguments filepath, and type. And then:

var audio = Audio.instance()
get_node("/root/,,,").add_child(audio)
audio.add_to_group(type) 
var file = load(filepath) 
audio.set_stream(file)
audio.play()

Line by line:

  1. instances the Audio scene we created first
  2. adds the instance to the tree. (the path and the parent is your option)
  3. this adds the instance to a group using the passed argument "type", it is important that "type" hold a String type value, e.g: "BGM" or "SFX"
  4. this loads the file using the passed argument "filepath" into the file variable. It is also important that "filepath" hold a String type value, e.g: "res://Audio/sword-attack.wav"
  5. We then set the just created variable file as current audiot to be played by the AudioStreamPlayer.
  6. And finally we play it using play()

Now, remember that the Audio has a script of it own that will queue_free() itself as soon as the audio comes to an end. But if you want to end it before, you can just use:

var currentPlayingAudio = get_tree().get_nodes_in_group("mygroupname") 

You wll use any group name you assigned before in the autoload script.
Then you can iterate through currentPlayingAudio and queuefree() all of then, or just select one or other to queuefree().

Well, that is it. Sorry if it is a little complicated. That was just the way I figured out how to do it.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.