how to play a random sound after the previous one stop?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By lucas2606

hi. this is my first day with the engine and my coding skills are very poor. i’m trying to play a random sound when the previous one stops, but i can’t make it. i got a “control” node and 4 audiostreamplayer nodes as childs, “s1”, “s2”, “s3” and “s4”. my control node code is this:

extends Control

var a = RandomNumberGenerator.new()
var sound = 0

func _ready():
a.randomize()
var sound = a.randi_range(1,4)
get_node("s"+str(sound)).play()
pass

func _process(delta):
if get_node("s"+str(sound)).is_active == false:
get_node("s"+str(sound)).play()
pass

the first part of the code works… it randomly plays one of the 4 sounds at the beginning of the scene. i don’t now if this is the best way to do it, but it’s the way that i found :stuck_out_tongue:
the problem is that i can’t make that when that first sound stop, another one start. the conditional “if get_node(“s”+str(sound)).is_active == false:” give me the error “invalid get index ‘is_active’ (on base: null instance)”
probably is a very noob mistake…

:bust_in_silhouette: Reply From: estebanmolca

I leave you another alternative way: Use a single AudioStreamPlayer and preload the audio files with preload and put them in an array. Then use the Stream property of AudioStreamPlayer to assign each sound to it. AudioStreamPlayer has a signal that runs every time the playback ends. The problem may be, if you have many files, you have to preload each sound (although there are ways to obtain all the files in a folder: https://forum.godotengine.org/5175/how-to-get-all-the-files-inside-a-folder but I see it half complex and unnecessary for this case.).

extends Node2D
var sounds=[]

func _ready():
	randomize()
	sounds.append(preload("res://sounds/music.wav"))
	sounds.append(preload("res://sounds/music2.wav"))
	sounds.append(preload("res://sounds/music3.wav"))
	$AudioStreamPlayer.stream=sounds.front()
	$AudioStreamPlayer.play()

func sounds_random(s:Array) -> void:
	s.shuffle()
	$AudioStreamPlayer.stream=sounds.front()
	$AudioStreamPlayer.play()

func _on_AudioStreamPlayer_finished():
	sounds_random(sounds)

Oh, if you are new, you may not know the godot signals, in that case, to connect the finished AudioStreamPlayer signal, select it and go to the Node tab in the properties panel, right next to the Inspector panel and you will see the signals below. Select the signal on_AudioStreamPlayer_finished () and press connect below, in the panel that appears select the node where you have the script. The _on_AudioStreamPlayer_finished () function is automatically created in your script.

estebanmolca | 2020-01-25 13:53

thanks! after a while trying to make it work I discovered the signals watching a sample project
your code works, but I used the yield option because I got a lot of audiostreams (I begun with 4 just for testing, but the idea is to have a lot more) each one with internal variables that I need to call

lucas2606 | 2020-01-26 06:02

Yes, it’s very good. What Yield does is pause the function until a condition is met, in this case it uses the same signal to resume. And you can do more things such as a fade in / out or use some random silence between sounds.

estebanmolca | 2020-01-26 10:26

Thnx, this helped me to bring in some variation into my background sounds. Together with a randomized timer, with a few sounds I get a lot of variation and randomness in my scene.

Cheers

eyeEmotion | 2020-04-24 19:00

:bust_in_silhouette: Reply From: jgodfrey

Another way to play a random set of sounds continually, one after another is via yield. You just need to pick a sound, play it, wait for it to finish (via yield) and then do it again. So, using bits of your above code, something like this:

var a = RandomNumberGenerator.new()

func _ready():
     a.randomize()
     playSound()

func playSound():
	var val = a.randi_range(1, 4)       # pick a valid random number
	var snd = get_node("s"+str(sound))  # select a sound
	snd.play()                          # play the sound
	yield(snd, "finished")              # wait for the finished signal
	playSound()                         # do it again

thanks for your answer! it works perfect

lucas2606 | 2020-01-26 06:04