Delay in sound effects from SamplePlayer2D

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Howl
:warning: Old Version Published before Godot 3 was released.

Hi, I am making a rhythm game (or at least trying to). I have some sound effects that must play in the very precise moment a “circle” on the screen is hit. The main problem is that the sound effect is a few milliseconds late - which are crucial for the game experience. Here is a footage in which you can see that it is indeed noticeable. This is the sound effect.

func _ready():
	# circle preparation would be here
	set_fixed_process(true)
	set_process_input(true)

func _input(event):
    # object_click = keyboard x, keyboard z, mouse left, mouse right
	if event.is_action_pressed("object_click"):
		_object_click()

func _object_click():
	var mousepos = get_global_mouse_pos()
	var bestel = null
    # found what element the mouse is hovering, and if there are multiple elements being overed find the "oldest created" one
	for i in get_tree().get_nodes_in_group("circles"):
		if i.is_part_of(mousepos):
			if bestel == null or bestel.id > i.id:
				bestel = i
	if bestel == null: return
    ## SOUND EFFECT
	get_node("sound_effects").play("normal-hitnormal")
	print("clicked ", bestel.id)
	bestel.fade()
	bestel.remove_from_group("circles")

EDIT: This is the sound effect in audacity. You can see that it starts at the very beginning of the file, without any offset. This is the full waveform

I have been working on build rhythm game based on bms format.
in my case, Linkpy’s solution reduced latency alot.
btw, if you are still working on this project, I just want to keep in touch with you

eaglecat | 2016-05-09 04:31

@eaglecat I’m not currently working on it. You probably have guessed that it’s a sort of osu! clone prototype. I stopped working of it because the workload of other personal projects is quite high :stuck_out_tongue:

Howl | 2016-05-12 10:02

:bust_in_silhouette: Reply From: Freeman

From my own experience (sound and music related applications mainly) Godot is not ready yet for intensive audio works especially if you expect precise syncing and not much latency. Your best bet will be to use rather short samples with SamplePlayer that in my tests was giving best results.
SamplePlayer2D is for other tasks, when you need your sound to be located in the space, so unless it’s what your need try to use SamplePlayer.

The audio part of the engine is going to be rewritten in the near future and hopefully it will work much better.

But I also have some thought about what I see on your screen when you play.
I see that you run the scene from Godot and I have an experience thatit can delay some things and run slower than normally it would run from binary file. Have you try to export the release version of the scene and check the delay than? It should make it work slightly better.

Also, I see set_fixed_process(true) in the fragment of your code. Do you use the physics in your game and things that would need to count the precise physics every frame in your game? I ask because counting precise physics might slow things down if not used right.

Changing to a simple SamplePlayer noticeably reduced latency - perhaps running it in an executable did, too. But still - the delay is quite long and annoying.
The sample used to test is very small (106ms - 25kb), so I don’t think that can be easily solved :confused:
fixed process isn’t actually doing anything at the moment. Removing set_fixed_process didn’t show any particular improvements.

Howl | 2016-03-30 14:12

:bust_in_silhouette: Reply From: Howl

After analysing the C++ code of a SamplePlayer and trimming all the fat from the code, I got down to the following function:

func play_sound(sample):
	AudioServer.voice_play(AudioServer.voice_create(), sample)

with sample being a sample loaded from a sample library through the following method chain:

var sample = get_node("soundplayer").get_sample_library().get_sample("sample_name").get_rid()

Using this method, I found the delay to be hugely reduced, and though still perceptible, much less of a bother to the player.

Interesting find. I was told once on irc channel when trying to fight sound latency in Godot , that using AudioServer will not change anything for me because it’s just a
“way to do things with just only more control, that can be done much easier with UI and nodes automation”.
I guess someone was wrong and my fault I did not pursue to check the info myself.
So thank you very much for sharing.

Freeman | 2016-03-31 22:22

:bust_in_silhouette: Reply From: Linkpy

Another solution is to do this :

With my try, an output latency to 1-2 will glitch the sound, 3 is the minimum I think. And I think that the buffering option help for the stream. For this, you can also start the music before the real start in the game (in this case, 100ms before the game start).

I would use this settings with caution. The settings probably might work on one hardware but cause a glitch by buffer underrun on another one.
As for now Godot’s delay between the interface input and sound output are probably not a hardware latency settings related most of the time, but the the engine design (audio part of it), that is going to be rewritten soon.

Freeman | 2016-04-08 23:26