phase2: fix velocity double-scaling in bridge job, bank/program parity, golden RMS test
- render_offline: send velocity as float 0..1 (RenderJob.cpp scales *127); old int(0.8*127) was scaled again -> clamp 127, velocity ignored - forward soundfont_bank/program into bridge job (presence-based, matches midi_events_to_messages) - new tests: bridge branch dispatch (SF_RENDER_ENGINE=bridge -> 404), bridge vs pedalboard golden RMS comparison (plan section 6)
This commit is contained in:
@@ -44,7 +44,7 @@ def test_bridge_render_sf2_e2e():
|
||||
pytest.skip("SF2 fixture missing")
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
job = {"instrument_type": 2, "plugin_path": sf2, "sample_rate": 44100, "bpm": 120.0,
|
||||
"notes": [{"pitch": 60, "velocity": 101, "start_beat": 0.0, "duration_beats": 1.0}]}
|
||||
"notes": [{"pitch": 60, "velocity": 0.8, "start_beat": 0.0, "duration_beats": 1.0}]}
|
||||
jp = os.path.join(td, "job.json")
|
||||
out = os.path.join(td, "out.wav")
|
||||
with open(jp, "w", encoding="utf-8") as fh:
|
||||
@@ -56,3 +56,37 @@ def test_bridge_render_sf2_e2e():
|
||||
info = sf.info(out)
|
||||
assert info.samplerate == 44100
|
||||
assert info.frames == 22050
|
||||
|
||||
|
||||
def test_plugins_bridge_branch_dispatch(monkeypatch):
|
||||
"""SF_RENDER_ENGINE=bridge: _render_midi_notes_pedalboard phải đi
|
||||
vào native_render (instrument lạ -> 404), không cần pedalboard."""
|
||||
from app.api.v1 import plugins as pl
|
||||
monkeypatch.setattr(pl.settings, "RENDER_ENGINE", "bridge")
|
||||
with pytest.raises(HTTPException) as ei:
|
||||
pl._render_midi_notes_pedalboard("__no_such__", [], bpm=120.0, sample_rate=44100)
|
||||
assert ei.value.status_code == 404
|
||||
|
||||
|
||||
def test_bridge_matches_pedalboard_rms():
|
||||
"""Golden so sánh (plan §6): bridge vs pedalboard cùng job Nexus → RMS
|
||||
trong tolerance. Skip nếu máy thiếu pedalboard hoặc Nexus VST3."""
|
||||
from app.core.vst_engine import HAS_PEDALBOARD, PluginManager
|
||||
if not HAS_PEDALBOARD:
|
||||
pytest.skip("pedalboard not installed")
|
||||
itype, path = native_render._resolve_instrument("Nexus")
|
||||
if not path:
|
||||
pytest.skip("Nexus VST3 not installed")
|
||||
notes = [{"pitch": 60, "velocity": 0.8, "start_beat": 0.0, "duration_beats": 1.0}]
|
||||
out_b, dur_b = native_render.render_offline("Nexus", notes, bpm=120.0, sample_rate=44100)
|
||||
vst = PluginManager().load_vst("Nexus")
|
||||
if vst is None:
|
||||
pytest.skip("pedalboard cannot load Nexus")
|
||||
ev = [{"note": 60, "start_beat": 0.0, "duration_beats": 1.0, "velocity": 101}]
|
||||
msgs = PluginManager.midi_events_to_messages(ev, 120.0, 44100)
|
||||
buf = vst(msgs, sample_rate=44100, duration=dur_b, num_channels=2)
|
||||
import numpy as np
|
||||
audio = sf.read(out_b)[0]
|
||||
rms_b = float(np.sqrt((audio ** 2).mean()))
|
||||
rms_p = float(np.sqrt((np.asarray(buf.T) ** 2).mean()))
|
||||
assert abs(rms_b - rms_p) < 0.01, f"bridge={rms_b:.5f} pedalboard={rms_p:.5f}"
|
||||
|
||||
Reference in New Issue
Block a user