"""Especificações de geração: rough cut, ritmo e montagem. Extraído de models.py — ver fcpxml/models/__init__.py. """ from dataclasses import dataclass, field from typing import List, Optional, Tuple from .enums import PacingCurve @dataclass class SegmentSpec: """Specification for a segment in auto rough cut.""" name: str keywords: List[str] = field(default_factory=list) duration_seconds: float = 0.0 priority: str = "best" # favorites, longest, shortest, random, best @dataclass class PacingConfig: """Configuration for rough cut pacing.""" pacing: str = "medium" # slow, medium, fast, dynamic min_clip_duration: float = 1.0 max_clip_duration: float = 8.0 avg_clip_duration: Optional[float] = None vary_pacing: bool = True def get_duration_range(self) -> Tuple[float, float]: """Get min/max based on pacing style.""" ranges = { "slow": (5.0, 10.0), "medium": (2.0, 5.0), "fast": (0.5, 2.0), "dynamic": (1.0, 6.0), } return ranges.get(self.pacing, (2.0, 5.0)) @dataclass class RoughCutResult: """Result of auto rough cut generation.""" output_path: str clips_used: int clips_available: int target_duration: float actual_duration: float segments: int average_clip_duration: float @dataclass class MontageConfig: """Configuration for montage generation with pacing curves.""" target_duration: float # Target duration in seconds pacing_curve: 'PacingCurve' start_duration: float = 2.0 # Clip duration at start end_duration: float = 0.5 # Clip duration at end min_duration: float = 0.2 # Minimum allowed clip duration max_duration: float = 5.0 # Maximum allowed clip duration def get_duration_at_position(self, position: float) -> float: """ Calculate clip duration for a given position (0.0 to 1.0). Args: position: Position in montage (0.0 = start, 1.0 = end) Returns: Target duration in seconds for a clip at this position """ if self.pacing_curve == PacingCurve.CONSTANT: duration = (self.start_duration + self.end_duration) / 2 elif self.pacing_curve == PacingCurve.ACCELERATING: # Linear interpolation from start to end duration duration = self.start_duration + (self.end_duration - self.start_duration) * position elif self.pacing_curve == PacingCurve.DECELERATING: # Reverse: start fast, end slow duration = self.end_duration + (self.start_duration - self.end_duration) * position elif self.pacing_curve == PacingCurve.PYRAMID: # Slow → fast → slow (parabolic curve) if position < 0.5: # First half: slow to fast duration = self.start_duration + (self.end_duration - self.start_duration) * (position * 2) else: # Second half: fast to slow duration = self.end_duration + (self.start_duration - self.end_duration) * ((position - 0.5) * 2) else: duration = self.start_duration # Clamp to min/max return max(self.min_duration, min(self.max_duration, duration))