- Add CueModel.duration field (float = 4.0) for block length in seconds - Add AnalysisBlock.calibration_offset field (float = 0.03) for librosa bias - Replace main-area animation grid with timeline canvas layout (toolbar, canvas, inspector) - Move ANIMATIONS panel into sidebar below DEVICES panel - Add timeline-toolbar with zoom slider, beat offset input, snap toggle
49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
from uuid import UUID, uuid4
|
|
from datetime import datetime, timezone
|
|
from typing import Any, Literal
|
|
from pydantic import BaseModel, Field
|
|
|
|
from lightsync.models.device import DeviceConfig
|
|
|
|
|
|
class AudioRef(BaseModel):
|
|
source_type: Literal["file", "youtube"] = "file"
|
|
path: str | None = None
|
|
yt_url: str | None = None
|
|
duration_seconds: float | None = None
|
|
|
|
|
|
class CueModel(BaseModel):
|
|
id: UUID = Field(default_factory=uuid4)
|
|
timestamp: float
|
|
duration: float = 4.0 # block length in seconds; defaults for old files
|
|
mode: Literal["animation", "frame_sequence"] = "animation"
|
|
animation: str | None = None
|
|
params: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class TrackModel(BaseModel):
|
|
device_id: UUID
|
|
cues: list[CueModel] = Field(default_factory=list)
|
|
|
|
|
|
class AnalysisBlock(BaseModel):
|
|
analysed_at: datetime | None = None
|
|
tempo_bpm: float | None = None
|
|
beat_times: list[float] = Field(default_factory=list)
|
|
onset_times: list[float] = Field(default_factory=list)
|
|
calibration_offset: float = 0.03 # seconds; compensates librosa latency bias
|
|
|
|
|
|
class ShowModel(BaseModel):
|
|
schema_version: int = 1
|
|
id: UUID = Field(default_factory=uuid4)
|
|
name: str
|
|
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
audio: AudioRef = Field(default_factory=AudioRef)
|
|
devices: list[DeviceConfig] = Field(default_factory=list)
|
|
analysis: AnalysisBlock = Field(default_factory=AnalysisBlock)
|
|
tracks: list[TrackModel] = Field(default_factory=list)
|
|
ai_sequences: list[Any] = Field(default_factory=list)
|