2016-03-24 3 views
3

Я выполнил инструкции в this article и создал метроном Javascript. Он использует API веб-аудио и имеет audioContext.currentTime в своем ядре для точного времени.Проблемы с синхронизацией аудиоконтекста при минимизации окна

Моя версия, доступная по адресу this plunker, является очень упрощенной версией оригинала, сделанной Крисом Уилсоном и доступна here. Для того, чтобы моя работала, поскольку она использует фактический звуковой файл и не синтезирует звуки через осциллятор, вам нужно загрузить плункер и this audio file, поместив его в корневую папку (это звук метронома «галочка», но вы может использовать любой звук, который вы хотите).

Это работает как шарм - если бы не тот факт, что если пользователь сводит к минимуму окно, то в противном случае очень точный метроном начинает икать мгновенно и ужасно. Я действительно не понимаю, в чем проблема, здесь.

Javascript

var context, request, buffer; 
var tempo = 120; 
var tickTime; 

function ticking() { 
    var source = context.createBufferSource(); 
    source.buffer = buffer; 
    source.connect(context.destination); 
    source.start(tickTime); 
} 

function scheduler() { 
    while (tickTime < context.currentTime + 0.1) { //while there are notes to schedule, play the last scheduled note and advance the pointer 
     ticking(); 
     tickTime += 60/tempo; 
    } 
} 

function loadTick() { 
    request = new XMLHttpRequest();     //Asynchronous http request (you'll need a local server) 
    request.open('GET', 'tick.wav', true);   //You need to download the file @ http://s000.tinyupload.com/index.php?file_id=89415137224761217947 
    request.responseType = 'arraybuffer'; 
    request.onload = function() { 
     context.decodeAudioData(request.response, function (theBuffer) { 
      buffer = theBuffer; 
     }); 
    }; 
    request.send(); 
} 

function start() { 
    tickTime = context.currentTime; 
    scheduleTimer = setInterval(function() { 
     scheduler(); 
    }, 25); 
} 

window.onload = function() { 
    window.AudioContext = window.AudioContext || window.webkitAudioContext; 
    context = new AudioContext(); 
    loadTick(); 
    start(); 
}; 

ответ

3

Да, это происходит потому, что браузеры душить SetTimeout и setInterval один раз в секунду, когда окно теряет фокус. (Это было сделано, чтобы обойти утечки CPU/мощности из-за разработчиков, использующих SetTimeout/setInterval для визуальной анимации, и не приостанавливают анимацию, когда ушко потерял фокус.)

Есть два способа обойти это:

1) увеличьте «взгляд вперед» (в вашем примере, 0,1 секунды) до более чем одной секунды - например, 1.1s. К сожалению, это означало бы, что вы не могли бы изменить ситуацию (например, остановить воспроизведение или изменить темп) без изменения времени, превышающего одну секунду; поэтому вы, вероятно, захотите только увеличить это значение, когда событие размытия было запущено в окне, и измените его на 0,1 при запуске события фокуса окна. Все еще не идеально.

2) Обтекаем дросселирование. :) Оказывается, вы можете это сделать, потому что setTimeout/setInterval НЕ дросселированы в веб-работниках! (Этот подход был первоначально предложен кем-то из комментариев в моей исходной статье в http://www.html5rocks.com/en/tutorials/audio/scheduling/#disqus_thread.) Я применил это для кода метронома в https://github.com/cwilso/metronome: взгляните на js/metronome.js и js/metronomeworker.js. Работник в основном просто поддерживает таймер и отправляет сообщение обратно в основной поток; посмотрите на https://github.com/cwilso/metronome/blob/master/js/metronome.js#L153, в частности, чтобы посмотреть, как он стартовал. Вы можете изменить этот фрагмент кода и использовать metronomeworker.js как есть, чтобы исправить это.

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

  • Нет связанных вопросов^_^