connect solution into app: VSTi live native (vst3 attach/vst2 bridge) with WASM autosample fallback, VST GUI window (Bug 1), native-first track instrument

This commit is contained in:
2026-08-11 20:35:53 +07:00
parent 916ce1334b
commit 255e8586bc
13 changed files with 538 additions and 98 deletions
+68 -2
View File
@@ -8,6 +8,7 @@ import os
from app.core.native_audio_service import get_service
from app.core.render_engine import _find_sf2_path
from app.core.vst_engine import get_plugin_manager
router = APIRouter()
@@ -47,7 +48,8 @@ class SfNoteOffRequest(BaseModel):
class Vst2EnsureRequest(BaseModel):
track_id: str
plugin_path: str
plugin_path: Optional[str] = None
plugin_id: Optional[str] = None # resolve path server-side
live: bool = True
@@ -63,6 +65,23 @@ class Vst2NoteOffRequest(BaseModel):
channel: int = 0
pitch: int
class Vst3EnsureRequest(BaseModel):
track_id: str
plugin_path: Optional[str] = None
plugin_id: Optional[str] = None # resolve path server-side
live: bool = True
class Vst3NoteRequest(BaseModel):
track_id: str
channel: int = 0
pitch: int
velocity: int = 100
class Vst3NoteOffRequest(BaseModel):
track_id: str
channel: int = 0
pitch: int
class RenderNote(BaseModel):
note: int = 60
@@ -89,6 +108,24 @@ def _svc():
return get_service()
def _resolve_plugin_path(plugin_id: str = None, plugin_path: str = None) -> str:
"""Resolve plugin path server-side: uu tien plugin_path truc tiep, con
khong thi plugin_id = ten plugin trong registry scan (JS chi co plugin_id)."""
path = (plugin_path or "").strip()
if path:
return path
pid = (plugin_id or "").strip()
if pid:
try:
plugins = get_plugin_manager()._scan_plugins()
if pid in plugins:
return plugins[pid]
except Exception:
pass
return ""
@router.get("/status")
async def status():
return _svc().status()
@@ -142,8 +179,12 @@ async def sf_audio_stop(req: SfNoteOffRequest):
@router.post("/vst2/ensure")
async def vst2_ensure(req: Vst2EnsureRequest):
path = _resolve_plugin_path(req.plugin_id, req.plugin_path)
if not path or not os.path.exists(path):
raise HTTPException(status_code=400, detail=f"khong tim thay plugin "
f"(plugin_id={req.plugin_id!r} plugin_path={req.plugin_path!r})")
try:
return _svc().ensure_vst2(req.track_id, req.plugin_path, req.live)
return _svc().ensure_vst2(req.track_id, path, req.live)
except RuntimeError as e:
raise HTTPException(status_code=400, detail=str(e))
@@ -163,6 +204,31 @@ async def vst2_note_off(req: Vst2NoteOffRequest):
except RuntimeError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.post("/vst3/ensure")
async def vst3_ensure(req: Vst3EnsureRequest):
path = _resolve_plugin_path(req.plugin_id, req.plugin_path)
if not path or not os.path.exists(path):
raise HTTPException(status_code=400, detail=f"khong tim thay plugin "
f"(plugin_id={req.plugin_id!r} plugin_path={req.plugin_path!r})")
try:
return _svc().ensure_vst3(req.track_id, path, req.live)
except RuntimeError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.post("/vst3/note_on")
async def vst3_note_on(req: Vst3NoteRequest):
try:
return _svc().vst3_note_on(req.track_id, req.channel, req.pitch, req.velocity)
except RuntimeError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.post("/vst3/note_off")
async def vst3_note_off(req: Vst3NoteOffRequest):
try:
return _svc().vst3_note_off(req.track_id, req.channel, req.pitch)
except RuntimeError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.post("/render")
async def render(req: RenderRequest):