fix: clean sfload with _allocCStr helper + printErr debug + verbose FluidSynth

- Thay MEMFS path từ /soundfonts/ → root / (tránh lỗi thư mục)
- Helper _allocCStr + _tryLoadSFL: unique filename, manual C string alloc, cleanup
- Thêm printErr callback để capture FluidSynth C stderr log
- Bật synth.verbose=1, synth.ladspa.active=0
- Loại bỏ _fluid_synth_get_sfont_count (không export)
- Log buffer magic bytes (RIFF/sfbk) để verify file valid
This commit is contained in:
2026-07-27 14:56:07 +07:00
parent 6fe0cd8d61
commit a887db587f
+36 -26
View File
@@ -81,7 +81,10 @@
} }
return path; 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) { if (!_fluidModule || !_fluidModule._new_fluid_settings) {
@@ -89,9 +92,13 @@
} }
_settingsPtr = _fluidModule._new_fluid_settings(); _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.gain", 0.5);
_fluidModule._fluid_settings_setnum(_settingsPtr, "synth.polyphony", 256); _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); _synthPtr = _fluidModule._new_fluid_synth(_settingsPtr);
if (!_synthPtr) throw new Error("Failed to create FluidSynth synthesizer"); if (!_synthPtr) throw new Error("Failed to create FluidSynth synthesizer");
@@ -117,6 +124,26 @@
return _initPromise; 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) { loadSoundFont: async function (sfId) {
if (!_initialized || !_fluidModule) return false; if (!_initialized || !_fluidModule) return false;
if (_currentSfId === sfId) return true; if (_currentSfId === sfId) return true;
@@ -137,31 +164,14 @@
buf = await resp.arrayBuffer(); buf = await resp.arrayBuffer();
if (cache) await cache.saveBuffer(sfId, buf); if (cache) await cache.saveBuffer(sfId, buf);
} }
var ext = '.sf3'; var sfHandle = this._tryLoadSFL(buf, '.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);
if (sfHandle === -1) { if (sfHandle === -1) {
var errPtr = _fluidModule._fluid_synth_error(_synthPtr); console.warn("[SonicSF] sfload .sf3 failed, trying .sf2 for", sfId);
var errMsg = errPtr ? _fluidModule.UTF8ToString(errPtr) : "unknown"; sfHandle = this._tryLoadSFL(buf, '.sf2');
console.warn("[SonicSF] sfload failed for", sfId, "as", ext, "error:", errMsg); }
try { _fluidModule.FS.unlink(virtualPath); } catch (e) {} if (sfHandle === -1) {
ext = '.sf2'; console.error("[SonicSF] FluidSynth failed to parse SoundFont:", sfId);
virtualPath = '/soundfonts/' + sfId + ext; return false;
_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);
} }
_sfHandleMap.set(sfId, sfHandle); _sfHandleMap.set(sfId, sfHandle);
_currentSfId = sfId; _currentSfId = sfId;