0
votes

I am creating a complex metronome app using Ionic and Web Audio API.

At certain points, the metronome could be playing 10+ 'beats' a second.

This essentially calls this function 10 times+ a second.

function playSound(e, name) {

    var buffer = audioBuffers[name];
    var source = audioContext.createBufferSource();
    var gain = audioContext.createGain();

    source.connect(gain);
    gain.connect(audioContext.destination);
    gain.gain.value = 1;
    source.buffer = buffer;
    source.connect(audioContext.destination);

    sched.nextTick(e.playbackTime, () => {
        source.start(0);
    });

}

The user can choose multiple samples, so I fetch them all first once and store the buffer in an array to improve performance instead of making a XMLHttpRequest() every time.

The issue is that when playing at these higher rates the playback gets odd and sometimes goes out of sync. I am using https://github.com/mohayonao/web-audio-scheduler which works lovely so I know its not a timing issue.

If I swap out the sample playback for a basic oscillator:

function oscillator(e) {

    const t0 = e.playbackTime;
    const t1 = t0 + 0.4;
    const osc = audioContext.createOscillator();
    const amp = audioContext.createGain();

    osc.frequency.value = 1000;
    osc.start(t0);
    osc.stop(t1);
    osc.connect(amp);

    amp.gain.setValueAtTime(1, t0);
    amp.gain.exponentialRampToValueAtTime(1e-6, t1);
    amp.connect(masterGain);

    sched.nextTick(t1, () => {
        osc.disconnect();
        amp.disconnect();
    });
}

Performance is fine no matter what tempo. Is there any improvements I can make to the sample playback to help improve performance?

2

2 Answers

0
votes

Your first function just uses source.start(0); which makes me think you're relying on setTimeout or setInterval to "schedule" the audio. The second one properly uses the Web Audio scheduler ("start(t0)"). See "A Tale of Two Clocks" for more: https://www.html5rocks.com/en/tutorials/audio/scheduling/.

0
votes

What cwilso says is right. Use AudioContext.CurrentTime and +/- to determine the next time for setTimeout manually and not with that scheduler library. Then everything should be fine.