/** A square-wave melody and bass, like a General MIDI file on a cheap sound card. */
const btn = root.querySelector<HTMLButtonElement>('.dk__midi')!
let ctx: AudioContext | null = null
let timer = 0
const melody = [72, 76, 79, 76, 81, 79, 76, 72, 74, 77, 81, 77, 79, 0, 79, 0, 72, 76, 79, 84, 83, 79, 76, 74, 72, 74, 76, 72, 67, 0, 72, 0]
const bass = [48, 48, 45, 45, 41, 41, 43, 43]
const hz = (n: number) => 440 * 2 ** ((n - 69) / 12)
function note(freq: number, at: number, len: number, type: OscillatorType, vol: number) {
const o = ctx!.createOscillator()
const g = ctx!.createGain()
o.type = type
o.frequency.value = freq
g.gain.setValueAtTime(vol, at)
g.gain.exponentialRampToValueAtTime(0.001, at + len)
o.connect(g).connect(ctx!.destination)
o.start(at)
o.stop(at + len)
}
function play() {
ctx ??= new AudioContext()
void ctx.resume()
const step = 0.16
let t = ctx.currentTime + 0.05
let i = 0
const schedule = () => {
while (t < ctx!.currentTime + 0.5) {
const m = melody[i % melody.length]
if (m) note(hz(m), t, step * 0.9, 'square', 0.05)
if (i % 4 === 0) note(hz(bass[(i / 4) % bass.length]), t, step * 3.5, 'triangle', 0.12)
t += step
i++
}
}
schedule()
timer = window.setInterval(schedule, 100)
}
function stop() {
clearInterval(timer)
void ctx?.suspend()
}