Timing Trouble

I'm having an issue timing a function call with the beat on a music track. I've calculated the milliseconds per beat to run the function using the following code;

local function beat(event)
print(event.time)
local beatTimer = timer.performWithDelay(mspb, beat)
end

bpm = 105 -- beats per minute of the track
mspb = (60000/bpm) -- milliseconds per beat

beat()

The music and the function line up nicely at first but slowly lose sync as the program executes. I've double and triple checked my audio file and it is a nice steady 105 bpm the whole song and the calculations are correct in theory but the output in the terminal is slightly slower than the music. I was wondering if maybe there is some issue where processor load could slow down the timer built into corona and cause this.

Any help is appreciated on this one.

Sorry, none of the audio engines in Corona are designed for this kind of timing synchronization. (FYI, Android itself really isn't setup for high performance audio.) In general, audio plays on another background thread while your Lua loop works mostly on the main thread so there will be drift when switching between threads. Also, the timers that run performWithDelay are not high precision timers to begin with.

computer timers are never completely accurate which is why most music programs use an audio buffer that presumably talks to the soundcard on a hardware interrupt.

Flash 10 does this now
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/SampleDataEvent.html

writing audio bytes directly into the Sound buffer...

1
2
3
4
5
6
7
8
9
10
11
12
13
//The following example plays a simple sine wave.
 
var BUFFER_SIZE:uint = 8192;
var mySound:Sound = new Sound();
function sineWaveGenerator(event:SampleDataEvent):void {
    for ( var c:int=0; c<BUFFER_SIZE; c++ ) {
        event.data.writeFloat(Math.sin((Number(c+event.position)/Math.PI/2))*0.25);
        event.data.writeFloat(Math.sin((Number(c+event.position)/Math.PI/2))*0.25);
    }
}
 
mySound.addEventListener(SampleDataEvent.SAMPLE_DATA,sineWaveGenerator);
mySound.play();

Oh. Well that answers my thread then: http://developer.anscamobile.com/forum/2011/02/22/syncing-music-and-animation

Where did I put the drawing board?

i'd avoid drawing applications too for now ;)

That's enough out of you!

:-)

You are just going about this the wrong way.

You can still accomplish pretty much what you want and be off no more than 16ms of the mark for any given beat--BUT--the most important thing is that the target to hit will not drift so over time, every beat will be triggered when it should, with an error of a maximum of 16 milliseconds from the ideal target-- some desktop soundcards have way higher latency than this... so really-- don't give up at all!

What you need to do is store the original system ticks at the music start time, then keep polling on each enterframe event (at 60fps of course) to see if you passed the next calcuated beat. if you have, then calculate the system time of the next beat and keep going.

And secondly, a hypothetical-

even if the performWithDelay timer was perfect, your recursive call within beat() is confusing. Even if it was perfect you should just have am infinitely looping performwithdelay outside of the beat function (e.g. timer.performWithDelay(yourBPM, beat, 0)) that calls beat. The reason is that there would still be a very small amount of processing time inserted before the timer is called again while the code in the function is being processed... the insertion of this time on each iteration would keep pushing the timing error farther and farther out. As it is, there is probably processing time insertion issues between loops with the looping mode of performWithDelay, so just use the method of checking the system ticks against the system ticks value for the next calculated beat, OK?? OK!!

As a test a while back I had a perfectly-spliced wave file (e.g. setting it to loop would produce the exact number of samples to maintain even tempo) audio loop going going, and using the method of checking the system ticks against the system ticks value for the next calculated beat, I had a bouncing character (using ease quad transition to) going in perfect sync with the music for a long long time and it never went out of sync for as long as I was patient enough to watch.

See my reply on this thread for more:
https://developer.anscamobile.com/forum/2011/08/15/drum-toy-0

Cheers.

Gary

views:1970 update:2012/2/7 8:40:54
corona forums © 2003-2011