Flash Player use of Internal clock
Internal clock in flash player sucks a lot. I am doing a project that needs to have a lot of precision in the time intervals. The project is like a music sequencer, so the timer have to tick always at the same time, because if not you listen like an empty space between sounds. I have done some tests with the event OnEnterFrame and the Timer function, and the results are the follows: if you start a timer with 3000 milliseconds the results will be: 3045, 3072, 3000, 3305, 3079, 3063, 3081, so you have like 80 milliseconds of difference, it’s not good enough. I have done the same test in c#, and the results are 3000,3000,3000,3000. It’s a little bit sad, if anyone knows a solution, please comment.
May 7th, 2008 at 9:19 pm
Yeap, I’ve came across that some weeks ago.
Check this Keith post on: http://www.bit-101.com/blog/?p=910
Cheers
May 7th, 2008 at 10:07 pm
I don’t think it’s the clock itself that is at fault but perhaps the overhead of the event being broadcasted that is causing a delay…perhaps…
May 7th, 2008 at 10:10 pm
Frame playback is not precise, nor does it try to be. Same applies to timers (which in turn are based from frame rate).
For best results, you would need use getTimer() or the Date class to poll the system time.
May 7th, 2008 at 10:55 pm
Flash uses a frame based system as a way of getting around the fact that it runs with only one thread, and will delay a frame at any point if it can’t get the work it needs to get done completed within that frame. This works well in keeping flash apps responsive, because it will delay redrawing the UI, until a frame where it has some spare capacity available. (Timers in C# are seperate threads, so you don’t have this problem).
Unfortunatly this does cause an almost unsolvable problem for you. The only thing I can think of, is if you are using flash (and not flex), you could see whether adjusting your framerate could give you more accuracy. Other than that, I think that flash might not be the platform for you…
May 8th, 2008 at 12:58 am
Tony thanks you for the explication. I Think Actionscript really need a multithreading system controlled by us.
May 8th, 2008 at 3:02 am
My stupid and (Don’t try this at home) solution… obviously it works only with more than 1 second intervals to get some precision and probably it kills cpus after some time…
function customTimer(interval:Number):void {
import flash.utils.getTimer;
import flash.utils.setInterval;
var timerPosition:Number = 0;
function checkTimer() {
function updateInterval(interval:Number):void {
if (interval - (getTimer() - timerPosition) < 500) {
while (getTimer() - timerPosition < interval) {
//do nothing
};
} else {
return;
}
if ((getTimer() - timerPosition) == interval) {
timerPosition += interval;
//Now we get precision…
trace(getTimer());
}
}
updateInterval(interval);
}
setInterval(checkTimer, 10);
}
customTimer(1150);
//customTimer(2000);
//customTimer(2300);
//customTimer(3000);
May 8th, 2008 at 3:28 am
Sorry for this new post, just less code… Here in Italy it’s time to sleep, but…
function customTimer(interval:Number):void {
import flash.utils.getTimer;
import flash.utils.setInterval;
var timerPosition:Number = 0;
function updateInterval():void {
while (getTimer() - timerPosition < interval) {
//do nothing
};
if ((getTimer() - timerPosition) == interval) {
timerPosition += interval;
//Now we get precision…
trace(getTimer());
}
}
setInterval(updateInterval, interval / 10);
}
customTimer(3000);
I don’t know if the while loops are cpu killers but they are the only super fast stuff to check the getTimer() value with precision. Obviously this function uses one Interval to check and for this reason this method works good only with intervals of more than one second…
Feel free to delete these comments if useless…
Thanks for blogging!
Nick
May 8th, 2008 at 9:03 am
You can highly minimize the time drift by doing two things, one: is setting the event to a higher priority and increasing the framerate.
Also you might want to check Craftymind’s post on AVM2 elastic racetrack: http://www.craftymind.com/2008/04/18/updated-elastic-racetrack-for-flash-9-and-avm2/.
Just using the two first will reduce your time drift from 80 to something between 2-10. Afterwards you can correct the time drift with the date.getTime(), so you actually know how much behind you are.
May 8th, 2008 at 9:10 pm
May 8th, 2008 at 10:22 pm
Hi Ivan, you’re right, I know that… but i wrote that this is a nighty and easy/stupid approach… btw the second function I posted is really bad… the first one is lighter… but, in any case, it can’t be used in any project… My intention was to find a light at the end of the tunnel, a starting point, one possible approach… My main idea was to find a way to wait some milliseconds to round the timer, and the olny one stuff I thought able in this job is a loop, that can check in less than one millisecond each millisecond… the utopy is the use of an infinite loop without any interval like this: (obviously the player will crash)
function customTimer(interval) {
var timerPosition:Number = 0;
function updateInterval(interval) {
while (getTimer() - timerPosition < interval) {
}
if ((getTimer() - timerPosition) == interval) {
timerPosition += interval;
trace(getTimer());
updateInterval(interval);
}
}
updateInterval(interval);
}
customTimer(3000);
Bye bye
May 9th, 2008 at 2:19 am
Hi Ivan,
I elaborated my idea and it seems to do a good job with low cpu usage, my MBP cpu is lower than 4-6%. No infinite loops, no execution time errors…
I added one more param, “precision”, that rapresent a reasonable value of Flash setInterval precision. I can say that “interval and precision” are inversely proportional.
Here is the as2 code if you want to try this… I’m sorry if I’m maybe follow an usless method, but now this stuff is like a game for me
And I’m playing…
The code:
var customTimer:Function = function (interval:Number, precision:Number):Void {
var myInterval;
var timerPosition:Number = 0;
var update:Function = function ():Void {
var t:Number = 0;
clearInterval(myInterval);
while (getTimer() - timerPosition < interval) {
t++;
}
(t == 0) ? trace(”I’m sorry, too hard to get absolute precision”) : trace(”Total iterations to get precision: ” + t + ” (Higer values need greater precision for lower cpu”);
if ((getTimer() - timerPosition) == interval) {
timerPosition += interval;
trace(”———-”);
trace(”Timer in this moment: ” + getTimer() + ” ms”);
trace(”———-”);
myInterval = setInterval(update, Number(interval * precision));
}
};
update();
};
customTimer(3000, 0.965);
Bye, Nick
May 9th, 2008 at 10:53 pm
As3 code, if anyone wants to give it a try:
var timer:Timer;
var timerPosition:Number;
var interval:Number;
var precision:Number;
function CustomTimer(delay:Number) {
timerPosition = 0;
interval = delay;
precision = 0.965;
timer = new Timer(delay);
timer.addEventListener(TimerEvent.TIMER,update);
timer.start();
}
function update(e:TimerEvent):void {
var t:Number = 0;
timer.stop();
while (getTimer()-timerPosition < interval) {
t++;
}
(t == 0) ? trace(”I’m sorry, too hard to get absolute precision”) : trace(”Total iterations to get precision: ” + t + ” (Higer values need greater precision for lower cpu”);
if ((getTimer()-timerPosition) == interval) {
timerPosition += interval;
trace(”Timer in this moment: “+getTimer()+” ms”);
timer = new Timer(interval*precision);
timer.addEventListener(TimerEvent.TIMER,update);
timer.start();
}
}
CustomTimer(3000);
May 10th, 2008 at 12:19 am
Hi Ivan, yes I tried with some tasks running under and the flash intervall precision go down:
I disposed 4 mc on the stage running crazy on the enterframe. With these simultaneous tasks I needed to set the precision value not at 0.99, but at 0.97 to let the timer go on… with more clips the correct value can be 0.94 or 0.8 or 0.3.
Flash player’s performances decrease with a lot of tasks, so, with the performances, decreases also the flash interval precision, so we need to consider this when we set the precision value. The bad thing is that decreasing the precision value we need greater loops to reach the correct interval… So more tasks more cpu usage…
The other problem, referred to the function I posted, is that I do calculations of the timer position using the time value saved into the variable timerPosition. And this variable must have as value a multiple of our interval. If you do something after the while loop, where we increase the timer position, we also need to take care of the time needed by this stuff to execute, otherwise our timerPosition value gets bad value that never more will verify the if statement causing the interruption of our custom interval…
everything is bad…
I think that this time an hack isn’t enough to find an acceptable solution to this flash limit… only you, actionscript gurus, maybe can find the right trick and I will be here reading…
thanks for blogging masters
May 11th, 2008 at 3:34 am
One working update with simoultaneous animations and text…
http://www.studiozu.com/custom_timer/customTimer.swf
Bye!
May 11th, 2008 at 4:29 pm
Ok, I think that now I’ve got a good result. The customTimer auto adjust itself for better performance, if it loose some ms it doesn’t fail, but auto adjust the next interval. We can set a maxLoop value to improve performances…
Than I have associated one task to the interval and it doesn’t create problems, the timing is always perfect.
I added a normal setInterval monitor for comparing…
Now I don’t know if this is a good solution, but I feel good now
http://www.studiozu.com/custom_timer/customTimer.swf
July 4th, 2008 at 10:31 am
Hello everyone!
I’m doing a similar project, in which I have music tracks playing and I need precise timing.
Did anyone find a solution to this?
The file that Nick posted gives 404.
If anyone has an idea, please mail me at cool-rr@cool-rr.com
Thanks,
Ram
July 9th, 2008 at 10:18 pm
Thank you from Poland