2016-03-24 12 views
3

Ich folgte den Anweisungen in this article und erstellte ein Javascript-Metronom. Es nutzt die Web Audio API und hat audioContext.currentTime in seinem Kern für präzises Timing.AudioContext Timing-Probleme, wenn Fenster minimiert wird

Meine Version, verfügbar unter this plunker, ist eine sehr vereinfachte Version des Originals, hergestellt von Chris Wilson und erhältlich here. Damit meine Arbeit funktioniert, da sie eine tatsächliche Audiodatei verwendet und keine Klänge über einen Oszillator synthetisiert, müssen Sie den Plocker und this audio file herunterladen und in den Stammordner stellen (es ist ein Metronom-Tick-Ton, aber Sie könnte jeden Ton verwenden, den Sie wollen).

Es funktioniert wie ein Zauber - wenn es nicht die Tatsache wäre, dass, wenn der Benutzer das Fenster minimiert, das ansonsten sehr genaue Metronom sofort und schrecklich schluckt. Ich verstehe wirklich nicht, was das Problem ist, hier.

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

Antwort

3

Ja, ist dies, weil die Browser setTimeout und setInterval auf einmal pro Sekunde drosseln, wenn das Fenster den Fokus verliert. (Dies wurde getan, um CPU/Stromverbrauch aufgrund Entwickler zu umgehen mit setTimeout/setInterval für visuelle Animationen und Pausieren nicht die Animation, wenn die Registerkarte den Fokus verloren.)

Es gibt zwei Möglichkeiten, um dieses:

1) erhöhen Sie die "Vorausschau" (in Ihrem Beispiel 0,1 Sekunden) auf mehr als eine Sekunde - wie 1,1 s. Leider würde dies bedeuten, dass Sie die Änderungen nicht ändern können (z. B. Stoppen der Wiedergabe oder Ändern des Tempos), ohne dass sich die Änderung um mehr als eine Sekunde verzögern würde. Sie möchten diesen Wert wahrscheinlich nur erhöhen, wenn das Blur-Ereignis im Fenster ausgelöst wurde, und ihn wieder auf 0,1 zurücksetzen, wenn das Fensterfokusereignis ausgelöst wurde. Immer noch nicht ideal.

2) Umgehen Sie die Drosselung. :) Es stellt sich heraus, dass Sie dies tun können, da setTimeout/setInterval in Web Workers NICHT gedrosselt wird! (Dieser Ansatz wurde ursprünglich von jemandem im Kommentar-Thread meines Originalartikels unter http://www.html5rocks.com/en/tutorials/audio/scheduling/#disqus_thread vorgeschlagen.) Ich habe dies für den Metronom-Code in https://github.com/cwilso/metronome implementiert: werfen Sie einen Blick auf die js/metronome.js und js/metronomeworker.js. Der Worker behält im Grunde nur den Timer bei und leitet eine Nachricht zurück zum Hauptthread; werfen Sie einen Blick auf https://github.com/cwilso/metronome/blob/master/js/metronome.js#L153, insbesondere, um zu sehen, wie es gestartet ist. Sie könnten diesen Codefragment ändern und metronomeworker.js unverändert verwenden, um dies zu beheben.