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;
|
_audioCtx = audioContext;
|
||||||
if (_audioCtx.state === 'suspended') await _audioCtx.resume();
|
if (_audioCtx.state === 'suspended') await _audioCtx.resume();
|
||||||
|
|
||||||
|
console.log("[SonicSF] AudioCtx state:", _audioCtx.state, "sampleRate:", _audioCtx.sampleRate);
|
||||||
|
|
||||||
|
var _useScriptNode = false;
|
||||||
try {
|
try {
|
||||||
await _audioCtx.audioWorklet.addModule('/static/js/worklets/fluidsynth-bridge.js');
|
await _audioCtx.audioWorklet.addModule('/static/js/worklets/fluidsynth-bridge.js');
|
||||||
|
console.log("[SonicSF] Worklet registered OK");
|
||||||
} catch (e) {
|
} 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...");
|
console.log("[SonicSF] Initializing FluidSynth WASM Engine...");
|
||||||
@@ -106,13 +111,43 @@
|
|||||||
|
|
||||||
try { _fluidModule.FS.mkdir('/soundfonts'); } catch (e) {}
|
try { _fluidModule.FS.mkdir('/soundfonts'); } catch (e) {}
|
||||||
|
|
||||||
_workletNode = new AudioWorkletNode(_audioCtx, 'fluidsynth-bridge');
|
|
||||||
|
|
||||||
_leftBufPtr = _fluidModule._malloc(RENDER_BLOCK * 4);
|
_leftBufPtr = _fluidModule._malloc(RENDER_BLOCK * 4);
|
||||||
_rightBufPtr = _fluidModule._malloc(RENDER_BLOCK * 4);
|
_rightBufPtr = _fluidModule._malloc(RENDER_BLOCK * 4);
|
||||||
|
|
||||||
_workletNode.connect(_audioCtx.destination);
|
if (!_useScriptNode) {
|
||||||
_startRenderLoop();
|
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;
|
_initialized = true;
|
||||||
console.log("[SonicSF] FluidSynth WASM Engine initialized.");
|
console.log("[SonicSF] FluidSynth WASM Engine initialized.");
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ class FluidSynthBridge extends AudioWorkletProcessor {
|
|||||||
super();
|
super();
|
||||||
this.leftQ = [];
|
this.leftQ = [];
|
||||||
this.rightQ = [];
|
this.rightQ = [];
|
||||||
|
this.called = 0;
|
||||||
this.port.onmessage = (e) => {
|
this.port.onmessage = (e) => {
|
||||||
const d = e.data;
|
const d = e.data;
|
||||||
if (d.type === 'PCM') {
|
if (d.type === 'PCM') {
|
||||||
@@ -15,6 +16,7 @@ class FluidSynthBridge extends AudioWorkletProcessor {
|
|||||||
process(inputs, outputs) {
|
process(inputs, outputs) {
|
||||||
const out = outputs[0];
|
const out = outputs[0];
|
||||||
if (!out) return true;
|
if (!out) return true;
|
||||||
|
this.called++;
|
||||||
const len = out[0].length;
|
const len = out[0].length;
|
||||||
const qL = this.leftQ;
|
const qL = this.leftQ;
|
||||||
const qR = this.rightQ;
|
const qR = this.rightQ;
|
||||||
@@ -28,6 +30,14 @@ class FluidSynthBridge extends AudioWorkletProcessor {
|
|||||||
if (si >= qL[fi].length) { fi++; si = 0; }
|
if (si >= qL[fi].length) { fi++; si = 0; }
|
||||||
}
|
}
|
||||||
if (fi > 0) { this.leftQ.splice(0, fi); this.rightQ.splice(0, fi); }
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user