Links
- Specification
- https://www.w3.org/TR/webaudio/
- MDN
- https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
Internal links
Miscellaneous links
- A tale of two clocks - Shows you how to schedule sounds, like a metronome (do not use
setTimeoutorsetInterval, even though some LLMs will tell you otherwise)
Audio scheduling
These are basically my notes of Chris Wilson’s excellent web.dev article on audio scheduling (also see his demo metronome).
I asked Kagi’s FastGPT to make a simple periodic beep, but it used setInterval, which you don’t want to do.
What you do want to do is have a periodic setTimeout that schedules upcoming events with overlaps.
Like, make a setTimeout call for 25ms, but have it schedule sounds up to the next 100ms.
In the article, there are 3 different functions.
One that’s called by setInterval, one that schedules the next note, and one that calculates the time of the next note.
They all work by modifying global variables.
I actually think you could use a generator here (and it’s one of the few places I’ve ever actually used a generator).
Something like:
function* noteGenerator(start, scheduleahead) {
const { audioCtx, finish } = getAudioCtx();
const notelength = 0.05;
var nextnotetime = start;
var currentbeat = 0;
while (true) {
let addednotes = 0;
while (nextnotetime < audioCtx.currentTime + scheduleahead) {
// Add a note
const oscillatorNode = new OscillatorNode(audioCtx);
oscillatorNode.connect(finish);
oscillatorNode.frequency.value =
( currentbeat % timetop ) === 0 ? 220.0
: ( currentbeat % 4) === 0 ? 880.0
: 440.0;
oscillatorNode.start(nextnotetime);
oscillatorNode.stop(nextnotetime + notelength);
addednotes++;
// Find next time for note
var secondsperbeat = 60.0 / tempo;
nextnotetime += (4.0 / timebottom) * secondsperbeat;
currentbeat++;
currentbeat %= timetop;
}
if (addednotes) {
// console.log(`${addednotes} notes were added`);
}
yield;
};
}