Spaces:
Sleeping
Sleeping
File size: 6,142 Bytes
a2d9995 f02c67e a2d9995 f02c67e a2d9995 f02c67e a2d9995 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | from __future__ import annotations
import json
import tempfile
import gradio as gr
import numpy as np
import soundfile as sf
from app_state import app_state
def render_full_set(max_iter, progress=gr.Progress()):
"""Render the DJ set through the AutomationIR full-set renderer."""
if not app_state.transitions:
return None, "⚠️ Generate a set plan first"
import app as core
progress(0.05, desc="Compiling full-set AutomationIR...")
from render_engine import render_full_set as render_full_set_shared
from stem_provider import StemProvider
stem_provider = StemProvider()
set_audio, set_info, ir = render_full_set_shared(
app_state.analyses,
app_state.set_order,
app_state.transitions,
load_audio_segment=core.load_audio_segment,
time_stretch_audio=core.time_stretch_audio,
stem_resolver=stem_provider.resolver(),
sr=44100,
)
app_state.last_stem_diagnostics = dict(stem_provider.diagnostics)
app_state.rendered_set = set_audio
progress(0.82, desc="Running diagnostics...")
benchmarks = core.run_benchmarks(app_state.analyses, app_state.transitions, set_audio)
benchmark_text = core.format_benchmarks(benchmarks)
progress(0.95, desc="Saving audio...")
tmp = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
audio_for_save = set_audio.T if set_audio.ndim == 2 else set_audio
if audio_for_save.ndim == 2 and audio_for_save.shape[1] > audio_for_save.shape[0]:
audio_for_save = audio_for_save.T
audio_for_save = np.clip(audio_for_save, -1.0, 1.0)
sf.write(tmp.name, audio_for_save.astype(np.float32), 44100)
summary = "# ✅ DJ Set Rendered via AutomationIR\n\n"
summary += f"- **Total duration:** {set_info['total_duration']:.1f}s ({set_info['total_duration']/60:.1f} min)\n"
summary += f"- **Tracks:** {len(set_info['tracks'])}\n"
summary += f"- **Transitions:** {len(set_info.get('transitions', []))}\n"
summary += f"- **AutomationIR:** {set_info['automation_ir']['clips']} clips, {set_info['automation_ir']['lanes']} lanes\n"
summary += f"- **Stem lane method:** `{set_info['automation_ir'].get('component_lane_method', 'n/a')}`\n\n"
summary += "## Tracklist\n"
for i, t in enumerate(set_info["tracks"]):
summary += f"{i+1}. **{t['filename']}** — tl={t['tl_start']:.1f}s\n"
if set_info.get("transitions"):
summary += "\n## Transitions Applied\n"
for i, t in enumerate(set_info["transitions"], start=1):
score = t.get("score_breakdown", {}).get("overall", "n/a")
summary += f"- **{i}. `{t['type']}`**: {t['track_a']} → {t['track_b']} / score={score}\n"
summary += "\n## AutomationIR preview\n"
summary += "```json\n" + json.dumps(ir.to_dict(), indent=2)[:8000] + "\n```\n"
summary += f"\n{benchmark_text}"
return tmp.name, summary
def render_single_transition(transition_idx, candidate_rank=0, progress=gr.Progress()):
"""Preview a selected or alternative transition candidate via AutomationIR."""
if not app_state.transitions:
return None, "⚠️ Generate a set plan first"
import app as core
idx = int(transition_idx) - 1
if idx < 0 or idx >= len(app_state.transitions):
return None, f"⚠️ Invalid transition index. Choose 1-{len(app_state.transitions)}"
rank = max(0, int(candidate_rank or 0))
trans = app_state.transitions[idx]
track_a = app_state.analyses[trans.track_a_idx]
track_b = app_state.analyses[trans.track_b_idx]
progress(0.15, desc="Compiling automation IR...")
from render_engine import render_transition_preview
from stem_provider import StemProvider
stem_provider = StemProvider()
audio, ir, candidate = render_transition_preview(
trans,
track_a,
track_b,
candidate_rank=rank,
load_audio_segment=core.load_audio_segment,
time_stretch_audio=core.time_stretch_audio,
stem_resolver=stem_provider.resolver(),
sr=44100,
)
app_state.last_stem_diagnostics = dict(stem_provider.diagnostics)
progress(0.85, desc="Saving preview...")
tmp = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
sf.write(tmp.name, audio.T, 44100)
cue_source = "selected plan" if rank == 0 or not candidate else f"alternative #{rank}"
edge_score = None
if candidate:
edge_score = candidate.get('score')
else:
edge_score = trans.score_breakdown.get('overall')
from transition_diagnostics import diagnose_transition_audio, format_transition_diagnostics
diag = ir.metadata.get("rendered_diagnostics") or diagnose_transition_audio(audio, sr=44100, anchor_seconds=ir.anchor_seconds)
rendered_scores = ir.metadata.get("rendered_candidate_scores", {})
stem_diag = json.dumps(app_state.last_stem_diagnostics, indent=2)[:2500] if app_state.last_stem_diagnostics else "{}"
info = (
f"**Transition {idx+1}:** {track_a.filename} → {track_b.filename}\n"
f"**Candidate:** {cue_source}\n"
f"**Type:** `{getattr(ir, 'transition_type', trans.transition_type)}`\n"
f"**Automation IR:** {len(ir.clips)} clips, {len(ir.lanes)} lanes, anchor={ir.anchor_seconds:.2f}s\n"
f"**Cue timing:** A out {ir.metadata['mix_out_point']:.2f}s, "
f"B in {ir.metadata['mix_in_point']:.2f}s, B drop {ir.metadata['b_drop']:.2f}s\n"
f"**Duration:** {ir.metadata['duration_seconds']:.2f}s; score={edge_score if edge_score is not None else 'n/a'}\n"
f"**Tempo policy:** ×{float(ir.metadata.get('bpm_adjustment', 1.0) or 1.0):.3f}; "
f"{(getattr(trans, 'tempo_policy', {}) or {}).get('reason', 'source tempo unless explicitly forced')}\n"
f"**Preview file duration:** {audio.shape[-1] / 44100:.1f}s\n\n"
f"**Rendered candidate scores:** `{json.dumps(rendered_scores)}`\n\n"
f"{format_transition_diagnostics(diag)}\n\n"
f"### Stem provider diagnostics\n```json\n{stem_diag}\n```\n\n"
f"```json\n{json.dumps(ir.to_dict(), indent=2)[:6000]}\n```"
)
return tmp.name, info
|