diff options
Diffstat (limited to 'static/mic-worklet.js')
| -rw-r--r-- | static/mic-worklet.js | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/static/mic-worklet.js b/static/mic-worklet.js new file mode 100644 index 0000000..814bf6a --- /dev/null +++ b/static/mic-worklet.js @@ -0,0 +1,60 @@ +// Microphone capture worklet: resamples the context rate to 48 kHz mono and +// posts 20 ms frames (960 Float32 samples) together with their RMS level. +const OUT_RATE = 48000; +const FRAME_SAMPLES = 960; + +class Ts6MicCapture extends AudioWorkletProcessor { + constructor() { + super(); + this.ratio = sampleRate / OUT_RATE; // input samples per output sample + this.t = 0; // fractional read position; -1 refers to `last` + this.last = 0; + this.frame = new Float32Array(FRAME_SAMPLES); + this.offset = 0; + } + + push(sample) { + this.frame[this.offset++] = sample; + if (this.offset < FRAME_SAMPLES) return; + let sum = 0; + for (let i = 0; i < FRAME_SAMPLES; i++) sum += this.frame[i] * this.frame[i]; + const frame = this.frame; + this.frame = new Float32Array(FRAME_SAMPLES); + this.offset = 0; + this.port.postMessage({ samples: frame, rms: Math.sqrt(sum / FRAME_SAMPLES) }, [frame.buffer]); + } + + process(inputs, outputs) { + const output = outputs[0] && outputs[0][0]; + if (output) output.fill(0); + const channels = inputs[0]; + if (!channels || channels.length === 0) return true; + + // Downmix to mono. + let input = channels[0]; + if (channels.length > 1) { + input = new Float32Array(input.length); + for (const ch of channels) for (let i = 0; i < input.length; i++) input[i] += ch[i] / channels.length; + } + + if (this.ratio === 1) { + for (let i = 0; i < input.length; i++) this.push(input[i]); + return true; + } + // Linear interpolation resampler. + const len = input.length; + while (this.t < len - 1) { + const i0 = Math.floor(this.t); + const frac = this.t - i0; + const a = i0 < 0 ? this.last : input[i0]; + const b = input[i0 + 1]; + this.push(a + (b - a) * frac); + this.t += this.ratio; + } + this.t -= len; + this.last = input[len - 1]; + return true; + } +} + +registerProcessor("ts6-mic-capture", Ts6MicCapture); |
