Spaces:
Sleeping
Sleeping
| """Shared preview/full-set rendering entrypoints. | |
| This module exists so preview exports and full-set exports cannot drift into | |
| separate tempo, pitch, and headroom policies again. Both paths call the same | |
| AutomationIR renderer and therefore share: | |
| * source-tempo default rendering; | |
| * pitch-preserving stretch only when explicitly enabled in plan metadata; | |
| * component-lane handoff back to the untouched full source clip; | |
| * attenuation-only output protection. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any, Callable, Mapping | |
| from automation_ir import AutomationIR, render_automation_ir, build_transition_ir | |
| from automation_set_renderer import build_set_automation_ir | |
| AudioLoader = Callable[[str, float, float, int], Any] | |
| TimeStretcher = Callable[[Any, float], Any] | |
| StemResolver = Callable[[Any, str, Any, int], Any | None] | |
| def render_ir( | |
| ir: AutomationIR, | |
| *, | |
| load_audio_segment: AudioLoader, | |
| time_stretch_audio: TimeStretcher, | |
| stem_resolver: StemResolver | None = None, | |
| ) -> Any: | |
| return render_automation_ir( | |
| ir, | |
| load_audio_segment=load_audio_segment, | |
| time_stretch_audio=time_stretch_audio, | |
| stem_resolver=stem_resolver, | |
| ) | |
| def render_transition_preview( | |
| plan: Any, | |
| track_a: Any, | |
| track_b: Any, | |
| *, | |
| candidate_rank: int = 0, | |
| load_audio_segment: AudioLoader, | |
| time_stretch_audio: TimeStretcher, | |
| stem_resolver: StemResolver | None = None, | |
| sr: int = 44100, | |
| ) -> tuple[Any, AutomationIR, Mapping[str, Any] | None]: | |
| candidate = None | |
| alternatives = list(getattr(plan, "alternatives", []) or []) | |
| if candidate_rank > 0 and candidate_rank <= len(alternatives): | |
| candidate = alternatives[candidate_rank - 1] | |
| ir = build_transition_ir(plan, track_a, track_b, candidate=candidate, sr=sr) | |
| audio = render_ir( | |
| ir, | |
| load_audio_segment=load_audio_segment, | |
| time_stretch_audio=time_stretch_audio, | |
| stem_resolver=stem_resolver, | |
| ) | |
| try: | |
| from transition_diagnostics import diagnose_transition_audio | |
| diag = diagnose_transition_audio(audio, sr=sr, anchor_seconds=ir.anchor_seconds) | |
| ir.metadata["rendered_diagnostics"] = diag | |
| metrics = dict(diag.get("metrics", {}) or {}) | |
| rendered_scores = { | |
| "kick_overlap_score": round(float(metrics.get("onset_regularity", 0.0) or 0.0), 3), | |
| "bass_overlap_score": round(max(0.0, min(1.0, 1.0 / max(float(metrics.get("anchor_low_balance_ratio", 1.0) or 1.0), 1.0))), 3), | |
| "energy_dip_jump_score": round(max(0.0, min(1.0, float(metrics.get("anchor_min_rms_ratio", 1.0) or 1.0) / max(float(metrics.get("anchor_rms_balance_ratio", 1.0) or 1.0), 1.0))), 3), | |
| "spectral_harshness_score": round(max(0.0, min(1.0, 1.0 / max(float(metrics.get("high_band_spike_ratio", 1.0) or 1.0) / 2.0, 1.0))), 3), | |
| "phrase_arrival_confidence": float((ir.metadata.get("candidate", {}) or {}).get("score_breakdown", {}).get("arrival_quality", 0.0) or 0.0), | |
| } | |
| ir.metadata["rendered_candidate_scores"] = rendered_scores | |
| if isinstance(candidate, dict): | |
| candidate["rendered_diagnostics"] = diag | |
| candidate["rendered_candidate_scores"] = rendered_scores | |
| except Exception: | |
| pass | |
| return audio, ir, candidate | |
| def render_full_set( | |
| tracks: list[Any], | |
| order: list[int], | |
| transitions: list[Any], | |
| *, | |
| load_audio_segment: AudioLoader, | |
| time_stretch_audio: TimeStretcher, | |
| stem_resolver: StemResolver | None = None, | |
| sr: int = 44100, | |
| ) -> tuple[Any, dict[str, Any], AutomationIR]: | |
| ir = build_set_automation_ir(tracks, order, transitions, sr=sr) | |
| audio = render_ir( | |
| ir, | |
| load_audio_segment=load_audio_segment, | |
| time_stretch_audio=time_stretch_audio, | |
| stem_resolver=stem_resolver, | |
| ) | |
| info = { | |
| "tracks": ir.metadata.get("tracks", []), | |
| "transitions": ir.metadata.get("transitions", []), | |
| "total_duration": audio.shape[-1] / sr, | |
| "automation_ir": { | |
| "clips": len(ir.clips), | |
| "lanes": len(ir.lanes), | |
| "duration_seconds": ir.duration_seconds, | |
| "component_lane_method": ir.metadata.get("component_lane_method"), | |
| "render_protection": ir.metadata.get("render_protection", {}), | |
| }, | |
| } | |
| return audio, info, ir | |