Files
maestro/ui/public/transcription-pcm-worklet.js
T
oss-sync 57702b4f34
CI / build-and-test (push) Canceled after 0s
sync: update from private repo (2336949a)
2026-09-17 11:29:31 +00:00

57 lines
1.9 KiB
JavaScript

/* Stateful box-filter resampling: phase and integration survive render quanta. */
class TranscriptionPCM extends AudioWorkletProcessor {
constructor() {
super();
this.ratio = sampleRate / 16000;
this.weight = 0;
this.sum = 0;
this.samples = [];
this.stopped = false;
this.port.onmessage = ({ data }) => {
if (data.type === 'flush') {
this.stopped = true;
if (this.weight > 0) this.samples.push(this.sum / this.weight);
this.emit();
this.port.postMessage({ type: 'flushed' });
}
};
}
emit() {
if (!this.samples.length) return;
const buffer = new ArrayBuffer(this.samples.length * 2);
const view = new DataView(buffer);
let energy = 0;
this.samples.forEach((value, index) => {
const sample = Math.max(-1, Math.min(1, value));
view.setInt16(index * 2, Math.round(sample * (sample < 0 ? 32768 : 32767)), true);
energy += sample * sample;
});
this.port.postMessage({ type: 'pcm', buffer, level: Math.sqrt(energy / this.samples.length) }, [buffer]);
this.samples = [];
}
process(inputs) {
if (this.stopped) return false;
const channels = inputs[0];
if (!channels?.length) return true;
for (let i = 0; i < channels[0].length; i++) {
let value = 0;
for (const channel of channels) value += channel[i] / channels.length;
let remaining = 1;
while (remaining > 1e-9) {
const take = Math.min(remaining, this.ratio - this.weight);
this.sum += value * take;
this.weight += take;
remaining -= take;
if (this.weight >= this.ratio - 1e-9) {
this.samples.push(this.sum / this.ratio);
this.sum = 0;
this.weight = 0;
if (this.samples.length >= 2400) this.emit();
}
}
}
return true;
}
}
registerProcessor('transcription-pcm', TranscriptionPCM);