---
name: "voiceover-production"
description: "Take a voiceover from script to delivery-ready audio: script pacing prep, mic technique and gain staging for a clean record, cleanup with ffmpeg (noise reduction, high-pass), and two-pass EBU R128 loudness mastering to platform targets. Triggers on requests to record, clean up, master, or produce voiceover / VO / narration audio."
metadata: { "includeInPrompt": true }
---

# Voiceover Production

## Purpose

Turn a script into finished, platform-ready voiceover: prep the script for
pacing, record a clean take, then run a deterministic ffmpeg chain —
cleanup → master → verify — so the file lands at the destination's loudness
spec instead of "sounds about right."

## Workflow

1. **Prep the script.** Copy `assets/script-template.md` and format the read:
   pacing marks, breath marks, emphasis, and phonetic spellings. Do a timed
   read of the first paragraph — runtime estimates come from a real sample,
   never from a guessed words-per-minute rate. (`bin/vo-master.py estimate`
   turns a finished script file into a runtime range.)
2. **Record.** See `references/recording-guide.md`: mic distance/angle,
   pop filter, gain staging targets, room discipline, and record format
   (PCM WAV, 48 kHz / 44.1 kHz, 24-bit if the interface offers it).
3. **Master.** Run the cleanup + loudness chain in one command:
   ```bash
   python3 bin/vo-master.py master raw-take.wav final.wav --target -16 --denoise 12
   ```
   What it does, in order: high-pass at 80 Hz → FFT noise reduction with
   adaptive floor tracking → DC-offset removal → two-pass measured
   `loudnorm` (EBU R128) → true-peak ceiling → PCM/WAV or MP3 export →
   independent `ebur128` verification. Full recipe table and every flag are
   documented in `references/ffmpeg-vo-recipes.md`.
4. **Audit before you ship.** Use `--audit-noise` to hear exactly what the
   denoiser removed (it must be hiss/hum, never sibilance or breath).
   Read the JSON report: integrated LUFS vs target, true peak vs ceiling,
   and the loudness range. Re-record beats over-processing — denoising past
   ~15 dB or aggressive compression leaves artifacts no master fixes.
5. **Deliver.** Match the export to the destination's spec (target table in
   `references/ffmpeg-vo-recipes.md`); keep the raw WAV archived.

## Output Contract

A finished take is a file plus its verification report:

- Audio file at the destination's loudness target (default −16 LUFS
  integrated, stereo) with true peak under the ceiling (−1.5 dBTP).
- JSON report from `vo-master.py`: `input`, `output`, `target_lufs`,
  `measured_integrated_lufs`, `measured_true_peak_dbtp`,
  `loudness_range_lu`, `denoise_db`, `pass` (boolean).
- The raw recording is untouched and archived alongside the master.

## Operating Rules

1. **No confident unverified claims.** Every number in this skill (targets,
   distances, levels) comes from the sources in
   `~/workspace/skill-production/scratch/voiceover-production-sources.md`.
2. **Measure, don't guess.** Run the two-pass loudnorm and the `ebur128`
   verification; "turned it up a bit" is not a master.
3. **Cleanup before compression.** Noise reduction and high-pass run before
   loudness gain — amplifying noise, then trying to remove it, fails.
4. **Short/silent inputs are flagged, not boosted.** If measured integrated
   loudness sits near the −70 LUFS gate floor, the CLI refuses to amplify;
   re-check the input instead.
5. **Over-processing is a defect.** If the audit reveals voice artifacts,
   reduce `nr` or re-record. A clean quiet take mastered up beats a noisy
   take scrubbed down.
