feat(02-03): add waveform extraction module and HTTP endpoint
- Create lightsync/audio/waveform.py with extract_peaks() (AUD-05)
- MP3 via ffmpeg pipe, WAV/FLAC/OGG via soundfile+numpy
- Add GET /api/audio/waveform endpoint with asyncio.to_thread
- peaks param clamped 100-5000, returns {peaks, count, file}
This commit is contained in:
@@ -3,6 +3,7 @@ import asyncio
|
||||
from pathlib import Path
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from pydantic import BaseModel
|
||||
from lightsync.audio.waveform import extract_peaks
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -45,3 +46,28 @@ async def get_audio_state(request: Request):
|
||||
if engine is None:
|
||||
raise HTTPException(status_code=503, detail="Audio engine not ready")
|
||||
return engine.get_state()
|
||||
|
||||
|
||||
@router.get("/waveform")
|
||||
async def get_waveform(request: Request, peaks: int = 1000):
|
||||
"""Get waveform peak data for the currently loaded audio file (AUD-05).
|
||||
|
||||
Query params:
|
||||
peaks: Number of peak samples (default 1000, max 5000)
|
||||
"""
|
||||
engine = request.app.state.engine
|
||||
if engine is None:
|
||||
raise HTTPException(status_code=503, detail="Audio engine not ready")
|
||||
|
||||
state = engine.get_state()
|
||||
if not state["loaded"] or not state["file"]:
|
||||
raise HTTPException(status_code=400, detail="No audio file loaded")
|
||||
|
||||
num_peaks = min(max(peaks, 100), 5000)
|
||||
|
||||
try:
|
||||
data = await asyncio.to_thread(extract_peaks, state["file"], num_peaks)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Waveform extraction failed: {e}")
|
||||
|
||||
return {"peaks": data, "count": len(data), "file": state["file"]}
|
||||
|
||||
Reference in New Issue
Block a user