Open-source voice-cloning voiceover pipeline

Turn a voice sample and a Markdown script into organized narration.

ses renders a cloned voice section by section, automatically retries suspicious takes, optionally enhances the result, and delivers editable WAVs plus one complete render.

  • Local Python CLI
  • Qwen3-TTS
  • LavaSR
  • MIT licensed
input Voice sample + transcript ICL cloning, or audio alone
input Markdown script Timestamped sections
process Quality-gated pipeline Your pacing & thresholds
output Section WAVs + full.wav Every section is editable

Bring any voice sample and any script. Pair the sample with a transcript for ICL cloning, tune the pacing to your project, and keep every section as a separate deliverable.

Built for narration work

Not just a text-to-speech demo.

garble gate

Retry the bad takes

A sustained loud-burst detector catches likely garbling per chunk and re-rolls it within a configurable retry budget.

pause gate

Catch dead air

Over-long internal silences trigger a section-level re-render before the take is ever accepted.

raw / enhanced

Enhance without losing the clean take

LavaSR post-processing is optional. If it injects high-frequency hash, the enhanced result is discarded and the raw take is kept.

--slide N

Iterate one section at a time

Revise a single part with --slide N instead of re-rendering the entire script. Indexes are zero-based.

The signal path

From Markdown to final voiceover.

The orchestration is one line in ses/pipeline.pyparse → chunk → synth → gate → enhance → level → concat. Two stations can send the signal backwards.

  1. 01
    Parse Timestamped sections from Markdown
  2. 02
    Chunk Sentences sized for stable prosody
  3. 03
    Synth Qwen3-TTS clones each chunk
  4. 04 ↺ re-roll / re-render
    Gate Garble re-roll · dead-pause re-render
  5. 05 ↺ reject added hash
    Enhance LavaSR, or keep the raw take
  6. 06
    Level Loudness leveling across sections
  7. 07
    Concat Section WAVs + full.wav
forward signal retry loop

Authoring

Write narration in plain Markdown.

Timestamped headings become named audio files. Blockquotes become narration. Blank quoted lines create longer paragraph pauses. Leave TODO, REDO, or WIP markers in place — ses skips them.

script.md
## 0:00 — Welcome

> Welcome to ses, a voiceover pipeline. This tool turns a
> written script into narrated audio using a short sample
> of your own voice.
>
> You write in plain markdown, drop in a voice sample, and
> get back one WAV per section plus a single render.

## 0:20 — How it works

> Each section is split into sentences and synthesized one
> sentence at a time, which keeps the prosody stable.
>
> TODO tighten the pacing note here
audio/20260720-143000/
audio/20260720-143000/
├─ slide-00-welcome.wav       § 0:00
├─ slide-01-how-it-works.wav  § 0:20
├─ slide-02-getting…wav       § 0:45
├─ slide-02-getting….raw.wav raw take kept
└─ full.wav                    every section, joined

Your first render

Three commands to a full run.

Put my_voice.wav in in/. Add my_voice.txt with the clip transcript to enable ICL cloning. Model weights download on the first render; later runs can work offline.

Useful controls

--dry-runParse and print — no models, no audio.
--slide 2Render a single section (zero-based).
--no-enhanceRender without LavaSR enhancement.
--samples-dirPoint at any folder of voice samples.
zsh — first render
# 1 · install dependencies
$ pip install -r requirements.txt
# qwen-tts shells out to the SoX executable
$ brew install sox

# 2 · drop in/my_voice.wav (+ optional in/my_voice.txt)
#     then render your script
$ python -m ses --script script.md --sample my_voice

# iterate on just section 2, no enhancement
$ python -m ses --script script.md --sample my_voice \
    --slide 2 --no-enhance

For developers

Small modules. Explicit seams. No plugin magic.

Parsing, chunking, DSP, and quality gates stay importable with numpy alone. Heavy model libraries are isolated inside adapters. Use the whole pipeline, pass your own engine to run_pipeline, or copy only the modules your project needs.

  • Frozen PipelineConfig — every tunable in one place.
  • Tiny Protocols for parsers, TTS engines, and enhancers.
  • No global state, no engine auto-discovery.
  • Pure-numpy tests with synthetic tones, bursts, and silence.

Take the pipeline — or just the useful parts.

Need only trim, fade, normalize, garble detection, or pause detection? The pure audio modules copy into another project without torch, Qwen3-TTS, LavaSR, or the orchestration layer.

copy-out
$ mkdir -p yourproject/audio
$ cp ses/audio/__init__.py \
     ses/audio/dsp.py ses/audio/quality.py \
     yourproject/audio/
$ pip install numpy

The honest part

A local developer tool with a deliberate engine stack.

ses runs Qwen3-TTS locally on Apple MPS or CPU and uses LavaSR for optional enhancement. The quality gates are tuned to this stack — you can replace an adapter, but a different engine will usually need different gate thresholds. It is an early-stage, developer-oriented reference pipeline, not a hosted product.

  • Python
  • SoX for rendering
  • Local model weights
  • Apple MPS or CPU
  • Command-line workflow

Give your script a voice —
one section at a time.

Start with a reference clip, write the narration in Markdown, and let ses render, check, enhance, and assemble the take.