Timer is not accurate?

Thanks for reading.

I am developing an app for musician right now, which requires being real accurate about the Beat Per Minute. I already finished most part of my code but sadly I find out the timing is not accurate in both simulater and Iphone during the test run.

After testing with two different professional metronome, the result is the speed in program is much slower. (You will not notice the difference during the first few bars, but after 20 sec, it turns out significantly.) In order to get a right beat while BPM=120, I changed the minute to 58080 instead of 60000. But with different BPM, the minute has to be set to different number to be accurate:

minute=58560 for BPM= 80,
minute=56880 for BPM=240,

So my questions are:

1.Do you think if coding this app with more function will make it even slower?
2.Are there any other ways to code it instead of performWithDelay or getTimer to make it accurate?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BPM = 120
minute = 60000
beatT = minute / BPM
sound1 = audio.loadSound("rde1.wav")
timer.performWithDelay(beatT, function(event) audio.play(sound1) end, 0) 
 
or 
 
sound1 = audio.loadSound("rde1.wav")
curtime = 0
local function realtimer (event)
        if system.getTimer() - curtime >= 500 then
                audio.play(sound1)
                curtime = system.getTimer()
        end
end
timer.performWithDelay(1, realtimer, 0)

anyone?

The latter of your coding examples is simply unrealistic:

timer.performWithDelay(1, realtimer, 0)

You are telling Corona to fire a timer event every 1ms - which means you are saying every 1ms, give time to this one function. Other things need to happen in that 1ms time (like CPU time to fire any other events or Corona stuff that happens under the hood.. or anything else)

If you need amazing accuracy of timing, a scripting language is likely not your best avenue. You will probably want to go with C++ or ObjC so that it compiles into native code and not be interpreted - you would be in full control of what your app is doing so your timing would be way more accurate.

Even with compiled code though, you will still run into a problem where a timed event may not fire when you want it to because the CPU is busy doing something else (say, slower model iPhones) so the only thing you could really do is create some code that 'catches up' to the correct beat per minute after it detects that it is behind (so it would have to play a sound a bit early to recalibrate with the correct BPM).

Your first example is the better example where it is not pegging the CPU by firing a timer event at 1ms. In order to create a 'catch up' type scenario, you may try something like this:

1) Create a function that checks how close you are to when you need to fire the next beat. This logic would have to be smart enough to know what the timing was between the two last beats so that it knows how much sooner it needs to fire the next beat, then set a timer.performWithDelay to fire the beat.

2) Set a timer to run this beat_check every 1second.

I know nothing about music timing, so this may not even be a realistic approach to solving this problem.

You would do better if you precomputed the times the beats would fire instead of computing them on the fly in direct relation to the last one. The way you do it now, if the 3rd beat is off by 2 ms, then the 4th beat is off by at least 2ms because you are scheduling the 4th beat by 500ms after the 3rd beat.

This is obviously pseudocode, but i'm just trying to convey the general idea.

1
2
3
4
5
6
7
8
9
10
11
12
beatTimes = {0,500,1000,1500, ....etc}
currentBeatIndex = 1;
startTime = system.getTimer()
 
local function realtimer (event)
        if system.getTimer() - startTime >= beatTimes[currentBeatIndex] then
                audio.play(sound1)
                currentBeatIndex = currentBeatIndex + 1
        end
end
 
timer.performWithDelay(1, realtimer, 0) 
views:1686 update:2011/9/27 8:54:05
corona forums © 2003-2011