Spaces:
Sleeping
Sleeping
| 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 | |