diff --git a/app/static/js/services/soundfontPlayer.js b/app/static/js/services/soundfontPlayer.js index 1e28d13..e1d5839 100644 --- a/app/static/js/services/soundfontPlayer.js +++ b/app/static/js/services/soundfontPlayer.js @@ -81,7 +81,10 @@ } return path; }, - TOTAL_MEMORY: TOTAL_MEMORY + TOTAL_MEMORY: TOTAL_MEMORY, + printErr: function (msg) { + if (msg.indexOf('stderr') === -1) console.warn('[FluidSynth:err]', msg); + } }); if (!_fluidModule || !_fluidModule._new_fluid_settings) { @@ -89,9 +92,13 @@ } _settingsPtr = _fluidModule._new_fluid_settings(); - _fluidModule._fluid_settings_setnum(_settingsPtr, "synth.sample-rate", _audioCtx.sampleRate); + _fluidModule._fluid_settings_setnum(_settingsPtr, "synth.sample-rate", _audioCtx.sampleRate || 44100); _fluidModule._fluid_settings_setnum(_settingsPtr, "synth.gain", 0.5); _fluidModule._fluid_settings_setnum(_settingsPtr, "synth.polyphony", 256); + _fluidModule._fluid_settings_setint(_settingsPtr, "synth.verbose", 1); + _fluidModule._fluid_settings_setint(_settingsPtr, "synth.ladspa.active", 0); + _fluidModule._fluid_settings_setstr(_settingsPtr, "player.timing-source", "audio"); + console.log("[SonicSF] FluidSynth settings configured"); _synthPtr = _fluidModule._new_fluid_synth(_settingsPtr); if (!_synthPtr) throw new Error("Failed to create FluidSynth synthesizer"); @@ -117,6 +124,26 @@ return _initPromise; }, + _allocCStr: function (str) { + var ptr = _fluidModule._malloc(str.length + 1); + for (var i = 0; i < str.length; i++) { + _fluidModule.HEAPU8[ptr + i] = str.charCodeAt(i); + } + _fluidModule.HEAPU8[ptr + str.length] = 0; + return ptr; + }, + + _tryLoadSFL: function (buf, ext) { + var fname = '/' + ext + '_' + Date.now(); + try { _fluidModule.FS.unlink(fname); } catch (e) {} + _fluidModule.FS.writeFile(fname, new Uint8Array(buf)); + var cPath = this._allocCStr(fname); + var handle = _fluidModule._fluid_synth_sfload(_synthPtr, cPath, 1); + _fluidModule._free(cPath); + try { _fluidModule.FS.unlink(fname); } catch (e) {} + return handle; + }, + loadSoundFont: async function (sfId) { if (!_initialized || !_fluidModule) return false; if (_currentSfId === sfId) return true; @@ -137,31 +164,14 @@ buf = await resp.arrayBuffer(); if (cache) await cache.saveBuffer(sfId, buf); } - var ext = '.sf3'; - var virtualPath = '/soundfonts/' + sfId + ext; - console.log("[SonicSF] Writing to MEMFS:", virtualPath, (buf.byteLength / 1024 / 1024).toFixed(2) + 'MB'); - try { _fluidModule.FS.unlink(virtualPath); } catch (e) {} - _fluidModule.FS.writeFile(virtualPath, new Uint8Array(buf)); - var fsSize = 0; - try { fsSize = _fluidModule.FS.stat(virtualPath).size; } catch (e) {} - console.log("[SonicSF] MEMFS stat:", fsSize, "bytes"); - var sfHandle = _fluidModule._fluid_synth_sfload(_synthPtr, virtualPath, 1); + var sfHandle = this._tryLoadSFL(buf, '.sf3'); if (sfHandle === -1) { - var errPtr = _fluidModule._fluid_synth_error(_synthPtr); - var errMsg = errPtr ? _fluidModule.UTF8ToString(errPtr) : "unknown"; - console.warn("[SonicSF] sfload failed for", sfId, "as", ext, "error:", errMsg); - try { _fluidModule.FS.unlink(virtualPath); } catch (e) {} - ext = '.sf2'; - virtualPath = '/soundfonts/' + sfId + ext; - _fluidModule.FS.writeFile(virtualPath, new Uint8Array(buf)); - sfHandle = _fluidModule._fluid_synth_sfload(_synthPtr, virtualPath, 1); - if (sfHandle === -1) { - var errPtr2 = _fluidModule._fluid_synth_error(_synthPtr); - var errMsg2 = errPtr2 ? _fluidModule.UTF8ToString(errPtr2) : "unknown"; - console.error("[SonicSF] FluidSynth failed to parse", sfId, "even as .sf2:", errMsg2); - return false; - } - console.log("[SonicSF] Loaded", sfId, "as .sf2 fallback, handle:", sfHandle); + console.warn("[SonicSF] sfload .sf3 failed, trying .sf2 for", sfId); + sfHandle = this._tryLoadSFL(buf, '.sf2'); + } + if (sfHandle === -1) { + console.error("[SonicSF] FluidSynth failed to parse SoundFont:", sfId); + return false; } _sfHandleMap.set(sfId, sfHandle); _currentSfId = sfId;