High resolution (eg. 1/200 sec) timer in Godot?

51 Views Asked by At

I am trying to do audio panning in Godot using AudioEffectPanner and when I update the pan of it the volume levels are updated right away, resulting in an audible pop.

I am calculating the target pan value in _process(), but even when smoothing it is quite noticeable.

I tried to move the smoothing to _physics_process(), tried to update the Physics FPS to a high value (200 FPS) but apparently it is only called more times before _process() is called (tested with timestamps, got the calls in groups).

I tried to set up a Timer as well as a last resort but it is also evaluated before the _process() is called.

So any of the methods I tried result in updating at a maximum of 60 times per seconds (my display's update rate, it will vary on player's setups).

Is there a way in Godot to have a timer with greater resolution? Or even just having a separate thread in a loop of just updating the volume and sleeping? Maybe there is a method to update the AudioEffectPanner and it will take care of smoothing it out?

(I am currently using Godot 3.5 and in the middle of a game jam, I will switch to 4.x for my next project.)

1

There are 1 best solutions below

1
On BEST ANSWER

Timers only run on the engine's proccess cycles as you have seen. However with OS.delay_msec()/OS.delay_usec() you can make a thread that calls your function at faster intervals.

Note: this is likely still not 100% accurate to the desired time as it is still limited by the CPU. Additionally it will also deviate more the longer your processing function takes.

Sample Script:

extends Node

var thread: Thread
var quitting := false

func _ready() -> void:
    thread = Thread.new()
    thread.start(self, "thread_func", null, Thread.PRIORITY_HIGH)


func stop_thread() -> void:
    # Setting quitting to true stops the thread, 
    # prevents a dead lock when cleaning up the thread
    quitting = true
    thread.wait_to_finish()


func do_thing() -> void:
    print(OS.get_system_time_msecs())


func thread_func(args = null) -> void:
    while not quitting:
        OS.delay_usec(1000000/200)
        do_thing()