GML Deltatime Metronome not accurate/constant

K

Kingkaneel

Guest
I tried making a metronome in Gamemaker which ticks to a previously specified Bpm. I used the following code:

Code:
MetronomeBeatsPerSecond = MetronomeBpm/60

MetronomeSecondsPerBeat = 1/MetronomeBeatsPerSecond

//tickup every real sec
MetronomeTotalSeconds += (delta_time*0.000001);


if MetronomeTotalSeconds >= MetronomeSecondsPerBeat{
    MetronomeTotalSeconds = 0
    MetronomeLastTick = floor(MetronomeTick)
    audio_play_sound(snd_tick,10,0)
    }
This code works kinda because it ticks at approximately the given Bpm but when checked against a proper Metronome app its a bit off and cant maintain a proper, steady pulse. The game currently runs at 30 fps and when I tried running at a higher fps it didn't really make a difference in accuracy.

Is there something obvious i'm missing? is there an easier/better way?
please let me know!
 

vdweller

Member
Have you tried get_timer() instead? I think this returns a time unit independent from what game maker thinks about its step execution time, which might be the case with delta_time.
 

FrostyCat

Member
The problem with your method is that it still doesn't account for the fact that GM code only responds when it gets a step. If the step is delayed, then the response to getting a step (playing a sound in your case) is also delayed. Your only recourse is to make the delays less noticeable by increasing the frame rate (increasing the number of chances to respond per second), decreasing the sleep interval and reducing the number of drawing calls (especially via frame skipping), and making sure vertical sync is disabled such that you aren't strictly capped by the refresh frequency.

Delta time is touted so heavily around here that a lot of people ascribe powers to it that it doesn't have. Delta time compensates lags after they happen, it doesn't prevent lags before they happen. Same thing with any hack that involves get_timer() or current_time in a Step-recurrent event.
 
Last edited:

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Your code cannot maintain a steady pulse because you are resetting the accumulated time to 0 (thus discarding any "overshoot") instead of subtracting MetronomeSecondsPerBeat from it.

Using get_timer and measuring that it "stepped over" a threshold should further improve consistency.
 

immortalx

Member
If it is relevant to the OP :
From a tiny experience I had writing a music tracker in vb.net (in working state but not finished), its very tricky to get really accurate timing.
I initially wrote it in vb6 and later moved it to .net cause it desperately needed multi-threading functionality.
I had to utilize the QueryPerformanceCounter and handle all the time-critical stuff in a separate thread, for it to be accurate enough.

You should be OK if it's just a simple metronome app, but if it's part of a bigger application things need to be very efficient.
 
T

TinyGamesLab

Guest
Your code cannot maintain a steady pulse because you are resetting the accumulated time to 0 (thus discarding any "overshoot") instead of subtracting MetronomeSecondsPerBeat from it.

Using get_timer and measuring that it "stepped over" a threshold should further improve consistency.
That is the correct answer for your problem.
Like said before, delta time will not prevent any lag and you "beat" will only play at the next step event from the "trigger moment". If you have a lag of 1 second between steps it will only be played 1 second after the trigger. Nonetheless, with ~30fps you should not be able to hear any difference from the actual time the metronome plays vs the correct time it should have played (we are talking of maybe a 0.03sec).
The problem is that by resetting your variable with this delay it will start accumulating with time hence your audible difference from the other app. Have your trigger always refer to the initial time the app started and you should be good to go!
 
K

Kingkaneel

Guest
Thanks for all the helpfull replies!

I tried out YellowAfterlife's Methode
New
Your code cannot maintain a steady pulse because you are resetting the accumulated time to 0 (thus discarding any "overshoot") instead of subtracting MetronomeSecondsPerBeat from it.

Using get_timer and measuring that it "stepped over" a threshold should further improve consistency.
And changed my code to

Code:
MetronomeBeatsPerSecond = MetronomeBpm/60
MetronomeSecondsPerBeat = 1/MetronomeBeatsPerSecond
//tickup every real sec
MetronomeTotalSeconds += (delta_time*0.000001);
if MetronomeTotalSeconds >= MetronomeSecondsPerBeat{
    MetronomeTotalSeconds -= MetronomeSecondsPerBeat
    audio_play_sound(snd_tick,10,0)
    }
Which improved the consistency of the pulse by a little bit but the it's still audibly unstable

I dont understant the part about the get_timer and the threshold checking. I would really appreciate it if you could explain this a bit more, it might be really helpfull advice!

Thank you in advance!
 
Top