FIX: sửa lỗi không load soundfont trên window
This commit is contained in:
@@ -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
@@ -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 chạy 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 lại sau khi xóa thư mục
|
||||
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} → hiển 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 với VSTi vừa chọn (desktop + Carla local) —
|
||||
// Carla load sẵn 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
Reference in New Issue
Block a user