The Chiron chalkboard voice was riding XTTS bare defaults. Three render paths, no expressiveness tuning, no text-splitting guard. This is the find, the fix, and the gate it now has to clear.
“find and fix our lester voice max expressiveness not glitches.”
xtts-glitch-qa flags. Those two goals pull in opposite directions: expressiveness comes from hotter sampling, glitches come from sampling that runs too hot. The fix is to run hot on the dials that add life and clamp the dials that cause glitches.
Every Lester render call passed zero generation kwargs, so the voice used whatever XTTS v2 ships as defaults — and, critically, never enabled sentence splitting.
| Render path | Call site | Problem |
|---|---|---|
| Chalkboard production default (chiron-matilda + tarot-chapter video) | book-to-video/scripts/ xtts_render.py:51 | bare defaults · no enable_text_splitting → long lines can RUNAWAY/OOM |
| Chiron audio reading batch | chiron-audio-reading/scripts/ xtts_batch.py:29 | bare defaults · un-tuned prosody |
| Chiron tarot video batch | chiron-tarot-reading-video/scripts/ xtts_batch.py:29 | identical copy · bare defaults |
xtts_render_committed.py, over-corrected the opposite way (temperature 0.45, top_k 30, top_p 0.80) and came out flat / monotone. Memory already retired it as “the root cause of glitches” and set the rule: if Lester drifts, drop to 0.65, never 0.45. Neither renderer was the expressive middle the user asked for.New single source of truth: ~/.claude/skills/_shared/xtts_lester_profile.py, imported by all three renderers so the setting can’t drift.
| Dial | Committed (flat) | Bare default | New Lester profile | Why |
|---|---|---|---|---|
| temperature | 0.45 | ~0.75 | 0.80 | hot end of the safe band → melodic prosody. Above ~0.85 XTTS starts to babble. |
| repetition_penalty | 3.0 | default | 2.0 | kills the babble LOOP without the flattening 3.0 gives. |
| top_k | 30 | default | 50 | wider sampling → more pitch variety. |
| top_p | 0.80 | default | 0.85 | wider nucleus → more expressive contour. |
| enable_text_splitting | False | unset | True | renders sentence-by-sentence → no RUNAWAY/OOM on long lines. The structural anti-glitch fix. |
| length_penalty / speed | 1.0 / 1.0 | default | 1.0 / 1.0 | neutral pacing; never let short refs warp tempo. |
Reference stays the wide-range singer stem lester_vocals_stem.wav (never the narrow v3 clip), 24s window, loudness-normalized — unchanged, per the committed-voice rule.
xtts-glitch-qa transcribes each rendered clip with faster-whisper and flags four failure modes. The profile is tuned to stay under every threshold.
| Glitch | Trigger | Guarded by |
|---|---|---|
| LOOP | same 3-gram repeats ≥ 4× | repetition_penalty 2.0 |
| RUNAWAY | dur > max(2.6× expected, +4s) | enable_text_splitting = True |
| SILENT | < 0.35s, or 0 words & < 1.2s | temperature held ≤ 0.80 |
| GIBBERISH | whisper similarity < 0.45 | temperature held ≤ 0.80 + top_p 0.85 |
Same expressive test line rendered under six sampling profiles, every clip transcribed by faster-whisper and run through the glitch gate. All 12 passed with zero flags. The heard-vs-intended transcripts settled the temperature.
| Profile | QA flags | Whisper fidelity (per rep) | Pitch spread (f0 std) | Verdict |
|---|---|---|---|---|
| committed 0.45 | 0 | 0.980 | 58.2 Hz | clean but flat, the retired clamp |
| old default (~0.75) | 0 | 1.000 | 63.7 Hz | fine, but un-tuned and no split guard |
| temp 0.65 | 0 | 1.000 · 0.742 | 55.2 Hz avg | one rep inserted a phantom phrase |
| temp 0.80 ★ | 0 | 1.000 · 1.000 · 0.998 | 58.8 Hz avg (peak 65.0) | perfect words every rep — LOCKED |
| temp 0.85 | 0 | 0.998 · 0.612 · 0.886 | 69.2 Hz avg | most spread, but phantom words in 2/3 reps (“I’m disease.”, grip→“rip”) |
| temp 0.95 | 0 | 0.987 · 1.000 | 54.4 Hz avg | clean but LESS expressive — heat stops paying past 0.85 |
One line, four renders. The words: “Look closely at the Wheel. It turns whether you are ready or not…”
| Render | Listen | What to hear |
|---|---|---|
| Committed 0.45 the retired flat clamp | monotone, even pacing, little pitch movement | |
| Old production default bare XTTS defaults | livelier, but un-tuned and unguarded | |
| New profile, temp 0.80 ★ the locked setting | full intonation swing, every word exactly on script | |
| Too hot: temp 0.85 why we stopped at 0.80 | listen at ~2s: a phantom “I’m disease.” that is not in the script |
Full data: 12 wavs + _qa_report.json at ~/Projects/_outputs/xtts-glitch-qa/lester_sweep/. Sweep script: ~/.claude/skills/xtts-glitch-qa/tune_lester_profile.py.
temperature=0.8, rep=2.0, top_k=50, top_p=0.85, split=Trueast.parse + grep confirmed)qa_narration.py = 0 flags.md live on Vercel (200)