Recursion on music looping

Godot Version

4.7 Stable

Question

Hello! I was just upgrading to Godot 4.7 when I came across the error of a music function: (this is the old version)

func _ready():
	play_music()


func play_music():
	if Global.TimeofDay == "Morning" or Global.TimeofDay == "Dawn":
		music.stream = morning_songs.get(Global.REGION).pick_random()
	if Global.TimeofDay == "dusk" or Global.TimeofDay == "Night":
		music.stream = night_songs["central"].pick_random()
		
		
		
	await get_tree().create_timer(randi_range(2,50)).timeout
	music.play()
	
	await music.finished
	await get_tree().create_timer(randi_range(1,20)).timeout
	return _ready()

At the bottom returning ready() having a problem with void return values. So I switched it to play_music() but I am concerned about recursion having an effect on memory or something.

Don’t use infinite recursion. You can make much better use of signals.

func _ready() -> void:
 	play_next()
	music.finished.connect(play_next)

func play_next() -> void:
	if Global.TimeofDay == "Morning" or Global.TimeofDay == "Dawn":
		music.stream = morning_songs.get(Global.REGION).pick_random()
	if Global.TimeofDay == "dusk" or Global.TimeofDay == "Night":
		music.stream = night_songs["central"].pick_random()

	await get_tree().create_timer(randi_range(2,50)).timeout
	music.play()

I agree with @gertkeno, but I’d take it a step further and get rid of that await altogether by adding a Timer. FYI, returning the _ready() function as a callable is going to have unintended consequences. Not sure where you got that idea, but it’s not a practice I would recommend.

extends Node

const MIN_SILENCE_TIME: float = 2.0
const MAX_SILENCE_TIME: float = 50.0

var timer: Timer

@onready var music: AudioStreamPlayer = $Music


func _ready() -> void:
	timer = Timer.new()
	add_child(timer)
	timer.one_shot = true
	timer.timeout.connect(_on_timer_timeout)
	music.finished.connect(_on_music_finished)
	_on_music_finished()


func _on_timer_timeout() -> void:
	if Global.TimeofDay == "Morning" or Global.TimeofDay == "Dawn":
		music.stream = morning_songs.get(Global.REGION).pick_random()
	if Global.TimeofDay == "dusk" or Global.TimeofDay == "Night":
		music.stream = night_songs["central"].pick_random()

	music.play()


func _on_music_finished() -> void:
	timer.start(randf_range(MIN_SILENCE_TIME, MAX_SILENCE_TIME))

I got rid of you Magic Numbers, and also used a single Timer node so that you’re not constantly instantiating one over and over. This also makes your flow clearer.

Thank you both!