72 lines
2.1 KiB
JavaScript
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);
|