Skip to main content

HeadVox

Turn a script into a talking‑head voiceover — with word‑aligned captions — in one command.

HeadVox reads a plain‑text or Markdown script, speaks it with a neural TTS voice, stitches the clips into a single track with natural pauses, and writes SRT + WebVTT captions that line up with the audio, plus a JSON timing manifest you can feed to a talking‑head avatar or a video editor. Point it at a video clip and it muxes the voiceover on, loops the clip to length, and attaches the subtitles.

Chinese, English and Japanese work out of the box (mixed CJK/Latin scripts segment correctly). The voices come from the free edge-tts service; HeadVox does not bundle or re‑host any model.

pip install "headvox[edge]"
headvox script.md -o out/ --voice zh-female --video avatar.mp4
# -> out/voiceover.mp3  out/voiceover.srt  out/voiceover.vtt
#    out/voiceover.json out/voiceover.mp4

Why

Making a short explainer or a "talking head" clip usually means three fiddly steps: generate the audio, hand‑time the subtitles, and mux it onto video. HeadVox does all three from one script and keeps them in sync, so the captions actually match the voice instead of drifting a few hundred milliseconds off.

Features

  • One command, three outputs — audio, captions (SRT and VTT), and a timing manifest.
  • Word‑aligned captions. With the edge backend HeadVox uses real word boundaries, then breaks lines at punctuation and a character budget (a CJK character counts as two columns) so no caption runs off screen.
  • Pacing you control. Sentence and paragraph pauses are automatic; drop [pause], [pause 1.5s] or [pause 400ms] anywhere for a beat.
  • Markdown‑aware. Headings, emphasis, links, code fences and lists are reduced to the words a narrator would actually say.
  • Pluggable backends. edge (online neural voices) and sine (offline, no network, used by the tests and for dry runs). Register your own in a few lines.
  • Caches every clip, so re‑rendering after a tiny script edit is nearly free.
  • Video muxing with optional looped, ducked background music, and either soft subtitles (toggleable) or burned‑in captions.
  • Pure‑Python, tiny deps. Only ffmpeg/ffprobe on your PATH, and edge-tts if you use the online voices.

Install

pip install "headvox[edge]"   # online neural voices
pip install headvox           # library + offline 'sine' backend only

You also need ffmpeg (with ffprobe) on your PATH — https://ffmpeg.org/download.html.

Usage

# Simplest: script in, files out
headvox talk.md -o out/

# Pick a voice and tweak the delivery
headvox talk.md -o out/ --voice en-female --rate +6 --pitch +1

# Put it on a clip, loop the clip to the voiceover length, duck some music under it
headvox talk.md -o out/ --video avatar.mp4 --music bed.mp3

# Burn captions into the picture instead of a soft track
headvox talk.md -o out/ --video avatar.mp4 --burn-subs

# See how the script will be segmented without calling any TTS
headvox talk.md --dry-run

Voice presets: zh-female, zh-male, en-female, en-male, ja-female, ja-male — or pass any edge-tts voice id directly (e.g. --voice zh-CN-YunxiNeural). Run edge-tts --list-voices to see them all. Behind a proxy? Use --proxy or set HEADVOX_PROXY.

As a library

from headvox import synthesize, Script, VoiceSettings

res = synthesize(
    Script.from_file("talk.md"),
    "out/",
    backend="edge",
    settings=VoiceSettings(voice="zh-CN-XiaoxiaoNeural", rate_pct=5),
)
print(res.duration_ms, "ms,", len(res.cues), "captions")
for cue in res.cues:
    print(cue.start_ms, cue.text)

synthesize() returns paths to the audio, SRT, VTT and manifest, the total duration, and the per‑segment word timings.

Timing manifest

voiceover.json holds everything downstream tools need to drive an avatar or re‑style captions:

{
  "tool": "headvox",
  "backend": "edge",
  "duration_ms": 19600,
  "segments": [
    {"index": 0, "text": "Hi everyone, and welcome back.",
     "start_ms": 2398, "end_ms": 4049,
     "words": [{"text": "Hi", "start_ms": 2398, "end_ms": 2560}, ...]}
  ],
  "cues": [{"index": 1, "start_ms": 262, "end_ms": 1573, "text": "HeadVox demo"}]
}

Write your own backend

from headvox.backends import SegmentAudio, WordMark, register_backend

class MyBackend:
    name = "mine"
    def synthesize_segment(self, text, settings):
        audio, fmt, dur = my_tts(text, settings.voice)   # bytes, "wav"/"mp3", ms
        return SegmentAudio(audio, fmt, dur, [WordMark("hi", 0, 200)])

register_backend("mine", lambda **kw: MyBackend())

Then headvox script.md -b mine.

How it works

  1. Parse the script to speech segments, stripping Markdown and honouring pause directives.
  2. Synthesize each segment through the chosen backend (cached by text + voice settings).
  3. Assemble one 24 kHz track, trimming the padding some engines add so your pauses are exact.
  4. Caption from the word boundaries, breaking lines at punctuation within a width budget.
  5. Mux (optional) onto video with ffmpeg, with ducked music and soft or burned‑in subtitles.

Development

git clone <your fork>
cd headvox
pip install -e ".[dev]"
pytest          # the suite runs fully offline via the 'sine' backend

License

MIT — see LICENSE. HeadVox is original work and is not affiliated with Microsoft or the edge-tts project; it simply uses edge-tts as one optional backend.

Metadata

Release files for headvox 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for headvox 0.1.0
File Size Uploaded Provenance Actions
headvox-0.1.0.tar.gz 23.0 kB Without provenance Details for headvox-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for headvox 0.1.0
File Interpreter ABI Platform Actions
headvox-0.1.0-py3-none-any.whl Python 3 none any Details for headvox-0.1.0-py3-none-any.whl

Total release size: 44.7 kB

Release files / headvox-0.1.0.tar.gz

Download URL headvox-0.1.0.tar.gz
Size 23.0 kB
Tags Source
SHA-256 checksum
How to use checksums
53412cfcd3ec4dcf3bcf831a7654535ee6114387790ccfb77659c467f176b0f9
BLAKE2b-256 checksum
How to use checksums
3ae1b7b5b0fabdf76d8b56b707979ac22daa24794e9490c9c0ef034480f8880b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / headvox-0.1.0-py3-none-any.whl

Download URL headvox-0.1.0-py3-none-any.whl
Size 21.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
05607c1cf9d6698e587fcc2bb62d30fddf32de671e83655de69cbe2a2389d9a7
BLAKE2b-256 checksum
How to use checksums
866c5e5bc9364af1ad1bfa2f49e86a913cfe26000f7b1162600ac3eec5bdfd49
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for headvox 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page