feat: add SoundFont inspection engine + AI instrument schema
- SoundFontInspector (sf2utils) scans .sf2, generates full/condensed catalog - GET /api/v1/plugins/soundfonts/catalog with lazy init + cache invalidation - AI tool generate_multitrack_midi now requires soundfont_id/bank/program - Condensed catalog auto-injected into AI system prompt with bank rules - Server render: FluidSynth program_select uses bank/program + channel routing (drums→ch9) - VST3 pedalboard path inserts CC0 bank select + program change before notes - DecentSamplerManager loads .dspreset with CWD fix for relative sample paths - Pianobook render branch in render_engine.py - Client SonicSF: controllerChange, programChange, applyAITrackInstrument - Post-AI track creation applies instrument via applyAITrackInstrument - Background cache rescan on .sf2 upload, frontend re-fetches catalog - libcurl4 + VST3 dirs in Dockerfile
This commit is contained in:
+28
-1
@@ -1,10 +1,11 @@
|
||||
import os, uuid, json, tempfile
|
||||
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
|
||||
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File, BackgroundTasks
|
||||
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.core.soundfont_inspector import SoundFontInspector
|
||||
from app.api.v1.auth import get_current_user
|
||||
|
||||
router = APIRouter()
|
||||
@@ -12,6 +13,16 @@ router = APIRouter()
|
||||
UPLOAD_SF_DIR = os.path.join(settings.STORAGE_DIR, "soundfonts")
|
||||
os.makedirs(UPLOAD_SF_DIR, exist_ok=True)
|
||||
|
||||
SYSTEM_SF_DIR = "/opt/daw_engine/soundfonts"
|
||||
|
||||
_inspector = None
|
||||
|
||||
def get_inspector():
|
||||
global _inspector
|
||||
if _inspector is None:
|
||||
_inspector = SoundFontInspector(system_sf_dir=SYSTEM_SF_DIR, upload_sf_dir=UPLOAD_SF_DIR)
|
||||
return _inspector
|
||||
|
||||
|
||||
@router.get("/available")
|
||||
async def list_plugins(current_user: dict = Depends(get_current_user)):
|
||||
@@ -35,6 +46,14 @@ async def list_default_soundfonts():
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/soundfonts/catalog")
|
||||
async def soundfont_catalog(current_user: dict = Depends(get_current_user)):
|
||||
inspector = get_inspector()
|
||||
full_catalog = inspector.get_catalog()
|
||||
condensed_catalog = inspector.get_condensed_catalog_summary()
|
||||
return {"full_catalog": full_catalog, "condensed_catalog": condensed_catalog}
|
||||
|
||||
|
||||
@router.get("/soundfont-instruments/{sf_id}")
|
||||
async def list_soundfont_instruments(sf_id: str, current_user: dict = Depends(get_current_user)):
|
||||
pm = PluginManager(upload_sf_dir=UPLOAD_SF_DIR)
|
||||
@@ -45,6 +64,7 @@ async def list_soundfont_instruments(sf_id: str, current_user: dict = Depends(ge
|
||||
@router.post("/upload-soundfont")
|
||||
async def upload_soundfont(
|
||||
file: UploadFile = File(...),
|
||||
background_tasks: BackgroundTasks = None,
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
if not (file.filename and (file.filename.endswith(".sf2") or file.filename.endswith(".sf3"))):
|
||||
@@ -69,6 +89,11 @@ async def upload_soundfont(
|
||||
import json
|
||||
json.dump({"original_name": file.filename, "uuid": file_uuid, "file": file_id}, f)
|
||||
|
||||
inspector = get_inspector()
|
||||
inspector.invalidate_catalog_cache()
|
||||
if background_tasks:
|
||||
background_tasks.add_task(inspector.generate_full_catalog)
|
||||
|
||||
return {"id": file_id, "name": file.filename, "path": dest_path, "size_bytes": len(contents)}
|
||||
|
||||
|
||||
@@ -93,6 +118,8 @@ async def delete_soundfont(sf_id: str, current_user: dict = Depends(get_current_
|
||||
break
|
||||
if not deleted:
|
||||
raise HTTPException(status_code=404, detail="SoundFont not found")
|
||||
inspector = get_inspector()
|
||||
inspector.invalidate_catalog_cache()
|
||||
return {"deleted": True, "sf_id": sf_id}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user