V45: D17 seamless loop wrap + D18 stop solo note-off (Qin) + D18b/c guard + engine VST load fixes
- D17: wrap_info/wrap-skip, fx wrap xfade, playhead-derived scheduling - D18: solo stop -> NOTE_OFF all sounding timeline pitches + CC123/CC120 - D18b: track audible gain guard, tracksRef fallback - D18c: timelinePitchesRef per-track Set, kill at applyAllTrackMuteSolo - bridge ring _MAX 16, index v=202608290928 - plugins.py/vst_engine.py/fx_realtime.py/JuceFxEngine.cpp: VSTi load + Qin fixes (uncommitted 12:18)
This commit is contained in:
@@ -1,13 +1,10 @@
|
||||
import os, sys, uuid, json, tempfile, subprocess, time as _time, threading, asyncio, logging
|
||||
import numpy as np
|
||||
import soundfile as sf
|
||||
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File, BackgroundTasks, Query, WebSocket, WebSocketDisconnect
|
||||
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_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
|
||||
from app.core.soundfont_scanner import SoundFontAutoScanner
|
||||
@@ -570,6 +567,7 @@ async def delete_soundfont(sf_id: str, current_user: dict = Depends(get_current_
|
||||
|
||||
@router.get("/soundfonts/download/{sf_id}")
|
||||
async def download_soundfont_asset(sf_id: str):
|
||||
from app.core.render_engine import _find_sf2_path, _find_default_sf2
|
||||
clean_id = sf_id.replace("sf_", "") if sf_id.startswith("sf_") else sf_id
|
||||
# Cũng tìm trong static/soundfonts (font bundled theo deployment) — trước
|
||||
# đây chỉ UPLOAD + SYSTEM → font bundled 404 → incognito (IndexedDB rỗng)
|
||||
@@ -963,6 +961,7 @@ class FxRenderRequest(BaseModel):
|
||||
@router.post("/fx-render")
|
||||
async def fx_render(req: FxRenderRequest, current_user: dict = Depends(get_current_user)):
|
||||
"""Áp fx_chain lên WAV đầu vào → WAV mới trong PROCESSED_DIR."""
|
||||
import soundfile as sf
|
||||
enforce_password_changed(current_user)
|
||||
src = (req.input_path or "").strip()
|
||||
if not src:
|
||||
@@ -1233,6 +1232,8 @@ async def soundfont_render(req: SoundfontRenderRequest, current_user: dict = Dep
|
||||
Khác FluidSynthWASM (docker): âm render server-side bằng pyfluidsynth, trả
|
||||
WAV để client play. Dùng cho: preview/keyboard, play MIDI item khi chạy
|
||||
transport ở môi trường standalone."""
|
||||
from app.core.render_engine import _find_sf2_path, _find_default_sf2
|
||||
import soundfile as sf
|
||||
enforce_password_changed(current_user)
|
||||
if not req.notes:
|
||||
raise HTTPException(status_code=400, detail="Chưa có nốt nhạc để render")
|
||||
@@ -1288,6 +1289,9 @@ def render_project(
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
enforce_password_changed(current_user)
|
||||
from app.core.render_engine import PythonRenderEngine
|
||||
import soundfile as sf
|
||||
import numpy as np
|
||||
engine = PythonRenderEngine()
|
||||
# Prevent path traversal: strip directory components; force .wav/.ogg.
|
||||
safe_name = os.path.basename((req.output_filename or "render_output.wav").replace("\\", "/"))
|
||||
|
||||
Reference in New Issue
Block a user