77 lines
2.7 KiB
JavaScript
77 lines
2.7 KiB
JavaScript
// sf-fx-realtime.js — AudioWorkletProcessor nối WebAudio → SHM FX engine.
|
|
// process() gom 128-sample quantum thành block 256 stereo float32 (khớp
|
|
// FXRT_BLOCK trong FxRealtimeIPC.h) → postMessage cho main thread gửi WS;
|
|
// nhận block đã xử lý từ main thread → queue → phát ra output. Queue rỗng →
|
|
// zero fill (WS chưa kịp round-trip).
|
|
//
|
|
// Latency ~2 block; backlog > 32 block (~190ms) → drop block cũ nhất. Cap cao
|
|
// hấp thụ jitter main thread (rAF renderFrame nặng khi mở MASTERING PANEL) mà
|
|
// không drop. ponytail: thay drop bằng adaptive stretch khi cần chất lượng cao.
|
|
class SfFxRealtimeProcessor extends AudioWorkletProcessor {
|
|
constructor() {
|
|
super();
|
|
this.BLOCK = 256; // FXRT_BLOCK
|
|
this.inL = new Float32Array(this.BLOCK);
|
|
this.inR = new Float32Array(this.BLOCK);
|
|
this.inCount = 0;
|
|
this.outQueue = []; // [{l: Float32Array, r: Float32Array}]
|
|
this.outPos = 0;
|
|
this.port.onmessage = (e) => {
|
|
const d = e.data;
|
|
if (d && d.type === 'set_param') { this.port.postMessage(d); return; }
|
|
if (!d || d.type !== 'out' || !d.l || !d.r) return;
|
|
this.outQueue.push({ l: d.l, r: d.r });
|
|
while (this.outQueue.length > 32) this.outQueue.shift();
|
|
};
|
|
}
|
|
process(inputs, outputs) {
|
|
const input = inputs[0];
|
|
const output = outputs[0];
|
|
const n = output[0] ? output[0].length : 128;
|
|
const outL = output[0];
|
|
const outR = output[1];
|
|
|
|
// Góp input thành block 256 → gửi main thread (transferable buffer).
|
|
if (input && input[0]) {
|
|
const inL = input[0];
|
|
const inR = input[1] || input[0];
|
|
for (let i = 0; i < n; i++) {
|
|
if (this.inCount < this.BLOCK) {
|
|
this.inL[this.inCount] = inL[i];
|
|
this.inR[this.inCount] = inR[i];
|
|
}
|
|
this.inCount++;
|
|
if (this.inCount >= this.BLOCK) {
|
|
const inter = new Float32Array(this.BLOCK * 2);
|
|
for (let j = 0; j < this.BLOCK; j++) {
|
|
inter[j * 2] = this.inL[j];
|
|
inter[j * 2 + 1] = this.inR[j];
|
|
}
|
|
this.port.postMessage({ type: 'in', data: inter.buffer }, [inter.buffer]);
|
|
this.inCount = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Phát output từ queue; rỗng → zero.
|
|
for (let i = 0; i < n; i++) {
|
|
if (this.outQueue.length === 0) {
|
|
outL[i] = 0;
|
|
if (outR) outR[i] = 0;
|
|
continue;
|
|
}
|
|
const blk = this.outQueue[0];
|
|
outL[i] = blk.l[this.outPos];
|
|
if (outR) outR[i] = blk.r[this.outPos];
|
|
this.outPos++;
|
|
if (this.outPos >= this.BLOCK) {
|
|
this.outQueue.shift();
|
|
this.outPos = 0;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
registerProcessor('sf-fx-realtime', SfFxRealtimeProcessor);
|