feat(fx-gui): đưa audio vào process GUI — meter VST nhảy theo âm thật qua SHM peek

- GUI process peek ring SHM đầu vào (không consume, không tranh chấp RealtimeFxLoop)
- gọi fx->processAudio() trên instance GUI để meter/UI plugin chuyển động theo âm thật
- performEdit forward sang controller -> meter điều khiển bởi param cũng cập nhật
- bridge /shm: frontend đẩy tên session live vào mỗi GUI đang mở (start/stop/open)
- tests: 127 passed
This commit is contained in:
2026-08-22 17:06:37 +07:00
parent 6ba38286ad
commit 6dfe390bda
7 changed files with 219 additions and 24 deletions
+32
View File
@@ -262,6 +262,38 @@ class TestMidiRenderVSTi:
for p in plugins_mod._FX_GUI_PROCESSES)
plugins_mod._FX_GUI_PROCESSES.clear()
def test_fx_gui_open_shm_written_to_job(self):
"""shm (tên session realtime) phải vào job.json → bridge fx-gui mở SHM
để feed audio vào instance GUI (meter nhảy theo âm thật)."""
token = get_admin_token()
if not token:
pytest.skip("Cannot get admin token")
import tempfile as _tf
fd, known = _tf.mkstemp(prefix="sf_fx_gui_test_", suffix=".json")
fake_proc = MagicMock()
fake_proc.stdout = iter(["SF_FXGUI_PORT=54322\n"])
from app.api.v1 import plugins as plugins_mod
try:
with patch("app.core.native_render.find_bridge_exe",
return_value="C:\\bridge\\daw_vst_bridge.exe"), \
patch("app.api.v1.plugins.subprocess.Popen", return_value=fake_proc), \
patch("app.api.v1.plugins.tempfile.mkstemp", return_value=(fd, known)):
resp = client.post("/api/v1/plugins/fx-gui",
headers={"Authorization": f"Bearer {token}"},
json={"path": "C:\\VST\\Ozone11.vst3", "name": "Ozone 11",
"embed": True, "shm": "SonicForge_FXRT_abc123"})
assert resp.status_code == 200
with open(known, "r", encoding="utf-8") as f:
job = json.load(f)
assert job.get("shm") == "SonicForge_FXRT_abc123"
finally:
plugins_mod._FX_GUI_PROCESSES.clear()
if os.path.exists(known):
try:
os.remove(known)
except OSError:
pass
def test_fx_gui_open_no_port_is_error(self):
token = get_admin_token()
if not token: