2010-10-27 2 views
4

Я пытаюсь написать простой музыкальный секвенсор в Javascript.Выполнение «реального времени» javascript без зависания браузера

Звуки будут играть SoundManager2

Я быстро понял, что SetTimeout и setInterval бесполезны для такого рода времени. Их точность просто не достаточно хороша.

Так что я пытаюсь вместо это:

Создать очередь звуковых событий (а 2d массив [примечание, время])

Процесс очереди в цикле в то время как

В псевдокоде это может выглядеть следующим образом:

// 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. 
    } 
} 

Через де bugging Я обнаружил, что этот метод кажется достаточно точным (вызов playNote производится в то время, когда он должен).

Однако, пока «последовательность» воспроизводится, все остальные Javascript (включая бит, который фактически ДЕЛАЕТ звук) приостановлены, что вряд ли является неожиданностью.

Это означает, что у меня есть тишина в течение длительного времени, которое требуется для выполнения последовательности, а затем выполняется ВСЕ вызовы playNote.

Я попытался изолировать цикл while в своей собственной функции, а затем называть его через setTimeout, надеясь, что это создаст фоновый поток, выполняющий его собственную вещь (а именно воспроизведение последовательности), не останавливая все другие действия JS , Это не работает

Я также попытался вызвать функцию playNote с помощью setTimeout, надеясь, что хотя действительно пользовательский интерфейс заморожен, по крайней мере, последовательность воспроизводится правильно, но это тоже не работает.

Я также пробовал комбинацию, но, как вы, наверное, уже догадались, это тоже не работает.

Так что мой вопрос:

Как я могу иметь очередь событий, обработанные с точным временем, а не закрывая все другие кодовые исполнения во время запуска

ответ

1

Я не знаю, если есть решение для старых браузеров, но web workers предназначены для выполнения parrallel в JavaScript.

Они поддерживаются в последних версиях Chrome и Firefox, я не знаю о других браузерах.

+0

Старых браузеры не имеют значения для меня.Эта вещь будет в конечном итоге как онлайн-приложение, где будет справедливо сказать: «Если вы хотите использовать это, вам нужно DITCH NS4.6!» (и мне не нужно будет поддерживать IE). Однако, если он может работать в webkit на мобильном телефоне (Android-IOS), это было бы замечательно. – Acebone

+0

@Acebone, я считаю, что он поддерживается на обеих мобильных платформах, но должен был бы это сделать, чтобы быть уверенным. – mikerobi

+0

Ну, веб-пользователи не будут создавать Flash или HTML5 Audio в фоновом режиме из-за ограничений браузера. Так что мой вопрос по-прежнему стоит – Acebone

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)); 

Edit: Проблемы с рекурсивными вызовами точностью + таймером следует позаботиться о по 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

Oh man! Это блестяще!! – Acebone

+0

Могу ли я спросить, для чего предназначены круглые скобки? – Acebone

+0

Это самоисполняемая функция. Параны делают это выражение функции, а не оператор, а оператор '()' вызывает именованно-анонимную функцию и передает 'q' в качестве аргумента. Написание его так, как это делает его действовать как цикл while, потому что он запускается, как только JS-движок добирается до него. – xj9

Смежные вопросы