FIX: sửa lỗi không load soundfont trên window

This commit is contained in:
2026-08-10 09:29:05 +07:00
parent 250b94cd88
commit 85ac80bb4f
4 changed files with 91 additions and 10 deletions
+42
View File
@@ -174,9 +174,51 @@ async def list_plugins(current_user: dict = Depends(get_current_user)):
for v in extra:
by_id.setdefault(v["id"], v)
avail["vst_instruments"] = list(by_id.values())
# Tương tự cho SOUNDFONT: gộp .sf2/.sf3 từ plugin_dirs user — nếu không,
# nút Synth không liệt kê instrument của soundfont trong thư mục user thêm.
sf_by_id = {s["id"]: s for s in avail["soundfonts"]}
for s in _scan_soundfonts_in_dirs(d["plugin_dirs"]):
sf_by_id.setdefault(s["id"], s)
avail["soundfonts"] = list(sf_by_id.values())
return avail
def _scan_soundfonts_in_dirs(dirs: list) -> list:
"""Walk các thư mục (plugin_dirs user) → danh sách soundfont .sf2/.sf3
(id = tên file; name từ .meta nếu có — cùng format PluginManager)."""
found = {}
for d in dirs:
if not d or not os.path.isdir(d):
continue
for root, dirs2, files in os.walk(d):
for f in files:
low = f.lower()
if not (low.endswith(".sf2") or low.endswith(".sf3")):
continue
base_id = os.path.splitext(f)[0]
if base_id in found:
continue
meta = {}
mp = os.path.join(root, os.path.splitext(f)[0] + ".meta")
if os.path.isfile(mp):
try:
with open(mp, "r", encoding="utf-8") as mf:
meta = json.load(mf)
except Exception:
meta = {}
name = meta.get("original_name", f) if meta else f
found[base_id] = {
"id": base_id,
"name": name,
"file": f,
"display": os.path.splitext(name)[0][:40],
"source": "user",
}
# Không walk sâu thêm (soundfont thường đặt ngay trong thư mục khai báo)
dirs2[:] = []
return list(found.values())
def _scan_vst_in_dirs(dirs: list) -> list:
"""Walk các thư mục (plugin_dirs user) → danh sách VST giống /scan:
file .vst3/.dll/.so + FOLDER tên X.vst3 (Windows VST3 = folder chứa
+35 -5
View File
@@ -5337,11 +5337,16 @@ const PluginManagerModal = ({ isOpen, onClose, pluginsData, onInsertInstrument }
};
const confirmPluginDir = () => {
const p = pmPicker && pmPicker.path;
if (p && !pmDirs.includes(p)) setPmDirs(prev => [...prev, p]);
if (p && !pmDirs.includes(p)) {
setPmDirs(prev => [...prev, p]);
// T ĐNG lưu + scan nút Synth có ngay danh sách instrument
clearTimeout(window.__pmAutoScanTimer);
window.__pmAutoScanTimer = setTimeout(() => { saveAndScanDirs(); }, 600);
}
setPmPicker(null);
};
const pickPluginFolder = async () => {
const addDir = (p) => { if (p && !pmDirs.includes(p)) setPmDirs(prev => [...prev, p]); };
const addDir = (p) => { if (p && !pmDirs.includes(p)) { setPmDirs(prev => [...prev, p]); clearTimeout(window.__pmAutoScanTimer); window.__pmAutoScanTimer = setTimeout(() => { saveAndScanDirs(); }, 600); } };
try {
// 1) NATIVE dialog qua engine (Tauri bridge IFileDialog/Explorer;
// fallback PowerShell/zenity/osascript) UI chy localhost:8000 nên
@@ -5372,6 +5377,9 @@ const PluginManagerModal = ({ isOpen, onClose, pluginsData, onInsertInstrument }
};
const removePluginDir = (dir) => {
setPmDirs(prev => prev.filter(d => d !== dir));
// T đng lưu + scan li sau khi xóa thư mc
clearTimeout(window.__pmAutoScanTimer);
window.__pmAutoScanTimer = setTimeout(() => { saveAndScanDirs(); }, 600);
};
// Expand 1 soundfont đc danh sách instrument (bank/program/name) bên trong
// qua API soundfont-instruments/{id} hin th nút "Chèn vào Synth".
@@ -5610,7 +5618,14 @@ const PluginManagerModal = ({ isOpen, onClose, pluginsData, onInsertInstrument }
React.createElement('div', { className: 'text-[10px] text-zinc-500' }, v.type || 'VST3')
)
),
React.createElement('span', { className: 'text-[10px] bg-violet-950/40 text-violet-400 px-2 py-0.5 rounded-full border border-violet-800/30' }, v.type || 'VST3')
React.createElement('div', { className: 'flex items-center gap-2' },
(window.SonicRuntime && window.SonicRuntime.capabilities && window.SonicRuntime.capabilities.features && window.SonicRuntime.capabilities.features.carla_local) && React.createElement('button', {
onClick: (e) => { e.stopPropagation(); window.SonicAPI.openInCarla(v.id).then(function (r) { if (r && r.success) showToast('Đã mở Carla với ' + (v.name || v.id), 'success'); }).catch(function (err) { showToast('Lỗi mở Carla: ' + (err.message || err), 'error'); }); },
className: 'text-[10px] bg-teal-800 hover:bg-teal-700 text-white px-2 py-1 rounded transition shrink-0',
title: 'Mở trong Carla (native GUI)'
}, '🎛 Carla'),
React.createElement('span', { className: 'text-[10px] bg-violet-950/40 text-violet-400 px-2 py-0.5 rounded-full border border-violet-800/30' }, v.type || 'VST3')
)
)
)
) :
@@ -5760,7 +5775,12 @@ const PluginManagerModal = ({ isOpen, onClose, pluginsData, onInsertInstrument }
React.createElement('div', { key: 'sv_' + i, className: 'flex items-center gap-2 text-[11px] text-zinc-300' },
React.createElement('span', { className: 'w-16 shrink-0 text-zinc-500 font-mono text-[9px] truncate' }, v.type || 'VST'),
React.createElement('span', { className: 'truncate' }, v.name),
React.createElement('span', { className: 'text-[9px] text-zinc-600 font-mono truncate ml-auto' }, v.dir)
React.createElement('span', { className: 'text-[9px] text-zinc-600 font-mono truncate ml-auto' }, v.dir),
(window.SonicRuntime && window.SonicRuntime.capabilities && window.SonicRuntime.capabilities.features && window.SonicRuntime.capabilities.features.carla_local) && React.createElement('button', {
onClick: () => { window.SonicAPI.openInCarla(null, v.path).then(function (r) { if (r && r.success) showToast('Đã mở Carla với ' + v.name, 'success'); }).catch(function (err) { showToast('Lỗi mở Carla: ' + (err.message || err), 'error'); }); },
className: 'text-[9px] bg-teal-800 hover:bg-teal-700 text-white px-1.5 py-0.5 rounded transition shrink-0',
title: 'Mở trong Carla (native GUI)'
}, '🎛')
)
),
React.createElement('div', { className: 'text-[10px] font-bold text-amber-300 uppercase flex items-center gap-1 mt-2' },
@@ -30051,7 +30071,17 @@ STRICT CONSTRAINTS:
(instrumentSelectorData?.vst_instruments?.length > 0) && /*#__PURE__*/React.createElement("div", { className: "mt-3 text-[10px] text-zinc-500 uppercase font-bold px-1 flex items-center gap-1" }, /*#__PURE__*/React.createElement("i", { "data-lucide": "cpu", className: "w-3 h-3 text-violet-400" }), "VST Instruments"),
(instrumentSelectorData?.vst_instruments || []).map(v => /*#__PURE__*/React.createElement("button", {
key: 'vst_modal_' + (v.id || v.name),
onClick: () => { setTrackInstrumentWithUndo(instrumentSelectorTrackId, v.id, v.name || v.id); closeInstrumentSelector(); },
onClick: () => {
setTrackInstrumentWithUndo(instrumentSelectorTrackId, v.id, v.name || v.id);
closeInstrumentSelector();
// T ĐNG m Carla vi VSTi va chn (desktop + Carla local)
// Carla load sn plugin + keyboard o đ preview realtime.
if (window.SonicRuntime && window.SonicRuntime.capabilities && window.SonicRuntime.capabilities.features && window.SonicRuntime.capabilities.features.carla_local) {
window.SonicAPI.openInCarla(v.id).then(function (r) {
if (r && r.success) showToast('Đã mở Carla với ' + (v.name || v.id) + ' — chọn preset, bấm keyboard để preview', 'success');
}).catch(function (err) { showToast('Lỗi mở Carla: ' + (err.message || err), 'error'); });
}
},
className: "w-full text-left px-3 py-2 text-sm rounded bg-zinc-800 hover:bg-violet-800 text-zinc-300 flex items-center justify-between gap-2"
}, /*#__PURE__*/React.createElement("span", { className: "truncate" }, v.name || v.id), /*#__PURE__*/React.createElement("span", { className: "text-[9px] text-cyan-400 shrink-0" }, v.type || "VST")))
),
File diff suppressed because one or more lines are too long