I was wondering what is the best way to implement a renderer in JavaScript. It's not the content part of the rendering that's really important here - I would rather like to hear when and how to effectively run the renderer code.
Currently, I have window.setInterval(renderFunc, 1000 / 20), which will just render a frame each 50 ms (i.e., fps = 20).
The point is that faster computers won't render more frames, moreover slower computers will not be able to catch up with 20 fps, so the function is called more than the computer might be able to handle.
I was thinking of a while(true) loop, but this uses 100% CPU and will freeze the computer itself - so actually my game (the renderer is of my 3D game) won't be playable anymore at all since you cannot click on buttons anymore.
What is the most efficient option in this scenario, or is there a better method that has not come to my mind?
Thanks in advance.
There's a feature that is made specifically for animation, called window.requestAnimationFrame. This means that the browsers chooses when to call your animation function instead of you hardcoding intervals. Lots of benefits from using it:
Faster computers will get higher frame rates
Windows/tabs that aren't visible are updated much less often
Varying frame rate depending on CPU usage
This article explains how to use it in a cross browser fashion:
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
The article also links to http://jsfiddle.net/paul/XQpzU/2/
You could time how long a frame render takes, and adjust frame spacing to achieve an acceptable load. E.g., if your current frame took 5ms to render, and you want 50% load, wait 5ms before the next frame. You'll want to put some sanity checks on it, and also probably use times from the last several frames.
Look into trying the while(true) loop inside of a web worker thread. This should prevent the browser from locking up. Note that you can't directly manipulate a <canvas> or any other part of the DOM from within the worker thread.
https://developer.mozilla.org/En/Using_web_workers
"setInterval() will pass the number of milliseconds late the callback was called"
-- https://developer.mozilla.org/en/window.setInterval
You could use this to dynamically adjust your interval time.
N.B. MDC docs are for Javascript as implemented by Mozilla, not ECMA Script or other implementations. You should check if this works in other browsers.
Related
I've studied requestanimationframe documentation and looked for many posts about the usage of it, but i still haven't get a clear answer on one of my thought.
I understand that requestanimationframe is scheduling a task to be executed right at the beginning of the next frame, so the code that does dom manipulations will have a better chance to be finished and painted before the pain cyle. (unless setInterval or setTimeout which usually executes a lot later, causing the well known 'running out of time before the frame gets painted' => dropping frames).
1. The recursive way
The simplest example to use requestanimation frame is the following:
function animate() {
requestAnimationFrame(animate);
// drawing code comes here
}
requestAnimationFrame(animate);
This will give you a smooth animation if you have something that needs to be updated frequently, and also giving you the benefit of not dropping any frames during your animations. This will usually gives you 60fps animations, but if your browser and screen supports 144hz/fps, then you can easily end up having 144fps animations (6.95 ms cycle).
2. Fps limited animations
Other examples also introduce ways to limit the fps to a certain number. The following code snippnet shows how to limit your fps to 30 fps:
const fpsInterval = 1000 / 30;
let previousTime = 0;
function animate(time) {
requestAnimationFrame(animate);
const deltaTime = time - previousTime;
if (deltaTime > fpsInterval) {
// Get ready for next frame by setting then=now, but also adjust for your
// specified fpsInterval not being a multiple of RAF's interval (16.7ms)
previousTime = time - (deltaTime % fpsInterval);
}
// drawing code comes here
}
requestAnimationFrame(animate);
3. One-off animations
I've been wondering a third case, when you just want your animation to be scheduled precisely, even if you have 1 or just a few amount of updates in each second.
A best example is when you have a websocket connection and each update will introduce a dom manipulation, but the update rate is far too low to do it in a recursive way.
// setting up websocket connection
ws.onmessage = (data) => {
// changing application state
myApplicationState = JSON.parse(data);
requestAnimationFrame(animate);
}
function animate () {
// drawing code comes here
}
Now here is my question for you all:
Does this make sense to call requestanimationframe right from the callback of a websocket onmessage function, or should i be using the recursive way?
So far I haven't tested it (in progress), but i have a feeling it does still going to give you the benefit of well-timed animations that can be executed without dropping a frame.
My real-life example is similar, i only have 5 messages in a second and i'd like to call requestanimationframe ONLY 5 times in a second.
My thought of doing this vs the recursive way:
Using requestanimation frame in a recursive way will incredibly increase the script execution time when measured in chrome profiling tools.
Only calling requestanimationframe when a websocket comes will still make sure to have the benefit of the feature, yet not polluting the callstack and reducing execution time
My initial measures were the following. I've spin up chrome profiling and run it for 10 seconds and measured the script execution times (we're not measuring render or paint since they are basically identical):
Script execution times:
recursive way: 4500ms
fps limited way: 4300ms
one-off animated way: 1700ms
While recursive requestanimationframe solution is giving you a super smooth and good user experience, it's also very costy for your CPU and execution times.
If you have multiple components doing animations with recursive requestanimationframe, you're going to hit a CPU bottleneck pretty soon.
Oddly this last case causing some fps drops, which I do not understand. My understanding is that you can call requestanimationframe whenever you want and it'll only execute the begginning of the next frame. But it seems there is something i dont know about.
Here is a picture of what is happening. I still don't understand it. requestanimationframe function was called before the end of the frame, but somehow because it was part of a bigger function call, it's marked as 'dropped' in chrome. Wonder if that's just a bug in the chrome profiling or was it for real dropped.
I wonder what you guys thinking about this topic. I'll update this post with some chrome performance metrics soon.
There seems to some misconception about requestAnimationFrame (rAF) magically preventing dropped frames by ensuring that whatever is executed in it will somehow run fast enough. It doesn't.
requestAnimationFrame is just a timer for "right before the next paint"*.
Its main goal is to limit the number of callbacks to just what is needed, avoiding to waste drawing operations which won't even be rendered on screen.
It does actually allow to drop frames smartly, so if one execution took the time of 3 frames to render, it won't stupidly try to execute the 3 missing frames as soon as possible, instead it will nicely discard them and get your script ready to get back from this hiccup.
So using it for updating something that doesn't match the screen refresh rate is not very useful.
One should remember that calling requestAnimationFrame is not free, this will mark the document as animated and force the event-loop to enter the update-the-rendering steps, which in itself has some performance costs. So if what you are doing in there is not going to update the rendering of the page, it can actually be detrimental to wrap your callback in a rAF callback.
Still, there are cases where it could make sense, for instance in complex pages it may be good to have a method that batches all the changes to the DOM in a rAF callback, and have all the scripts that need to access the CSSOM boxes before these changes take effect, thus avoiding useless and costly reflows.
An other case is to avoid executing scripts when the page is in the background: rAF is heavily throttled when in background and if you have some script running that doesn't need to run when the page is hidden (e.g a clock or similar), it may make sense to wrap a timer in a rAF callback to take advantage of this heavy throttling.
*Actually both Chrome and Firefox have broken this conception. In these browsers if you call requestAnimationFrame(cb) from a non-animated document (a document where no animation frame callback is scheduled, and no mouse-event occurred in the last frame), they will force the update the rendering steps to fire immediately, making this frame not synced with the monitor (and, in Chrome, sometimes not even rendered on the screen at all).
This may be a stupid/previously answered question, but it is something that has been stumping me and my friends for a little while, and I have been unable to find a good answer.
Right now, i make all my JS Canvas games run in ticks. For example:
function tick(){
//calculate character position
//clear canvas
//draw sprites to canvas
if(gameOn == true)
t = setTimeout(tick(), timeout)
}
This works fine for CPU-cheep games on high-end systems, but when i try to draw a little more every tick, it starts to run in slow motion. So my question is, how can i keep the x,y position and hit-detection calculations going at full speed while allowing a variable framerate?
Side Note: I have tried to use the requestAnimationFrame API, but to be honest it was a little confusing (not all that many good tutorials on it) and, while it might speed up your processing, it doesn't entirely fix the problem.
Thanks guys -- any help is appreciated.
RequestAnimationFrame makes a big difference. It's probably the solution to your problem. There are two more things you could do: set up a second tick system which handles the model side of it, e.g. hit detection. A good example of this is how PhysiJS does it. It goes one step further, and uses a feature of some new browsers called a web worker. It allows you to utilise a second CPU core. John Resig has a good tutorial. But be warned, it's complicated, is not very well supported (and hence buggy, it tends to crash a lot).
Really, request animation frame is very simple, it's just a couple of lines which once you've set up you can forget about it. It shouldn't change any of your existing code. It is a bit of a challenge to understand what the code does but you can pretty much cut-and-replace your setTimeout code for the examples out there. If you ask me, setTimeout is just as complicated! They do virtually the same thing, except setTimeout has a delay time, whereas requestAnimationFrame doesn't - it just calls your function when it's ready, rather than after a set period of time.
You're not actually using the ticks. What's hapenning is that you are repeatedly calling tick() over and over and over again. You need to remove the () and just leave setTimeout(tick,timeout); Personally I like to use arguments.callee to explicitly state that a function calls itself (and thereby removing the dependency of knowing the function name).
With that being said, what I like to do when implementing a variable frame rate is to simplify the underlying engine as much as possible. For instance, to make a ball bounce against a wall, I check if the line from the ball's previous position to the next one hits the wall and, if so, when.
That being said you need to be careful because some browsers halt all JavaScript execution when a contaxt menu (or any other menu) is opened, so you could end up with a gap of several seconds or even minutes between two "frames". Personally I think frame-based timing is the way to go in most cases.
As Kolink mentioned. The setTimeout looks like a bug. Assuming it's only a typo and not actually a bug I'd say that it is unlikely that it's the animation itself (that is to say, DOM updates) that's really slowing down your code.
How much is a little more? I've animated hundreds of elements on screen at once with good results on IE7 in VMWare on a 1.2GHz Atom netbook (slowest browser I have on the slowest machine I have, the VMWare is because I use Linux).
In my experience, hit detection if not done properly causes the most slowdown when the number of elements you're animating increases. That's because a naive implementation is essentially exponential (it will try to do n^n compares). The way around this is to filter out the comparisons to avoid unnecessary comparisons.
One of the most common ways of doing this in game engines (regardless of language) is to segment your world map into a larger set of grids. Then you only do hit detection of items in the same grid (and adjacent grids if you want to be more accurate). This greatly reduces the number of comparisons you need to make especially if you have lots of characters.
When adapting a web page for mobile devices I always rely on css media queries.
Recently I no longer worry only about the screen size, but also the javascript engine of many mobile devices. Some common javascript effects that rely on window scrolls or a quick sequence of DOM transformations work really bad on slow devices.
Is there any way to guess the device performance so I can enable/disable elements that look bad on slow devices?
So far I can only think of bad solutions:
screen size. narrow screen "might" mean slow device
user agent information. I could look at the device, browser or cpu, but that does not seem a stable long term solution because of the amount of devices to consider
UPDATE:
Fixed my question to focus on one problem. In the comments there is a good solution for the touch interface problem.
It certainly seems as though there is no particularly good solution for this issue (which would make sense since this type of stuff is normally supposed to be the type of stuff that's hidden away). I think either way your best starting with UA detection to take care of those platforms that are known to fall into one category or another. Then you'd have 2 options to flexibly adapt to unknown/uncertain platforms:
Progressive Enhancement: Start with a stripped down test and load a small performance test or tests to gauge the device performance and then load the files for the appropriate enhancements. Test such as already provided or at: Skip some code if the computer is slow
Graceful Degradation: Wrap those features that are candidates for causing unfavorable UX on slower devices in a higher order function that replaces them if they take too long on first execution. In this case I'd probably add it to Function.prototype and then allow an acceptable delay argument to be chained on to the function definition. After the first invocation store the time lapsed, and then on the second invocation if the time lapsed is over the delay swap out the function with a fallback. If the time elapsed is acceptable then remove the profiling code by swapping in the standard function. I'd need to sit down and work out sample code (maybe this weekend). This could also be adjusted by additional arguments such as to profile multiple times before swapping.
The first option would likely be the friendlier option, but the 2nd may be less intrusive to existing code. Cookies or collecting further UA data would also help from continuing to profile after information is retrieved.
The only way I could think of would be to run some kind of speed test in JS in the background either before or while using the effects. This should catch devices that are slow due to their processor speed or vice versa, catch devices that are time accurate/fast. However if the devices have optimisations meaning they use different processors to calculate graphical effects, this will not work.
var speedtest = function(){
/// record when we start
var target = new Date().getTime(), count = 0, slow = 0;
/// trigger a set interval to keep a constant eye on things
var iid = setInterval(function(){
/// get where we actually are in time
var actual = new Date().getTime();
/// calculate where we expect time to be
target += 100;
/// 100 value here would need to be tested to find the best sensitivity
if ( (actual - target) > 100 ) {
/// make sure we aren't firing on a one off slow down, wait until this
/// has happened a few times in a row. 5 could be too much / too little.
if ( (++slow) > 5 ) {
/// finally if we are slow, stop the interval
clearInterval(iid);
/// and disable our fancy resource-hogging things
turnOffFancyAnimations();
}
}
else if ( slow > 0 ){
/// decrease slow each time we pass a speedtest
slow--;
}
/// update target to take into account browsers not being exactly accurate
target = actual;
/// use interval of 100, any lower than this might be unreliable
},100);
}
Of course by running this you'll affect the speed of the device as well, so it's not the best solution really. As a rule I tend to disable animations and other superfluous things simply when the screen is small.
One other downside to this method - that I've experience before - is that one certain browsers that implement multi-tabbed environments setIntervals are automatically limited to a certain speed when the tab is not being viewed. This would mean for this browsers tabbing away would automatically downgrade their experience - unless this imposed speed limited could be detected some way.
You could make your own mini benchmark of sorts. Do some demanding calculations and time the result. If it's slower than the device you consider to be slowest supported device then you drop to a less intensive version of your site.
You could also just make an easily accessible link to switch to the more basic site if the user is experiencing performance issues.
Going off screen size is not a good idea. Plenty of modern phones have small screens with fast processors.
When writing a JavaScript animation, you of course make a loop using setInterval (or repeated setTimeout). But what is the best delay to use in the setInterval/setTimeout call(s)?
In the jQuery API page for the .animate() function, the user "fbogner" says:
Just if anyone is interested: Animations are "rendered" using a setInterval with a time out of 13ms. This is quite fast! Chrome's fastest possible interval is about 10ms. All other browsers "sample" at about 20-30ms.
Any idea how jQuery determined to use this specific number?
Started bounty. I'm hoping someone with knowledge of the source code behind Chromium or Firefox can provide some hard facts that might back up the decision of a specific framerate. Or perhaps a list of animations (or frameworks) and their delays. I believe this makes for an interesting opportunity to do a bit of research.
Interesting - I just took the time to look at Google's Pac-Man source to see what they did. They set up an array of possible FPSes (90, 45, 30), start at the first one, and then each frame they check the "slowness" of the frame (amount the frame exceeded its allotted time). If the slowness exceeds 50ms 20 times, the framerate is notched down to the next in the list (90 -> 45, 45 -> 30). It appears that the framerate is never raised back up, presumably because the game is so short-lived that it wouldn't be worth the trouble to code that.
Oh, and the setInterval delay is of course set to 1000 / framerate. They do, in fact, use setInterval and not repeated setTimeouts.
I think this dynamic framerate feature is pretty neat!
I would venture to say that a substantial fraction of web users are using monitors that refresh at 60Hz, which translates to one frame every 16.66ms. So to make the monitor the bottleneck, you need to produce frames faster than 16.66ms.
There are two reasons you would pick a value like 13ms. First, the browser needs a little bit of time to repaint the screen (in my experience, never less than 1ms). Which puts you at, say, updating every 15ms, which happens to be a very interesting number - the standard timer resolution on Windows is 15ms (see John Resig's blog post). I suspect that an well-written 15ms animation looks very close to the same on a wide variety of browsers/operating systems.
FWIW, fbogner is plain wrong about non-Chrome browsers firing setInterval every 20-30ms. I wrote a test to measure the speed of setInterval firing, and got these numbers:
Chrome - 4ms
Firefox 3.5 - 15ms
IE6 - 15ms
IE8 - 15ms
The pseudo-code for this is this one:
FPS_WANTED = 25
(just a number, it can be changed while executing, or it can be constant)
TIME_OF_DRAWING = 1000/FPS_WANTED
(this is in milliseconds, I believe it is accurate enough)
( should be updated when FPS_WANTED changes)
UntilTheUserLeavesTheDrawingApplication()
{
time1 = getTime();
doAnimation();
time2 = getTime();
animationTime = time2-time1;
if (animationTime > TIME_OF_DRAWING)
{
[the FPS_WANTED cannot be reached]
You can:
1. Decrease the number of FPS to see if a lower framerate can be achieved
2. Do nothing because you want to get all you can from the CPU
}
else
{
[the FPS can be reached - you can decide to]
1. wait(TIME_OF_DRAWING-animationTime) - to keep a constant framerate of FPS_WANTED
2. increase framerate if you want
3. Do nothing because you want to get all you can from the CPU
}
}
Of course there can be variations of this but this is the basic algorithm that is valid in any case of animation.
When doing loops for animations, it's best that you find a balance between the speed of the loop, and how much work needs to be done.
For example, if you want to slide a div across the page within a second so it is a nice effect and timely. You would skip coordinates and have a reasonably fast loop time so the effect is noticeable, but not jumpy.
So it's a trial and error thing (by having to put work, time, and browser capability into account). So it doesn't only look nice on one browser.
The number told by fbogner have been tested.
The browsers throttle the js-activity to a certain degree to be usable every time.
If your javascript would be possible to run every 5msec the browser runtime would have much less cpu time to refresh the rendering or react on user input (clicks) because javascript-execution blocks the browser.
I think the chrome-devs allow you to run your javascript at much shorter intervals than the other browsers because their V8-Javascript-Engine compiles the JavaScript and therefore it runs faster and the browser will noch be blocked as long as with interpreted js-code.
But the engine is not only so much faster to allow shorter intervals the devs have certainly tested which is the best possible shortest interval to allow short intervals and don't blocking the browser for to long
Don't know the reasoning behind jQuery's interval time, as 13ms translates to 80fps which is very fast. The "standard" fps that's used in movies and such is 25fps and is fast enough that human eye won't notice any jittering. 25fps translates to 40ms, so to answer your question: anything below 40ms is enough for an animation.
I'm playing some notes at regular intervals. Each one is delayed by a random number of milliseconds, creating a jarring irregular effect. How do I fix it?
Note: I'm OK with some latency, just as long as it's consistent.
Answers of the type "implement your own small SoundManager2 replacement, optimized for timing-sensitive playback" are OK, if you know how to do that :) but I'm trying to avoid rewriting my whole app in Flash for now.
For an example of app with zero audible latency see the flash-based ToneMatrix.
Testcase
(see it here live or get it in an zip):
<head>
<title></title>
<script type="text/javascript"
src="http://www.schillmania.com/projects/soundmanager2/script/soundmanager2.js">
</script>
<script type="text/javascript">
soundManager.url = '.'
soundManager.flashVersion = 9
soundManager.useHighPerformance = true
soundManager.useFastPolling = true
soundManager.autoLoad = true
function recur(func, delay) {
window.setTimeout(function() { recur(func, delay); func(); }, delay)
}
soundManager.onload = function() {
var sound = soundManager.createSound("test", "test.mp3")
recur(function() { sound.play() }, 300)
}
</script>
</head>
<body>
</body>
</html>
I know this isn't the answer you want to hear, but there is no way to stop this, regardless of whether you wrote your own flash library to play sound or not.
For everyone who said "it works fine for me!" try resizing or moving your browser window as the poster's demo plays out. You'll hear more than just a subtle amount of delay. This is most noticeable in Firefox and IE, but even Chrome will experience it.
What's worse, if you click and hold the mouse down on the close box for the browser window, the sound completely stops until you release your mouse (you can release it outside of the close box and not actually close the window, FYI).
What is going on here?
It turns out that when you start resizing or moving around the browser window, the browser tries to multi-task the act of changing the window properties with the act of keeping up with the javascript going on in the window. It short-changes the window when it needs to.
When you hold down the mouse over the close box in the browser window, time stops completely. This is what is happening in smaller increments when you are re-sizing or moving the window: time is standing still in the javascript world in small, sporadic chunks (or large chunks, depending on how slow your machine is).
Now, you might say "sure, resizing the browser or holding down the close button makes the browser pause, but normally this wouldn't happen". Unfortunately you would be wrong.
It happens all the time, actually. I've run tests and it turns out that even by leaving the browser window completely still, not touching the mouse, and not touching the keyboard, backgrounds processes on the computer can still cause "hiccups", which means that for brief periods (perhaps as small as a few milliseconds) time is "standing still" in the browser, at completely random intervals outside of your control.
What do I mean by "standing still"? Let's say you have a setInterval() call (this applies to setTimeout also) running every 33 milliseconds (about 30 frames per second). Now, you would expect that after every 33 "real world" milliseconds your function would get called. And most of the time, this is true.
But when "hiccups" start happening, your setInterval call might happen in 43 milliseconds. What happened during the 10 ms? Nothing. Time stood still. Nothing on the browser was being updated. If you had sound playing, it will continue playing, but no NEW sound calls would start playing, because no javascript is being executed at all. If you had 5 setInterval() functions running, they would have all been paused for 10ms at some point.
The only way to tell that "time stood still" is to poll real-world time in your setInterval function callbacks. You'll be able to see that the browser tries to keep up most of the time, but that when you start resizing the window or doing something stressfull, the intervals will be longer than usual, but that all of your code will remain synched up (I'm making games using this technique, so you will see that all your game updates happen in synch, but just get slightly stuttered).
Usually, I should point out, these stutters are completely unnoticeable, and unless you write a function to log real-world time during setInterval times (as I have done in my own testing) you wouldn't even know about it. But it becomes a problem if you try to create some type of repetitive sound (like the beeping in the background of Asteriods) using repetitive play() calls.
My suggestion? If you have a sound that you know will loop, give it a long duration, maybe 10 seconds, and you'll be less likely to notice the hiccups (now, the graphics on the screen could still hiccup, but you're screwed there).
If you are writing a game and having the main character fire off a machine gun, don't do 10 rapid-succession calls to playSound('singleShot'), do one call to playSound('machineGunFire10Rounds'), or something along those lines.
You'll have to do some trickery to get around it, but in most cases you'll be alright.
It seems that Flash applets run in a process that is somehow less affected this whole "time freezing" thing going on in the regular browser/javascript environment, but I can still get it to happen, even on your link to the ToneMatrix example, by resizing or moving the browser window.
But Flash still seems much better than javascript. When I leave the browser alone I'd be willing to bet that Flash is not freezing for any amount of time and that intervals are always running on time.
tl;dr:
you're screwed in what you're hoping to achieve
try to deal with it using some workarounds
re-write your project in pure flash (no javascript)
wait for browsers to get better (Firefox 4 is getting a new javascript engine called JaegerMonkey which will be interesting to watch)
how do I know all this? I've done a lot of testing & logging with javascript, setInterval, and soundManager/html5 audio calls
In my comment to your question I mentioned that I don't hear the irregularity when I play your sample. That means I'm either "rhythm deaf", or that there may be something in your setup that interferes with good realtime performance. You don't mention any details of your environment, but you may have other processes running on your computer that are sucking up CPU cycles, or an older version of Flash that may not do a good job of handling sound latencies. I myself am using a recent version of Flash (10.something), whereas your parameters call for Flash 9. But maybe I should assume that if you're smart enough to be using SoundManager2 and StackOverflow that you would have eliminated these problems.
So here are some troubleshooting possibilities and comments that come to mind:
1) the SoundManager site has a number of demos, including JS-DOM "painting" + Sound, V2. Are you hearing irregular latencies and delays there? If not, maybe you can compare what they're doing there against what you're doing. If you are, then maybe look at your machine environment. When I run that demo, it is very responsive. (EDIT: Looking at it more closely, however, you can watch how the size of the brush stamps varies during a stroke. Since it varies with the time interval between mouse events (assuming you are keeping a constant mouse speed), you can visually see any irregularities in the pattern of mouse events. I can see occasional variation in stamp sizes, which does indicate that mouse events are not coming in at regular times. Which brings us to Javascript events.)
2) Javascript setTimeout() and setInterval() are not very reliable when it comes to timing. Mostly they will come back in some ballpark of the interval you have requested, but there can be large variations, usually delays, that make them unreliable. I've found that the same is true when using ActionScript inside Flash. You might want to print out the times that your sound.play() call is being made to see whether the irregularities are due to the irregularities in setTimeout/setInterval(). If that's the case, you could try shortening the interval, and then polling the system time to get much closer to the 300ms interval that you want. You can poll system time using new Date().getTime(), and this seems to have ms accuracy. Polling is of course a hideous hack that sucks up cycles when they could be used for something else, and I don't recommend it in general, but you may try it to see whether it helps. EDIT: Here's a writeup by John Resig on the handling of input and timer events in js.
3) When flash plays sounds, there is usually a latency involved, just so that the player can "build up a head of steam" and make sure there's enough stuff in the buffer to be played before the next buffer request is filled. There's a trade off between this latency and the reliability of uninterrupted playback. This might be a limitation you can't do anything about, short of "implement[ing] your own small SoundManager2 replacement", which I know you don't want to do.
Hope this helps. I recently wrote an AS3 sound experiment which exposed me to some of the basics, and will be watching this space to see what other suggestions people come up with.
You are using the javascript interval, which can not be guaranteed to fire at an exact time. I am sure that the internal Flash timing is far more reliable.
But this might help, fire recur AFTER you have triggered playing the sound.
window.setTimeout(function() { func(); recur(func, delay); }, delay);
As explained in another answer, there's no way you can avoid this. But...
I've done some experiments to mitigate this issues, and in the end I resorted to using:
lowLag: responsive html5 audio, which uses SoundManager2 for some cases where it's the fastest option available.
GSAP JS – Professional-Grade JavaScript Animation, in order to do the animation of properties and syncing of the audio (you probably don't care about this :P)
Take a peek at the source on the prototype of the demo, and (if possible) give lowLag a shot. It worked nicely for me.
Good luck!