@@ -0,0 +1,47 @@
|
||||
class PCM16CaptureProcessor extends AudioWorkletProcessor {
|
||||
constructor(options) {
|
||||
super();
|
||||
this.targetRate = Number(options.processorOptions?.targetSampleRate || 16000);
|
||||
this.frameSamples = Number(options.processorOptions?.frameSamples || 320);
|
||||
this.ratio = sampleRate / this.targetRate;
|
||||
this.source = [];
|
||||
this.position = 0;
|
||||
this.output = [];
|
||||
}
|
||||
|
||||
process(inputs) {
|
||||
const channel = inputs[0]?.[0];
|
||||
if (!channel?.length) return true;
|
||||
for (const sample of channel) this.source.push(sample);
|
||||
while (this.position + this.ratio <= this.source.length) {
|
||||
const start = Math.floor(this.position);
|
||||
const end = Math.max(start + 1, Math.floor(this.position + this.ratio));
|
||||
let sum = 0;
|
||||
for (let index = start; index < end && index < this.source.length; index += 1) sum += this.source[index];
|
||||
this.output.push(sum / Math.max(1, end - start));
|
||||
this.position += this.ratio;
|
||||
if (this.output.length >= this.frameSamples) this.flush();
|
||||
}
|
||||
const consumed = Math.floor(this.position);
|
||||
if (consumed > 0) {
|
||||
this.source.splice(0, consumed);
|
||||
this.position -= consumed;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
flush() {
|
||||
const frame = this.output.splice(0, this.frameSamples);
|
||||
const pcm = new Int16Array(frame.length);
|
||||
let energy = 0;
|
||||
for (let index = 0; index < frame.length; index += 1) {
|
||||
const sample = Math.max(-1, Math.min(1, frame[index]));
|
||||
energy += sample * sample;
|
||||
pcm[index] = sample < 0 ? Math.round(sample * 32768) : Math.round(sample * 32767);
|
||||
}
|
||||
const volume = Math.min(100, Math.round(Math.sqrt(energy / Math.max(1, frame.length)) * 280));
|
||||
this.port.postMessage({ type: "pcm", bytes: pcm.buffer, volume }, [pcm.buffer]);
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor("pcm16-capture", PCM16CaptureProcessor);
|
||||
Reference in New Issue
Block a user