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
setTimeout
orsetInterval
, 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;
};
}