/** * Continuous mic capture for streaming dictation. * * The AudioContext is created at 16 kHz so no resampling is needed here. Frames * arrive 128 samples at a time (8 ms), which would be ~125 postMessage calls per * second; they are batched to 480 samples (30 ms) instead -- the same frame size * the energy gate measures RMS over, so the gate never has to re-frame a partial * block. */ const BATCH = 480; // 30 ms at 16 kHz class CaptureProcessor extends AudioWorkletProcessor { constructor() { super(); this.buf = new Float32Array(BATCH); this.at = 0; } process(inputs) { const channel = inputs[0]?.[0]; if (!channel) return true; for (let i = 0; i < channel.length; i++) { this.buf[this.at++] = channel[i]; if (this.at === BATCH) { // Transfer a copy: `buf` is reused, and the render quantum's own // input buffer is recycled by the engine after process() returns. const out = this.buf.slice(); this.port.postMessage(out, [out.buffer]); this.at = 0; } } return true; } } registerProcessor('ctc-capture', CaptureProcessor);