0 votes

I have several songs running concurrently. When the player presses one button, one song will mute and another will start playing. Right now, this happens immediately when the button is pressed, regardless of whether this is in the middle of a note or not.

Let's assume that the song is 90 BPM, or 1.5 beats a second, or 2/3 seconds per beat.
How would I go about this so that every mute or unmute happens at an interval of 2/3 seconds rather than at the user input?

My first thought is to have the user input set a flag that gets checked every 2/3 seconds, but I'm not certain how to set that up in Godot yet.

in Engine by (17 points)

2 Answers

+1 vote

Something like this should work:

func _on_Button_pressed() -> void:
    var playback_pos = $AudioStreamPlayer.get_playback_position()
    var wait_time = 2.0/3.0 - fmod(playback_pos, 2.0/3.0)
    yield(get_tree().create_timer(wait_time), "timeout")
    $AudioStreamPlayer.stop()

However, audio output is usually buffered and prone to several types of delays (e.g. depending on your hardware) - so I wouldn't bet on this stopping perfectly in-sync with the beat. I'd recommend you slowly fade out the music volume instead.

by (10,221 points)

Given what you said about audio output being buffered, does that mean that if I start 4 songs at the same time, depending on the hardware, they might not all stay in sync with each other unless I do something specific in the code to guarantee they do?

I'm far from being an audio-expert, but I'd argue even if they don't stay perfectly in sync, the deviation will be so minor that's unlikely anyone will notice. However, if you are trying to precisely hit a certain beat, things might look different. I recommend you read through this part of the documentation, if you haven't already.

+1 vote

It'll be better using _physics_process as it's a fixed framerate (I've used it to record and play replays with accuracy). You could use a bool to check if the input has been pressed and use a timer node with one_shot false and TimerProcessMode on 0 for physics framerate then use the timeout signal to change the music (hopefully in time).

by (3,223 points)
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.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.