diff --git a/app/static/js/services/soundfontPlayer.js b/app/static/js/services/soundfontPlayer.js index 30190df..c65387d 100644 --- a/app/static/js/services/soundfontPlayer.js +++ b/app/static/js/services/soundfontPlayer.js @@ -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."); diff --git a/app/static/js/worklets/fluidsynth-bridge.js b/app/static/js/worklets/fluidsynth-bridge.js index 9cb24fe..088dfd8 100644 --- a/app/static/js/worklets/fluidsynth-bridge.js +++ b/app/static/js/worklets/fluidsynth-bridge.js @@ -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; } }