Version: 0.1 (draft) Owner: Single-operator / personal tool Target hardware: Windows 10/11, NVIDIA RTX 3090 (24 GB VRAM)
A single-operator local tool (Gradio UI in the browser, runs 100% locally on an RTX 3090) that turns a song + metadata + optional lyrics into a YouTube-ready music video.
Inputs:
- An audio file (MP3 / WAV / FLAC)
- Song metadata (artist, title, album, year, genre)
- A logo PNG (optional, transparent background)
- Lyrics text (optional, one line per lyric line)
- Visual style selection: reactive shader (including none / passthrough), per-shader scene prompt text, typography + palette bundled in code (
pipeline/visual_style.py; optional YAML overrides still supported)
Outputs (written to outputs/<run_id>/):
output.mp4— 1080p, 30 fps, H.264 NVENC, original audio muxed inthumbnail.png— 1920×1080 cover framemetadata.txt— suggested YouTube title, description (with chapter timestamps if detected), tags
Target render time: under 3× song length end-to-end on the 3090 (e.g. a 3-minute song in under 9 minutes), dominated by AI background generation. Non-AI reactive-only renders should run faster than real-time.
flowchart TD
UI["Gradio UI (app.py)"] --> Orch[Orchestrator]
Orch --> Audio[Audio Analyzer]
Orch --> Lyr[Lyrics Aligner]
Orch --> BG[Background Generator]
Orch --> Reactive[Reactive Overlay Layer]
Orch --> Typo[Kinetic Typography Layer]
Audio -->|"beats, onsets, spectrum, RMS"| Reactive
Audio -->|"vocal stem"| Lyr
Lyr -->|"word timings"| Typo
BG --> Comp[Compositor]
Reactive --> Comp
Typo --> Comp
Logo[Logo PNG] --> Comp
Comp -->|"raw RGB frames via stdin"| FF["ffmpeg NVENC"]
Audio2[Original audio] --> FF
FF --> MP4["output.mp4"]
Comp --> Thumb[Thumbnail picker]
Thumb --> PNG["thumbnail.png"]
Orch --> Meta["metadata.txt"]
Single-page layout, sections:
- Audio: file upload, waveform preview, play/scrub.
- Metadata: artist, title, album, year, genre, BPM (auto-filled after analyze, editable).
- Branding: logo upload, logo position (4 corners / center), logo opacity slider.
- Lyrics: large textarea (paste raw lyrics, one line per lyric line), checkbox "Enable kinetic typography".
- Visual style:
- Reactive shader dropdown: No reactive shader,
void_ascii_bg,spectral_milkdrop,tunnel_flight,synth_grid; each bundles default scene prompt text, typography style, palette, motion flavor (style-<stem>ids for cache/metadata). - Scene prompt text field (AnimateDiff/stills backgrounds; prefilled per shader; empty falls back to the bundle example).
- Background mode:
AI stills (fast),AI animated (AnimateDiff, slow),Static image upload. - Reactive intensity slider (0–100%).
- Reactive shader dropdown: No reactive shader,
- Output: resolution (1080p default, 4K optional), fps (30/60), filename prefix.
- Actions:
Analyze— quick (~10 s): runs audio analyzer only, populates BPM, waveform.Preview 10 s— renders a 10 s sample from the loudest / chorus section.Render full video— the main action.
- Progress panel: per-stage progress bars, live ETA, scrolling log tail.
- Load via
soundfile/librosaat 44.1 kHz mono mixdown for analysis (keep stereo original for mux). - Tempo + beat grid:
BeatNet(preferred, ML-based, accurate on modern music) withmadmomfallback. - Onset detection:
librosa.onset.onset_strength→ peaks for drum hits. - Spectral bands: 8-band log-mel energy per frame at target fps (30/60 Hz) feeding the reactive shader.
- RMS / loudness envelope for global pulsing.
- Vocal separation:
demucs(htdemucs_ft model) →vocals.wavused by the aligner and for vocal-reactive FX. - Structural segmentation (
librosa.segment) → section boundaries for chapters and background keyframe planning. - Key/chord detection (stretch): drives color palette shifts.
Results cached as cache/<song_hash>/analysis.json + stem WAVs so re-renders skip analysis.
- Input: user-pasted lyrics (plain text) +
vocals.wav. WhisperX(large-v3) with word-level timestamps on the vocal stem.- Alignment: map pasted lyrics to WhisperX word tokens via Needleman–Wunsch / DTW on normalized text, carrying timestamps across so the user's exact spelling/punctuation is preserved.
- Output: list of
{word, line_idx, t_start, t_end}incache/<song_hash>/lyrics.aligned.json. - Manual correction pass in UI (stretch): timeline view, drag to shift.
- AI stills mode (default): generate
N = ceil(duration / 8 s)SDXL keyframes using the scene prompt resolved from Visual style (+ optional YAML preset when used), interpolate between them withFILMor simple crossfades synced to section boundaries. Each image 1920×1080, upscaled if needed. Runs indiffuserspipeline with FP16 on the 3090. - AnimateDiff mode: short motion loops (~2 s) generated per section, looped/crossfaded. Heavier VRAM/time but true motion.
- Static image mode: use uploaded image with subtle Ken-Burns + parallax based on RMS envelope.
Results cached in cache/<song_hash>/background/.
- GPU shader pass via
moderngl(OpenGL, offscreen FBO) — draws on top of the background frame. - Uniforms per frame:
time,beat_phase,band_energies[8],rms,onset_pulse. - Shader library in
assets/shaders/: bundled reactive fragments listed inpipeline/builtin_shaders.py(void_ascii_bg,spectral_milkdrop,tunnel_flight,synth_grid);noneskips the GL pass so only the diffusion/static background shows through (plus typography, logo, FX). - Rendered at target resolution, alpha-composited onto background.
- Rendered with
skia-python(fast, high-quality text with shadows / strokes / gradients). - Driven by
lyrics.aligned.json. - Per-word motion presets:
pop-in,beat-shake,scale-pulse,slide,flicker. - Line layout: centered lower-third by default, auto-resize to fit safe area, previous line fades as next starts.
- Font: bundled open-license display font (defaults via
CompositorConfig; override in UI/config). - Rendered as RGBA at target resolution, composited on top of the reactive layer.
- Frame loop runs at target fps. For each frame index:
- Pull/interpolate background RGB frame.
- Blend reactive RGBA.
- Blend typography RGBA.
- Blend logo RGBA (fixed).
- Write raw BGR to
ffmpegstdin.
ffmpegcommand:ffmpeg -f rawvideo -pix_fmt bgr24 -s WxH -r FPS -i - \ -i <audio> \ -c:v h264_nvenc -preset p5 -rc vbr -cq 19 -b:v 12M \ -c:a aac -b:a 192k -shortest output.mp4- Parallelism: background gen, reactive render, and typography render can each run on separate CUDA streams; frame pipeline uses a bounded queue so the encoder never starves.
- Thumbnail: pick the frame at the first chorus downbeat (or loudest 1-s window), overlay a big-text treatment of
Artist — Titleusing the same typography/color bundle as the run. Save asthumbnail.png1920×1080. - metadata.txt:
- Title:
{Artist} — {Title} [Official Visualizer] - Description: song info + optional lyric block + "Generated with Glitchframe" line.
- Tags: genre, artist, title, "music visualizer", plus tags derived from visual style (
preset_id, shader stem, hyphen segments). - Chapters (if instrumental sections detected):
00:00 Intro,00:32 Verse 1, etc.
- Title:
- Language: Python 3.11
- GPU runtime: CUDA 12.x, PyTorch 2.x (FP16/BF16)
- Audio:
librosa,soundfile,BeatNet(ormadmom),demucs,whisperx - Diffusion:
diffusers, SDXL base+refiner, optionally AnimateDiff - Graphics:
moderngl(shaders),skia-python(typography),Pillow/numpy(utility) - UI:
gradio4.x - Encoding: system
ffmpegwith NVENC (h264_nvenc) - Packaging:
uvorpip+requirements.txt;.envfor model cache paths
glitchframe/
├── app.py # Gradio entrypoint
├── config.py # Defaults, paths; optional presets dir
├── orchestrator.py # Pipeline coordinator
├── pipeline/
│ ├── audio_analyzer.py
│ ├── lyrics_aligner.py
│ ├── background_gen.py
│ ├── reactive_layer.py
│ ├── lyric_layer.py
│ ├── compositor.py
│ ├── thumbnail.py
│ ├── metadata.py
│ ├── visual_style.py # Shader bundles & style-* ids
│ └── renderer.py
├── presets/ # Optional YAML overrides (empty by default).
├── assets/
│ ├── shaders/
│ └── fonts/
├── cache/ # analysis + stems + backgrounds (per-song hash)
├── outputs/ # MP4 + PNG + TXT per run
├── requirements.txt
└── README.md
- M1 — Skeleton + audio analysis: Gradio shell, upload, BeatNet + spectrum + RMS, render a plain 1080p video with a simple spectrum visualizer overlaid on a solid color, ffmpeg NVENC piping, audio muxed in. Proves the render pipeline end-to-end.
- M2 — Reactive shader layer:
moderngloffscreen rendering, bundled reactive shaders (+ optionalnonepassthrough), optional YAML presets, logo compositing, thumbnail + metadata generation. - M3 — Lyrics alignment + typography: Demucs + WhisperX + alignment, Skia typography layer with 3 motion presets.
- M4 — AI background (stills): SDXL integration, keyframe prompt planning from song sections, interpolation, caching.
- M5 — Polish: AnimateDiff mode (optional), 4K support, preview-10s fast path, shader/visual-style tweaks, error handling + resumable renders.
Each milestone produces a usable tool; scope can stop at any milestone if priorities shift.
- WhisperX vs NeMo Forced Aligner: WhisperX is simpler; if alignment quality on sung vocals is poor, fall back to aeneas or MFA with a phoneme model.
- AnimateDiff VRAM: may require tiled / low-res generate + upscale on the 3090 at 1080p; easier to generate at 720p and upscale.
- Font licensing: ship only open-license fonts; provide a "use system font" option.
- Gradio + long renders: use background jobs + polling; Gradio's queue handles this, but we must stream progress correctly.
- Audio/video drift: NVENC piping must honor
-rexactly; validate withffprobeafter each render. - First-run model downloads: SDXL + Whisper large-v3 + Demucs together ≈ 20+ GB on disk; document this clearly in README.
- No automatic upload to YouTube (explicitly out of scope; metadata file only).
- No multi-song batch queue in v1 (easy to add later).
- No cloud rendering; 100% local on the 3090.
- No stem-based remixing of the song itself.
- No mobile / vertical (Shorts) aspect ratio in v1 — 16:9 only.