Getting Started
Install
Section titled “Install”pip install fx-dubRequires Python 3.10 or newer. Zero runtime dependencies — the package is pure standard library, so there is nothing to resolve and nothing that can break it from underneath.
Two console scripts are installed:
fxdub-receipt --help # the container receiptfxdub-dialogue --help # the content receiptYour first content check
Section titled “Your first content check”fxdub-dialogue needs two files: the scene your take was supposed to perform, and
a word-level diarized transcript of what it actually performed.
1. Write the scene. This is the contract:
{ "clip_duration_s": 10.062, "lines": [ { "speaker": "VOICE", "text": "Hey, how's it going?" }, { "speaker": "MAC", "text": "Not bad. Can't complain." }, { "speaker": "VOICE", "text": "Good to hear, good to hear." } ]}2. Transcribe the take. Any diarizing ASR works. fx-dub expects a JSON list of
words, each with text, start, end, and speaker_id:
[ { "text": "Hey", "start": 0.60, "end": 0.78, "speaker_id": "speaker_0", "type": "word" }, { "text": "how's", "start": 0.80, "end": 1.02, "speaker_id": "speaker_0", "type": "word" }]If you are on ComfyUI, vo_graphs.transcribe()
builds the graph that produces exactly this.
3. Check it:
fxdub-dialogue scene.json words.json11/11 checks pass| PASS | line_present:0:VOICE | Hey, how's it going?| PASS | line_present:1:MAC | Not bad. Can't complain.| PASS | no_invented_speech | clean| PASS | no_overlap | clean| PASS | no_internal_straggle | clean| PASS | one_voice_per_character | clean| PASS | characters_are_distinct | 2 character(s) -> 2 distinct voice(s)| PASS | fits_clip | speech ends 9.779s, clip is 10.062sChecking a single character’s stem
Section titled “Checking a single character’s stem”If you render characters as separate stems — which you often must, because many engines apply pitch and delivery knobs per node, not per speaker — check each stem against only its own lines:
fxdub-dialogue scene.json voice-words.json --only-speaker VOICEA VOICE stem should carry VOICE’s lines and silence where MAC talks. Anything
else in it is a defect, and no_invented_speech will say so.
Your first container check
Section titled “Your first container check”Download a run’s artifacts into one directory, then:
fxdub-receipt runs/my-run --bed-gain-db -12 --json receipt.jsonThe tool matches files by filename_prefix stem, whatever counter suffix your
platform appends — mix*.flac, stem_bed*.flac, stem_vo*.flac,
*_lufs*.txt, caption*.txt, dubbed*.mp4.
--bed-gain-db matters: the bed meter reads the stem pre-gain, so recovering
the delivered ducking depth needs the mix gain you applied.
Wiring it into CI
Section titled “Wiring it into CI”Both tools exit non-zero on failure, and the two failure modes are distinct:
fxdub-dialogue scene.json words.jsoncase $? in 0) echo "ship it" ;; 1) echo "the take failed its contract — read the receipt" ; exit 1 ;; 2) echo "bad invocation — check paths and speaker names" ; exit 2 ;;esac