FIX: Carla sử dụng bridge

This commit is contained in:
2026-08-10 07:57:26 +07:00
parent fbaac1f673
commit aa32272f36
17 changed files with 1372 additions and 34 deletions
+67
View File
@@ -408,3 +408,70 @@ class DecentSamplerManager:
os.chdir(cwd_before)
return plugin
# ── Preset bridge (Carla ↔ pedalboard) ─────────────────────────────────────
# Carla (chạy ngoài, user tự cài — GPL-2.0+ nên app KHÔNG bundle/nhúng) dùng
# để mở native GUI VSTi + xuất file preset (.vstpreset từ nút Save của plugin).
# File preset nằm trong thư viện storage/presets (upload qua web UI hoặc picker
# local trên Windows) → render_engine tải qua apply_preset_to_plugin() khi render.
PRESET_EXTENSIONS = (".vstpreset", ".fxp", ".fxb", ".dspreset")
def preset_library_dir() -> str:
from app.config import settings as _st
d = os.path.join(_st.STORAGE_DIR, "presets")
try:
os.makedirs(d, exist_ok=True)
except Exception:
pass
return d
def resolve_preset_path(preset_id_or_path: str) -> str:
"""preset_id (tên file trong thư viện) hoặc đường dẫn tuyệt đối → path.
Trả '' nếu không tìm thấy. Chống path traversal: chỉ chấp nhận tên file
(không chứa separator) hoặc đường dẫn tuyệt đối tồn tại."""
if not preset_id_or_path:
return ""
p = preset_id_or_path
# Đường dẫn tuyệt đối / tương đối tồn tại → dùng thẳng
if os.path.isfile(p):
return p
# id dạng tên file trong thư viện (uuid + ext)
if os.path.basename(p) == p:
cand = os.path.join(preset_library_dir(), p)
if os.path.isfile(cand):
return cand
# Không có ext → quét theo prefix (uuid.idx → uuid.vstpreset)
try:
for f in os.listdir(preset_library_dir()):
if f.lower().endswith(PRESET_EXTENSIONS) and f.startswith(p + "."):
return os.path.join(preset_library_dir(), f)
except Exception:
pass
return ""
def apply_preset_to_plugin(plugin, preset_id=None, preset_path=None, preset_data_b64=None) -> bool:
"""Gán preset lên plugin pedalboard: bytes nhúng (base64 .vstpreset) ưu
tiên, sau đó preset_id (thư viện), sau preset_path (file). Trả True nếu
áp dụng được; KHÔNG raise (render engine chỉ log warning)."""
if plugin is None:
return False
try:
if preset_data_b64:
import base64
raw = base64.b64decode(preset_data_b64)
if hasattr(plugin, "preset_data"):
plugin.preset_data = raw # bytes dạng .vstpreset (VST3)
return True
p = resolve_preset_path(preset_id or "") or resolve_preset_path(preset_path or "")
if p and hasattr(plugin, "load_preset"):
plugin.load_preset(p) # .vstpreset (VST3) / .dspreset (DecentSampler)
return True
except Exception:
return False
return False