Start Event at OS Time

Hey, I know Corona is event-based and whatnot. But I am making a metronome-based app so timing is very important. I’ll spare you the unnecessary details, but what I need to know is how I can start a function at a specific OS time.

local function metronomeTick() print("tick") end local function startMetronome() started = true repeat timer.performWithDelay(20, metronomeTick)--This Line until os.time() == startTime repeat timer.performWithDelay(60/tempo, metronomeTick) local stopData = send:receive() until stopData and stopData == "Stop" end

The line I labelled should make it tick every 20 milliseconds until the os time reaches the variable startTime. However, the app just crashes. What should I do instead? Thanks.

The app is most likely crashing due to infinite loops inside your startMetronome function. You didn’t include code where you defined startTime or stopData , but I am guessing that at least one of their until conditions is never met. In fact, it is very unlikely for 

until os.time() == startTime

to ever be met since the loop would break only in the event that os.time() is exactly the same as startTime. If you were to replace the condition with “>=” then it would stop if the os.time() is ever the same or higher than startTime.

However, your function has a more fundamental flaw in it. That is, the entire idea of using a loop like this is wrong. What is going on now is that Corona is going to fire the timer multiple times every frame until the condition is met.

I’d recommend sticking more to the timers, i.e. something like:
 

local getTimer = system.getTimer local startTime, stopTime local tickTimer local function metronomeTick( tickTime ) if getTimer() \< stopTime then print("tick", "time passed: "..(getTimer()-startTime)) tickTimer = timer.performWithDelay( tickTime, function() metronomeTick( tickTime ) end ) end end local function startMetronome( tickTime, duration ) startTime = getTimer() stopTime = startTime + duration tickTimer = timer.performWithDelay( tickTime, function() metronomeTick( tickTime ) end ) end startMetronome( 20, 2000 )

I think that this is a lot closer to what you want. But I still left you with a bit more coding to do.

If you run the code, you’ll see that the time passed between the prints is actually more than 20ms. This is due to Corona being frame-based and if you run the app at 60fps, the events can only execute once every ~17ms, which is problematic if you plan to run your timers every 20ms. Additionally, a user’s device never performs constantly at 60fps. Any lag spike or performance drop in general is going to temporarily drop it, which again causes inaccuracies for the timers.

Now, these inaccuracies can be fixed to a great extent by applying delta time. You’ll find a good tutorial and sample code for it at http://www.sdknews.com/cross-platform/corona/guest-tutorial-delta-time-in-corona

Hopefully this helps!

@xedur that is one of the most lucid post I have read in at least a few weeks. When I grow up I want to write like you.

Thanks @agramonte! Let’s hope the OP finds the post as lucid as you did :smiley:

Lucid indeed

The app is most likely crashing due to infinite loops inside your startMetronome function. You didn’t include code where you defined startTime or stopData , but I am guessing that at least one of their until conditions is never met. In fact, it is very unlikely for 

until os.time() == startTime

to ever be met since the loop would break only in the event that os.time() is exactly the same as startTime. If you were to replace the condition with “>=” then it would stop if the os.time() is ever the same or higher than startTime.

However, your function has a more fundamental flaw in it. That is, the entire idea of using a loop like this is wrong. What is going on now is that Corona is going to fire the timer multiple times every frame until the condition is met.

I’d recommend sticking more to the timers, i.e. something like:
 

local getTimer = system.getTimer local startTime, stopTime local tickTimer local function metronomeTick( tickTime ) if getTimer() \< stopTime then print("tick", "time passed: "..(getTimer()-startTime)) tickTimer = timer.performWithDelay( tickTime, function() metronomeTick( tickTime ) end ) end end local function startMetronome( tickTime, duration ) startTime = getTimer() stopTime = startTime + duration tickTimer = timer.performWithDelay( tickTime, function() metronomeTick( tickTime ) end ) end startMetronome( 20, 2000 )

I think that this is a lot closer to what you want. But I still left you with a bit more coding to do.

If you run the code, you’ll see that the time passed between the prints is actually more than 20ms. This is due to Corona being frame-based and if you run the app at 60fps, the events can only execute once every ~17ms, which is problematic if you plan to run your timers every 20ms. Additionally, a user’s device never performs constantly at 60fps. Any lag spike or performance drop in general is going to temporarily drop it, which again causes inaccuracies for the timers.

Now, these inaccuracies can be fixed to a great extent by applying delta time. You’ll find a good tutorial and sample code for it at http://www.sdknews.com/cross-platform/corona/guest-tutorial-delta-time-in-corona

Hopefully this helps!

@xedur that is one of the most lucid post I have read in at least a few weeks. When I grow up I want to write like you.

Thanks @agramonte! Let’s hope the OP finds the post as lucid as you did :smiley:

Lucid indeed