feat: VST FX rack per-track + masterbus render via native_bridge
This commit is contained in:
@@ -2,6 +2,7 @@ import os
|
||||
import json
|
||||
import pytest
|
||||
from app.core.render_engine import PythonRenderEngine
|
||||
import numpy as np
|
||||
|
||||
def test_render_engine_init():
|
||||
engine = PythonRenderEngine()
|
||||
@@ -87,3 +88,68 @@ def test_render_session_fx_reverb_scipy_fallback():
|
||||
assert buf.shape == (2, 44100)
|
||||
assert (buf != 0.0).any()
|
||||
|
||||
|
||||
_BRIDGE_TEST_PATH = r"C:/Users/locpham/SonicForgeStudio/native_bridge/build/Release/daw_vst_bridge.exe"
|
||||
|
||||
|
||||
def _peak(buf):
|
||||
return float(np.max(np.abs(buf)))
|
||||
|
||||
|
||||
def test_render_track_fx_chain_gain_via_bridge(monkeypatch):
|
||||
"""Track fx_chain (builtin gain +6dB) qua native_bridge → biên độ x2."""
|
||||
import numpy as np
|
||||
if not os.path.isfile(_BRIDGE_TEST_PATH):
|
||||
pytest.skip("bridge chưa build")
|
||||
monkeypatch.setenv("SF_BRIDGE_PATH", _BRIDGE_TEST_PATH)
|
||||
from app.api.v1 import plugins as pl
|
||||
monkeypatch.setattr(pl.settings, "RENDER_ENGINE", "bridge")
|
||||
engine = PythonRenderEngine()
|
||||
base = _midi_track("__no_such_plugin__")
|
||||
fx = _midi_track("__no_such_plugin__")
|
||||
fx["vst_fx_chain"] = [{"type": "builtin", "id": "gain", "params": {"db": 6.0}}]
|
||||
b0 = engine.render_session_container({"tracks": [base]}, {}, 120.0, 4, 44100)
|
||||
b1 = engine.render_session_container({"tracks": [fx]}, {}, 120.0, 4, 44100)
|
||||
assert _peak(b1) > 1.5 * _peak(b0)
|
||||
|
||||
|
||||
def test_render_project_master_fx_chain_gain_via_bridge(monkeypatch, tmp_path):
|
||||
"""Masterbus master.fx_chain (gain +6dB) qua native_bridge → peak x2."""
|
||||
import numpy as np
|
||||
if not os.path.isfile(_BRIDGE_TEST_PATH):
|
||||
pytest.skip("bridge chưa build")
|
||||
monkeypatch.setenv("SF_BRIDGE_PATH", _BRIDGE_TEST_PATH)
|
||||
from app.api.v1 import plugins as pl
|
||||
monkeypatch.setattr(pl.settings, "RENDER_ENGINE", "bridge")
|
||||
engine = PythonRenderEngine()
|
||||
|
||||
def project(with_master):
|
||||
track = _midi_track("__no_such_plugin__")
|
||||
track["volume_db"] = -20.0 # tránh normalize (>1.0) làm hỏng tỉ lệ 2x
|
||||
proj = {
|
||||
"metadata": {"bpm": 120.0, "time_signature_numerator": 4},
|
||||
"main_session": {"length_bars": 1.0, "tracks": [track]},
|
||||
"section_store": {},
|
||||
}
|
||||
if with_master:
|
||||
proj["main_session"]["master"] = {
|
||||
"fx_chain": [{"type": "builtin", "id": "gain", "params": {"db": 6.0}}],
|
||||
"bypass": False,
|
||||
}
|
||||
return proj
|
||||
|
||||
out0 = str(tmp_path / "no_master.wav")
|
||||
out1 = str(tmp_path / "with_master.wav")
|
||||
engine.render_project(project(False), out0)
|
||||
engine.render_project(project(True), out1)
|
||||
_, d0 = sf_read_peaks(out0)
|
||||
_, d1 = sf_read_peaks(out1)
|
||||
assert d1 > 1.5 * d0
|
||||
|
||||
import soundfile as _sf
|
||||
|
||||
def sf_read_peaks(path):
|
||||
import numpy as np
|
||||
data, _ = _sf.read(path, dtype="float32", always_2d=True)
|
||||
return data, float(np.max(np.abs(data)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user