// The room's audio output: the mix (computed on the page by wai-live-web's integer mixer, // live-compose ยง6) arrives as blocks of interleaved stereo 16-bit samples, and this // processor plays them from a bounded queue. It mixes nothing itself: an AudioWorklet's // scope has no text decoder for the wasm glue, so the mixer runs where the glue does. class RoomMix extends AudioWorkletProcessor { constructor() { super(); this.queue = []; this.at = 0; this.played = 0; this.underruns = 0; this.peak = 0; this.port.onmessage = (e) => { if (e.data && e.data.pcm) { this.queue.push(e.data.pcm); // At most half a second queued: the oldest goes first. while (this.queue.length > 25) this.queue.shift(); } }; this.tick = 0; } process(_inputs, outputs) { const out = outputs[0]; const l = out[0], r = out[1] || out[0]; for (let i = 0; i < l.length; i++) { let block = this.queue[0]; if (!block) { l[i] = 0; r[i] = 0; if (i === 0) this.underruns++; continue; } const sl = block[this.at] / 32768, sr = block[this.at + 1] / 32768; l[i] = sl; r[i] = sr; const a = Math.abs(sl) > Math.abs(sr) ? Math.abs(sl) : Math.abs(sr); if (a > this.peak) this.peak = a; this.at += 2; this.played++; if (this.at >= block.length) { this.queue.shift(); this.at = 0; } } if (++this.tick % 100 === 0) this.port.postMessage({ played: this.played, underruns: this.underruns, peak: this.peak }); return true; } } registerProcessor("room-mix", RoomMix);