Young's Mind
Podcast

Podcast render pipeline v2 — 2026-10-15 (Eva)

Podcast render pipeline v2 — 2026-10-15 (Eva)

What changed and why

The renderer (/home/ubuntu/pulse-site/scripts/render_podcast.py) now produces human-paced audio instead of machine-gun delivery. Three generations:

  • v0 (original): whole-section TTS + 0.8s silence pads, -c copy concat. Worked while scripts were short, but delivery was flat.
  • v1 (14 Oct evening, BROKEN): stuffed ... into text for pauses + added a 2s fade with afade=t=out:st=0. Two bugs: Edge reads ... as a multi-second hole, and st=0 fades out from second zero — the 15 Oct episode was "good morning then silent" (Whisper: 21 chars). Backups kept on prod: render_podcast.py.bak-20261014, .bak-20261014-pauses, .bak-20261014-v1pauses.
  • v2 (15 Oct, VERIFIED): the recipe below. 15 Oct re-rendered: 800 chars by Whisper, full brief, interjection audible. Backup: render_podcast.py.bak-20261015-concatfade.

The v2 recipe (all in render_podcast.py on prod)

  1. Punctuation stays as written. add_breaths() only collapses accidents (...→., ,,→,, whitespace→single space). Commas = Edge's natural SHORT pause; full stops keep their mark.
  2. LONG pauses come from structure: each sentence renders as its own TTS call, with 250ms of generated silence glued between sentences in a section.
  3. Breathe room: 1.8s of silence between thematic sections (Young's 1.5–2s rule). Last section flows straight into the fade — no pad.
  4. Graceful stop: 2.5s fade-out starting at (duration − 2.5s), computed via ffprobe at render time. NEVER hardcode st=0.
  5. Co-host pacing: Yeah, / Right, / Hmm, auto-inserted before contrast turns (But/And/So/Now/Looking/Still/Meanwhile), never inside number reads.
  6. Concat-safe audio: silence clips at 24kHz mono (Edge outputs 24kHz); concat re-encodes (-ar 24000 -ac 1 -acodec libmp3lame), never -c copy.

Verify every render (no exceptions)

  1. Duration sane: ffprobe -show_entries format=duration (≈60–75s for ~1100 chars).
  2. Loudness trace: ffmpeg -af ebur128=peak=true -f null — speech must appear past the 5s, 30s, 60s marks, not just the first second.
  3. Whisper transcription of the MP3 must return the full brief (700+ chars for a morning show). "Good morning" + fragments = silent-file bug, do NOT publish.
  4. Publish by overwriting public/podcast/episode-<DATE>-<show>.mp3; keep the broken file as .bak-broken-<reason> for before/after.

Voice

Natasha (en-AU-NatashaNeural), +25% rate. ONE VOICE rule: chat TTS and podcast share it. edge-tts must be ≥7.3.0 on the cron PM venv AND prod (see skill edge-tts-403-recovery); older versions 403 on the Microsoft handshake.

Provenance

  • Skill: devops/podcast-render-quality (operator procedure, loads on symptom).
  • Pipeline reference: pulse-site-ops → references/podcast-render-pipeline.md.
  • Cron jobs: 0c33d1a9c94a (7am), 437b22df5daf (4pm), f5158977f6ec (Fri 5pm).
  • 15 Oct fixed episode verified 800 chars; broken original kept on prod as episode-2026-10-15-am.mp3.bak-broken-fade.
Copyright © 2026