Files

72 lines
2.1 KiB
JavaScript

class PCMProcessor extends AudioWorkletProcessor {
constructor(options) {
super();
const opts = options.processorOptions || {};
this.targetRate = opts.targetRate || 16000;
this.inputRate = opts.inputRate || sampleRate || 48000;
this.ratio = this.inputRate / this.targetRate;
this.tail = new Float32Array(0);
this.phase = 0;
}
process(inputs) {
const input = inputs[0]?.[0];
if (!input || input.length === 0) {
return true;
}
let sum = 0;
for (let i = 0; i < input.length; i++) {
const s = Math.max(-1, Math.min(1, input[i]));
sum += s * s;
}
const rms = Math.sqrt(sum / input.length);
const merged = new Float32Array(this.tail.length + input.length);
merged.set(this.tail, 0);
merged.set(input, this.tail.length);
let outFloat;
if (Math.abs(this.ratio - 1) < 0.0001) {
outFloat = merged;
this.tail = new Float32Array(0);
this.phase = 0;
} else {
const available = merged.length - this.phase;
const outLen = Math.floor(available / this.ratio);
if (outLen <= 0) {
this.tail = merged;
this.port.postMessage({ rms, sampleRate: this.targetRate });
return true;
}
outFloat = new Float32Array(outLen);
for (let i = 0; i < outLen; i++) {
const pos = this.phase + i * this.ratio;
const i0 = Math.floor(pos);
const i1 = Math.min(i0 + 1, merged.length - 1);
const frac = pos - i0;
outFloat[i] = merged[i0] * (1 - frac) + merged[i1] * frac;
}
const consumed = this.phase + outLen * this.ratio;
const keepFrom = Math.floor(consumed);
this.phase = consumed - keepFrom;
this.tail = keepFrom < merged.length ? merged.slice(keepFrom) : new Float32Array(0);
}
const int16 = new Int16Array(outFloat.length);
for (let i = 0; i < outFloat.length; i++) {
const s = Math.max(-1, Math.min(1, outFloat[i]));
int16[i] = s < 0 ? s * 32768 : s * 32767;
}
this.port.postMessage({ pcm: int16.buffer, rms, sampleRate: this.targetRate }, [int16.buffer]);
return true;
}
}
registerProcessor('pcm-processor', PCMProcessor);