feat: thêm soundfont và VSTi cho MIDI
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import os, uuid, json, tempfile
|
||||
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
|
||||
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
|
||||
from app.core.render_engine import PythonRenderEngine
|
||||
from app.api.v1.auth import get_current_user
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
UPLOAD_SF_DIR = os.path.join(settings.STORAGE_DIR, "soundfonts")
|
||||
os.makedirs(UPLOAD_SF_DIR, exist_ok=True)
|
||||
|
||||
|
||||
@router.get("/available")
|
||||
async def list_plugins(current_user: dict = Depends(get_current_user)):
|
||||
pm = PluginManager()
|
||||
return pm.list_available()
|
||||
|
||||
|
||||
@router.get("/default-soundfonts")
|
||||
async def list_default_soundfonts():
|
||||
static_sf_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "static", "soundfonts")
|
||||
result = []
|
||||
if os.path.isdir(static_sf_dir):
|
||||
for f in os.listdir(static_sf_dir):
|
||||
if f.endswith(".sf2") or f.endswith(".sf3"):
|
||||
result.append({
|
||||
"id": os.path.splitext(f)[0],
|
||||
"name": f,
|
||||
"file": f,
|
||||
"url": f"/soundfonts/{f}"
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/upload-soundfont")
|
||||
async def upload_soundfont(
|
||||
file: UploadFile = File(...),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
if not (file.filename and (file.filename.endswith(".sf2") or file.filename.endswith(".sf3"))):
|
||||
raise HTTPException(status_code=400, detail="Only .sf2 / .sf3 files are allowed")
|
||||
|
||||
contents = await file.read()
|
||||
if not PluginManager.validate_sf2_header(contents):
|
||||
raise HTTPException(status_code=400, detail="Invalid SoundFont file: missing RIFF/sfbk header")
|
||||
|
||||
file_id = str(uuid.uuid4()) + os.path.splitext(file.filename)[1]
|
||||
dest_path = os.path.join(UPLOAD_SF_DIR, file_id)
|
||||
with open(dest_path, "wb") as f:
|
||||
f.write(contents)
|
||||
|
||||
return {"id": file_id, "name": file.filename, "path": dest_path, "size_bytes": len(contents)}
|
||||
|
||||
|
||||
class RenderRequest(BaseModel):
|
||||
project_json: dict
|
||||
output_filename: Optional[str] = "render_output.wav"
|
||||
|
||||
|
||||
@router.post("/render")
|
||||
async def render_project(
|
||||
req: RenderRequest,
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
engine = PythonRenderEngine()
|
||||
output_path = os.path.join(settings.PROCESSED_DIR, req.output_filename or "render_output.wav")
|
||||
try:
|
||||
result_path = engine.render_project(req.project_json, output_path)
|
||||
return {"url": f"/static/audio/processed/{os.path.basename(result_path)}", "path": result_path}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Render failed: {str(e)}")
|
||||
Reference in New Issue
Block a user