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
+17 -59
View File
@@ -6,7 +6,7 @@ from fastapi.responses import FileResponse
from pydantic import BaseModel
from typing import Optional, Any
from app.config import settings
from app.core.vst_engine import PluginManager, HAS_PEDALBOARD, HAS_PYFLUIDSYNTH, apply_preset_to_plugin, render_soundfont_midi_to_audio, RENDER_LOCK, _render_locked
from app.core.vst_engine import PluginManager, HAS_PYFLUIDSYNTH, render_soundfont_midi_to_audio, RENDER_LOCK, _render_locked
from app.core.render_engine import PythonRenderEngine, _find_sf2_path, _find_default_sf2
from app.core.soundfont_inspector import SoundFontInspector
from app.core.soundfont_converter import SoundFontConverter
@@ -875,8 +875,8 @@ def _write_carla_project(plugin_name: str, plugin_path: str) -> str:
async def preview_instrument(req: PreviewRequest):
"""Quick-render preview VSTi (âm thật, cùng code path với export)."""
# SF_RENDER_ENGINE=bridge: preview qua native_bridge, không cần pedalboard
if settings.RENDER_ENGINE != "bridge" and not HAS_PEDALBOARD:
raise HTTPException(status_code=501, detail="pedalboard không khả dụng trên máy này")
if settings.RENDER_ENGINE != "bridge":
raise HTTPException(status_code=501, detail="Chỉ hỗ trợ native_bridge render — set SF_RENDER_ENGINE=bridge")
if not req.notes:
raise HTTPException(status_code=400, detail="Chưa có nốt nhạc để preview")
try:
@@ -969,8 +969,8 @@ async def midi_render(req: MidiRenderRequest, current_user: dict = Depends(get_c
pass
raise HTTPException(
status_code=500,
detail=f"Render MIDI thất bại: {e}. Nếu plugin là VST2 hoặc pedalboard "
"không load được, hãy mở Carla Bridge (chọn VSTi, chỉnh âm, "
detail=f"Render MIDI thất bại: {e}. Nếu plugin VSTi không load được "
"qua native_bridge, hãy mở Carla Bridge (chọn VSTi, chỉnh âm, "
"Save preset .vstpreset) rồi Upload preset vào track — render "
"sẽ dùng đúng âm đã chỉnh.",
)
@@ -982,66 +982,24 @@ def _render_midi_notes_pedalboard(instrument_id: str, notes: list, bpm: float,
preset_data_b64=None, soundfont_bank=None,
soundfont_program=None) -> tuple:
"""Render MIDI notes (VSTi + preset) → WAV trong PROCESSED_DIR — qua
pedalboard (mặc định) hoặc native_bridge --render (SF_RENDER_ENGINE=bridge).
native_bridge --render (SF_RENDER_ENGINE=bridge; pedalboard GPL-3.0 đã gỡ).
Trả (out_path, duration_sec). Ném HTTPException khi plugin không load được."""
if settings.RENDER_ENGINE == "bridge":
from app.core import native_render
return native_render.render_offline(
instrument_id=instrument_id,
notes=notes,
bpm=bpm,
sample_rate=sample_rate,
preset_id=preset_id,
preset_path=preset_path,
preset_data_b64=preset_data_b64,
soundfont_bank=soundfont_bank,
soundfont_program=soundfont_program,
)
if not HAS_PEDALBOARD:
raise HTTPException(status_code=501, detail="pedalboard không khả dụng trên máy này")
pm = PluginManager()
vst = pm.load_vst(instrument_id)
if vst is None:
raise HTTPException(
status_code=404,
detail=f"Không tìm thấy VSTi: {instrument_id} — chưa scan thấy plugin này. "
"Kiểm tra Plugins Manager → Scan, hoặc mở Carla để load VST2 "
"(pedalboard chỉ render được VST3).",
)
apply_preset_to_plugin(
vst,
if settings.RENDER_ENGINE != "bridge":
raise HTTPException(status_code=501,
detail="Chỉ hỗ trợ native_bridge render — set SF_RENDER_ENGINE=bridge")
from app.core import native_render
return native_render.render_offline(
instrument_id=instrument_id,
notes=notes,
bpm=bpm,
sample_rate=sample_rate,
preset_id=preset_id,
preset_path=preset_path,
preset_data_b64=preset_data_b64,
soundfont_bank=soundfont_bank,
soundfont_program=soundfont_program,
)
from pedalboard import Pedalboard
midi_events = []
for n in notes:
midi_events.append({
"note": int(n.get("pitch", 60)),
"start_beat": float(n.get("start_beat", 0)),
"duration_beats": float(n.get("duration_beats", 1)),
"velocity": int(float(n.get("velocity", 0.8)) * 127),
})
midi_messages = PluginManager.midi_events_to_messages(
midi_events, bpm, sample_rate,
bank=soundfont_bank, program=soundfont_program,
)
total_needed = 0
beat_sec = 60.0 / max(30.0, bpm)
for ev in midi_events:
end_sec = (ev["start_beat"] + ev["duration_beats"]) * beat_sec
if int(end_sec * sample_rate) > total_needed:
total_needed = int(end_sec * sample_rate)
total_needed = max(total_needed, 1024)
# pedalboard >= 0.9: Pedalboard container KHÔNG chứa instrument — gọi
# thẳng overload MIDI của plugin (overload 2: midi_messages + duration).
buf = vst(midi_messages, sample_rate=sample_rate,
duration=total_needed / float(sample_rate), num_channels=2)
out_path = os.path.join(settings.PROCESSED_DIR, f"preview_{uuid.uuid4().hex[:10]}.wav")
sf.write(out_path, buf.T, sample_rate)
return out_path, buf.shape[1] / float(sample_rate)
class SoundfontRenderRequest(BaseModel):