2010-10-27 63 views
4

我想在Javascript中编写简单的音乐测序器。执行'realtime'javascript而不挂浏览器

声音将SoundManager2

我很快意识到,setTimeout和setInterval的是无用的这种定时播放。他们的准确性不够好。

那么我想的却是这样的:

创建的声音事件队列(二维数组[时间])

过程中while循环

队列

在伪代码可能是这样的:

// The queue of time/note values (millisecs) 
var q = [[0, C], [250, D], [500, E]] 

var begin = (new Date).getTime() 

while(q.length > 0){ 
    var now = (new Date).getTime() 
    var eventTime = q[0][0] + begin 

    if(now >= eventTime){ 

     playNote(q[0][1]) // Play the note 
     q.shift()  // Now that the note has been played, discard it. 
    } 
} 

通过德窃听我发现这种方法似乎足够精确(playNote调用是在它应该的确切时间进行的)。

但是,当播放'序列'时,所有其他Javascript(包括实际发出声音的位)都被暂停,这并不令人意外。

这意味着我会沉默很长时间才能运行序列,然后执行所有的playNote调用。

我试着在它自己的函数中隔离while循环,然后通过setTimeout调用它,希望这会创建一个后台线程执行它自己的东西(即播放序列)而不会停止所有其他JS执行。这是行不通的

我也尝试过使用setTimeout调用playNote函数,希望尽管UI被冻结,至少序列播放正确,但这也不起作用。

我也试过了一个组合,但是正如你可能已经猜到的那样,那也行不通。

所以我的问题是:

我怎么能有精确定时处理事件的队列中,同时运行

回答

1

过程中未关闭所有其他代码执行,我不知道是否有针对较旧浏览器的解决方案,但web workers适合在JavaScript中执行平行执行。

在最近的Chrome和Firefox版本中,我不支持其他浏览器。

+0

旧版浏览器不相关的我。这件事最终会成为一个在线应用程序,可以公平地说'如果你想使用这个,你得到DITCH NS4.6!' (我也不需要支持IE)。 但是,如果它可以运行在webkit上的移动(android - IOS),那真是太棒了。 – Acebone 2010-10-27 13:41:22

+0

@Abone,我相信它支持两个移动平台,但必须谷歌它肯定。 – mikerobi 2010-10-27 13:43:25

+0

好吧,由于浏览器的限制,Webworkers不会在后台实例化Flash或HTML5音频。所以我的问题仍然存在 – Acebone 2010-10-28 09:30:57

0

如果用递归函数替换while循环(它不必自动执行),浏览器将不会冻结。

(function foo (q) { 
    var now = (new Date).getTime(), 
     eventTime = q[0][0] + begin; 
    if (q.length > 0) { 
     if (now >= eventTime) { 
      playNote(q[0][1]); // Play the note 
      q.shift(); // Discard played note 
     } 
     return foo(q); // Pass q into the next round 
    } else { 
     return; // End the "loop" 
    } 
}(q)); 

编辑:与递归调用+计时精度的问题应该被照顾的setInterval

var timer = setInterval(function foo() { 
    var now = (new Date).getTime(), 
     eventTime = q[0][0] + begin; 
    if (q.length > 0) { 
     if (now >= eventTime) { 
      playNote(q[0][1]); // Play the note 
      q.shift(); // Discard played note 
     } 
    } else { 
     clearInterval(timer); // End the "loop" 
    } 
}, 10); // This is in ms (10 is just a random number) 
+0

哦!太精彩了!! – Acebone 2010-10-28 22:18:48

+0

我可以问附上的括号是什么吗? – Acebone 2010-10-28 22:19:33

+0

这是一个自我执行的函数:parens使它成为函数表达式而不是语句,'()'运算符调用named-anonymous函数并将'q'作为参数传递。像这样写它使得它像'while'循环一样,因为只要JS引擎达到它就会被执行。 – xj9 2010-10-29 01:19:11