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:
+17
-59
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user