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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user