3

この記事の指示に従い、Javascript メトロノームを作成しました。Web Audio API を利用し、audioContext.currentTime正確なタイミングを実現するためのコアを備えています。

この plunkerで入手できる私のバージョンは、元のバージョンを非常に単純化したもので、Chris Wilson によって作成され、ここで入手できます。私のものを機能させるには、実際のオーディオ ファイルを使用し、オシレーターを介してサウンドを合成しないため、プランカーとこのオーディオ ファイルをダウンロードしてルート フォルダーに配置する必要があります (これはメトロノームの「ティック」サウンドであり、任意のサウンドを使用できます)。

ユーザーがウィンドウを最小化すると、それ以外の場合は非常に正確なメトロノームが即座にひどく途切れ始めるという事実がなければ、それは魅力のように機能します. ここで何が問題なのか本当にわかりません。

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

1 に答える 1

3

Yeah, this is because the browsers throttle setTimeout and setInterval to once per second when the window loses focus. (This was done to circumvent CPU/power drain due to developers using setTimeout/setInterval for visual animation, and not pausing the animation when the tab lost focus.)

There are two ways around this:

1) increase the "look-ahead" (in your example, 0.1 second) to greater than one second - like, 1.1s. Unfortunately, this would mean you couldn't change things (like stopping the playback, or changing the tempo) without a more-than-one-second lag in the change; so you'd probably want to only increase that value when the blur event was fired on the window, and change it back to 0.1 when the window focus event fired. Still not ideal.

2) Circumvent the throttling. :) It turns out you can do this, because setTimeout/setInterval are NOT throttled in Web Workers! (This approach was originally suggested by someone in the comment thread of my original article at http://www.html5rocks.com/en/tutorials/audio/scheduling/#disqus_thread.) I implemented this for the metronome code in https://github.com/cwilso/metronome: take a look at the js/metronome.js and js/metronomeworker.js. The Worker basically just maintains the timer, and marshals a message back across to the main thread; take a look at https://github.com/cwilso/metronome/blob/master/js/metronome.js#L153, in particular, to see how it's kicked off. You could modify that snippet of code and use metronomeworker.js as-is to fix this.

于 2016-03-25T17:46:48.743 に答える