fix: ScriptProcessorNode fallback + worklet process() logging

- ScriptProcessorNode fallback khi AudioWorkletNode fails
- Render trực tiếp trong onaudioprocess callback, không cần setInterval
- Worklet log peak + queue depth mỗi 50 process() calls
- Log audioCtx state + sampleRate khi init
This commit is contained in:
2026-07-27 15:09:47 +07:00
parent 4ca6e7c6ad
commit 4d2da5a272
2 changed files with 50 additions and 5 deletions
+40 -5
View File
@@ -66,10 +66,15 @@
_audioCtx = audioContext;
if (_audioCtx.state === 'suspended') await _audioCtx.resume();
console.log("[SonicSF] AudioCtx state:", _audioCtx.state, "sampleRate:", _audioCtx.sampleRate);
var _useScriptNode = false;
try {
await _audioCtx.audioWorklet.addModule('/static/js/worklets/fluidsynth-bridge.js');
console.log("[SonicSF] Worklet registered OK");
} catch (e) {
console.warn("[SonicSF] Worklet reg failed:", e);
console.warn("[SonicSF] Worklet reg failed, fallback ScriptProcessorNode:", e);
_useScriptNode = true;
}
console.log("[SonicSF] Initializing FluidSynth WASM Engine...");
@@ -106,13 +111,43 @@
try { _fluidModule.FS.mkdir('/soundfonts'); } catch (e) {}
_workletNode = new AudioWorkletNode(_audioCtx, 'fluidsynth-bridge');
_leftBufPtr = _fluidModule._malloc(RENDER_BLOCK * 4);
_rightBufPtr = _fluidModule._malloc(RENDER_BLOCK * 4);
_workletNode.connect(_audioCtx.destination);
_startRenderLoop();
if (!_useScriptNode) {
try {
_workletNode = new AudioWorkletNode(_audioCtx, 'fluidsynth-bridge');
_workletNode.connect(_audioCtx.destination);
console.log("[SonicSF] AudioWorklet node connected");
_startRenderLoop();
} catch (e) {
console.warn("[SonicSF] AudioWorkletNode failed:", e);
_useScriptNode = true;
}
}
if (_useScriptNode) {
var spBufSz = 2048;
var spn = _audioCtx.createScriptProcessor(spBufSz, 0, 2);
var lp = _fluidModule._malloc(spBufSz * 4);
var rp = _fluidModule._malloc(spBufSz * 4);
spn.onaudioprocess = function (e) {
var left = e.outputBuffer.getChannelData(0);
var right = e.outputBuffer.getChannelData(1);
var sz = left.length;
try {
_fluidModule._fluid_synth_write_float(_synthPtr, sz, lp, 0, 1, rp, 0, 1);
var hf = _fluidModule.HEAPF32;
var lpb = lp >> 2, rpb = rp >> 2;
for (var si = 0; si < sz; si++) {
left[si] = hf[lpb + si];
right[si] = hf[rpb + si];
}
} catch (er) {}
};
spn.connect(_audioCtx.destination);
_workletNode = spn;
console.log("[SonicSF] ScriptProcessorNode fallback active (buf:", spBufSz, ")");
}
_initialized = true;
console.log("[SonicSF] FluidSynth WASM Engine initialized.");
@@ -3,6 +3,7 @@ class FluidSynthBridge extends AudioWorkletProcessor {
super();
this.leftQ = [];
this.rightQ = [];
this.called = 0;
this.port.onmessage = (e) => {
const d = e.data;
if (d.type === 'PCM') {
@@ -15,6 +16,7 @@ class FluidSynthBridge extends AudioWorkletProcessor {
process(inputs, outputs) {
const out = outputs[0];
if (!out) return true;
this.called++;
const len = out[0].length;
const qL = this.leftQ;
const qR = this.rightQ;
@@ -28,6 +30,14 @@ class FluidSynthBridge extends AudioWorkletProcessor {
if (si >= qL[fi].length) { fi++; si = 0; }
}
if (fi > 0) { this.leftQ.splice(0, fi); this.rightQ.splice(0, fi); }
if (this.called % 50 === 0) {
var pk = 0;
for (var j = 0; j < len; j++) {
var v = out[0][j] > 0 ? out[0][j] : -out[0][j];
if (v > pk) pk = v;
}
if (pk > 0) console.log('[FluidSynth:bridge] process #' + this.called + ' peak:' + pk.toFixed(6) + ' q:' + qL.length);
}
return true;
}
}