phase5: mặc định RENDER_ENGINE=bridge, gỡ pedalboard khỏi requirements/source/LICENSE

- config.py: SF_RENDER_ENGINE default 'bridge' (pedalboard GPL-3.0 đã gỡ)
- requirements.txt: bỏ pedalboard==0.9.19
- vst_engine.py: bỏ HAS_PEDALBOARD/check_pedalboard_safe/load_vst/import pedalboard;
  midi_events_to_messages giữ làm utility thuần (không gate pedalboard)
- render_engine.py: bỏ nhánh elif vst and HAS_PEDALBOARD + import thừa
- plugins.py: preview/midi-render chỉ qua native_bridge; guard SF_RENDER_ENGINE=bridge
- runtime.py: _vst_render_available() check bridge exe (SF_BRIDGE_PATH/install/) thay find_spec('pedalboard')
- LICENSE.md/THIRD_PARTY_LICENSES.md: bỏ cảnh báo GPL-3.0 pedalboard, đánh số lại
- tests: bỏ test golden so pedalboard + test requires_pedalboard; 114 passed 0 skip
This commit is contained in:
2026-08-17 12:58:51 +07:00
parent e79dae5d5c
commit dc331f39d8
14 changed files with 55 additions and 215 deletions
-24
View File
@@ -66,27 +66,3 @@ def test_plugins_bridge_branch_dispatch(monkeypatch):
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}"
-15
View File
@@ -5,7 +5,6 @@ from fastapi.testclient import TestClient
from unittest.mock import patch, MagicMock
from app.main import app
from app.core.vst_engine import HAS_PEDALBOARD, HAS_PYFLUIDSYNTH
client = TestClient(app)
@@ -176,20 +175,6 @@ class TestMidiRenderVSTi:
assert resp.status_code == 404
assert "VSTi" in resp.json()["detail"]
def test_midi_render_requires_pedalboard(self):
# Nếu pedalboard thiếu → 501 (không crash)
import app.api.v1.plugins as plugins_mod
token = get_admin_token()
if not token:
pytest.skip("Cannot get admin token")
if not plugins_mod.HAS_PEDALBOARD:
resp = client.post("/api/v1/plugins/midi-render", headers={"Authorization": f"Bearer {token}"},
json={"instrument_id": "x",
"notes": [{"pitch": 60, "start_beat": 0, "duration_beats": 1}]})
assert resp.status_code == 501
else:
pytest.skip("pedalboard present — render path covered by unknown-instrument test")
def test_carla_play_notes_requires_auth(self):
client.cookies.clear() # TestClient giữ cookie login từ test trước
resp = client.post("/api/v1/plugins/carla-play-notes",
+4 -4
View File
@@ -56,8 +56,8 @@ def test_render_session_vsti_bridge_unknown_instrument_falls_back(monkeypatch):
assert (buf != 0.0).any()
def test_render_session_vsti_pedalboard_default_falls_back(monkeypatch):
"""Mặc định pedalboard: không có plugin load được → oscillator (không crash)."""
def test_render_session_vsti_non_bridge_engine_falls_back(monkeypatch):
"""Engine không phải bridge (vd 'pedalboard' cũ): VSTi → fallback oscillator (không crash)."""
from app.api.v1 import plugins as pl
monkeypatch.setattr(pl.settings, "RENDER_ENGINE", "pedalboard")
engine = PythonRenderEngine()
@@ -69,7 +69,7 @@ def test_render_session_vsti_pedalboard_default_falls_back(monkeypatch):
def test_render_session_fx_chorus_scipy_fallback():
"""FX chorus: fallback scipy (không pedalboard) không crash, thay đổi âm."""
from app.api.v1 import plugins as pl
pl.settings.RENDER_ENGINE = "pedalboard"
pl.settings.RENDER_ENGINE = "bridge"
engine = PythonRenderEngine()
session = {"tracks": [_midi_track("__no_such_plugin__", fx_type="chorus")]}
buf = engine.render_session_container(session, {}, 120.0, 4, 44100)
@@ -80,7 +80,7 @@ def test_render_session_fx_chorus_scipy_fallback():
def test_render_session_fx_reverb_scipy_fallback():
"""FX reverb: fallback scipy (không pedalboard) không crash, thay đổi âm."""
from app.api.v1 import plugins as pl
pl.settings.RENDER_ENGINE = "pedalboard"
pl.settings.RENDER_ENGINE = "bridge"
engine = PythonRenderEngine()
session = {"tracks": [_midi_track("__no_such_plugin__", fx_type="reverb")]}
buf = engine.render_session_container(session, {}, 120.0, 4, 44100)
+1 -3
View File
@@ -4,7 +4,7 @@ import pytest
import numpy as np
from unittest.mock import patch, MagicMock
from app.core.vst_engine import PluginManager, midi_note_to_freq, render_midi_events_to_audio, HAS_PEDALBOARD
from app.core.vst_engine import PluginManager, midi_note_to_freq, render_midi_events_to_audio
class TestPluginManager:
@@ -20,8 +20,6 @@ class TestPluginManager:
assert pm.sf_dir == "/opt/daw_engine/soundfonts"
def test_midi_events_to_messages(self):
if not HAS_PEDALBOARD:
pytest.skip("pedalboard not available")
events = [{"note": 60, "start_beat": 0, "duration_beats": 1, "velocity": 100}]
bpm = 120
sr = 44100