Add F5-TTS as tts-1-f5 engine (additive, alongside tts-1-qwen)

This commit is contained in:
russell@unturf.com 2026-05-23 13:24:25 -04:00
parent bfc5260dfc
commit 2df34f85cc
No known key found for this signature in database
6 changed files with 511 additions and 5 deletions

View file

@ -3,7 +3,7 @@
CONTAINER_NAME ?= uncloseai-speech-server-1
.PHONY: help deploy restart logs test clean stop start voices voices-qwen voices-piper voices-xtts voices-kokoro test-kokoro voices-silero test-silero voices-chatterbox test-chatterbox push-all hydrate load-test test-qwen venv venv-run local local-cpu
.PHONY: help deploy restart logs test clean stop start voices voices-qwen voices-piper voices-xtts voices-kokoro test-kokoro voices-silero test-silero voices-chatterbox test-chatterbox push-all hydrate load-test test-qwen test-f5 venv venv-run local local-cpu
help:
@echo "Raccoon TTS Mission - Development Commands"
@ -24,6 +24,7 @@ help:
@echo "Testing:"
@echo " make test - Test TTS endpoint (Qwen3-TTS)"
@echo " make test-qwen - Test Qwen3-TTS voice cloning"
@echo " make test-f5 - Test F5-TTS voice cloning"
@echo " make hydrate - Test all configured voices"
@echo " make load-test - Concurrent load test"
@echo ""
@ -118,6 +119,15 @@ test-qwen:
@echo ""
@echo "Saved to /tmp/qwen_test.mp3"
test-f5:
@echo "Testing F5-TTS endpoint..."
curl -X POST http://localhost:8000/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{"model":"tts-1-f5","voice":"aria","input":"Raccoon mission TTS test with F5 flow matching"}' \
-o /tmp/f5_test.mp3
@echo ""
@echo "Saved to /tmp/f5_test.mp3"
test-kokoro:
@echo "Testing Kokoro fast synthesis..."
curl -X POST http://localhost:8000/v1/audio/speech \

View file

@ -125,6 +125,66 @@ make test-qwen # Test Qwen3-TTS explicitly
---
### F5-TTS ✅ (also enabled by default)
**Status:** INTEGRATED as tts-1-f5 (additive, alongside tts-1-qwen)
**Project:** SWivid/F5-TTS (community-maintained, gated HuggingFace checkpoint)
**License:** MIT (model + code)
**Model:** F5-TTS_v1
**Why Integrated:**
- Empirical benchmark (Richard, 2026-05-23): faster inference + better voice clones than Qwen3-TTS on the same reference clips
- Smaller model (~336M params vs Qwen3-TTS 1.7B) — lower VRAM, fits comfortably on modest GPUs
- Flow-matching architecture, zero-shot cloning, no fine-tuning needed
- 24kHz output, matches Qwen3-TTS sample rate (drop-in voice swap for clients)
**Model Specs:**
- Parameters: ~336M
- Sample Rate: 24kHz
- Input: Text + Reference Audio (3+ seconds) + Reference Transcript
- Languages: English (primary); community fine-tunes available for others
- Size: ~1.5GB (F5-TTS_v1 + Vocos vocoder)
**Model Source:**
- HuggingFace: `SWivid/F5-TTS` (**gated** — accept license at https://huggingface.co/SWivid/F5-TTS)
- Auto-downloaded on first use; requires `HF_TOKEN` env var
**Integration:**
- Used for `tts-1-f5` model (additive default)
- Voice cloning with `ref_audio` + `ref_text` (same shape as tts-1-qwen)
- Reuses the same 40 LibriSpeech voices as tts-1-qwen
**Example Config:**
```yaml
tts-1-f5:
aria:
ref_audio: cloned-voices/aria.wav
ref_text: "BUT THE WINDOWS ARE PATCHED WITH WOODEN PANES AND THE DOOR I THINK IS LIKE THE GATE IT IS NEVER OPENED"
language: English
```
**Tuning Knobs (engine-specific, not OpenAI-compatible):**
- `nfe_step` (default 32) — ODE step count; higher = better quality, slower
- `cfg_strength` (default 2.0) — classifier-free guidance strength
- `speed` (default 1.0) — pitch-preserving speed multiplier
- Does NOT support `temperature` / `top_p` / `top_k` (flow-matching, not autoregressive)
**Makefile Targets:**
```bash
make test-f5 # Test F5-TTS voice cloning
```
**Hardware Requirements:**
- GPU: NVIDIA with 4GB+ VRAM (lighter than Qwen3-TTS)
- CPU: Works but many× realtime
- MPS (Apple Silicon): supported, ~1.52× realtime per VoiceClone benchmarks
**Source of Inspiration:** [MonumentalSystems/VoiceClone](https://github.com/MonumentalSystems/VoiceClone) — a single-file F5-TTS web app that proved the engine on our reference workload. Our wrapper mirrors their `F5TTS.infer()` call pattern.
**Raccoon Priority:** ⭐⭐⭐⭐⭐ (Empirically beats current default, MIT, lower VRAM)
---
### 1. Piper TTS (disabled by default) ✅
> 📖 **See [detailed documentation](models/piper-tts.md)** for comprehensive technical specs and integration guide

View file

@ -4,6 +4,11 @@ loguru
# Qwen3-TTS - state-of-the-art TTS with voice cloning (Apache 2.0)
# 1.7B params, 10 languages, 97ms latency, 12Hz tokenizer
qwen-tts>=0.0.5
# F5-TTS - flow-matching zero-shot voice cloning (MIT, SWivid/F5-TTS)
# 336M params, 24kHz output, no fine-tuning needed
# Checked 2026-05-23: 1.1.20 is latest stable
# Note: gated checkpoint on HuggingFace; requires HF_TOKEN env var + license accept
f5-tts==1.1.20
# OHF-Voice fork doesn't have installable Python package yet
# Stick with PyPI piper-tts but use absolute paths in config
# piper-tts>=1.2.0

View file

@ -9,4 +9,9 @@ WORKERS=1
#PRELOAD_MODEL=xtts
#PRELOAD_MODEL=xtts_v2.0.2
#EXTRA_ARGS=--log-level DEBUG --unload-timer 300
#USE_ROCM=1
#USE_ROCM=1
# F5-TTS gated checkpoint requires a HuggingFace token + license accept.
# Visit https://huggingface.co/SWivid/F5-TTS, accept the license, then set
# this in your local speech.env (NOT here — sample.env is committed).
#HF_TOKEN=

182
speech.py
View file

@ -52,6 +52,20 @@ except ImportError:
torch = None
Qwen3TTSModel = None
# Try to import F5-TTS dependencies (SWivid/F5-TTS, MIT-licensed flow-matching TTS)
try:
import torch
from f5_tts.api import F5TTS
F5_TTS_AVAILABLE = True
except ImportError:
F5_TTS_AVAILABLE = False
if torch is None:
try:
import torch
except ImportError:
torch = None
F5TTS = None
@contextlib.asynccontextmanager
async def lifespan(app):
# Startup: Initialize voice caches in each worker process
@ -107,6 +121,10 @@ async def lifespan(app):
model_info["engine"] = "qwen3-tts"
model_info["description"] = "State-of-the-art TTS with voice cloning (1.7B params, 10 languages)"
model_info["sample_rate"] = 24000
elif model_id == 'tts-1-f5':
model_info["engine"] = "f5-tts"
model_info["description"] = "Flow-matching zero-shot voice cloning (336M params, MIT)"
model_info["sample_rate"] = 24000
models_data.append(model_info)
@ -145,6 +163,7 @@ kokoro_pipeline = None
kokoro_lang = None
qwen_model = None
qwen_voice_prompts = {} # Cache for voice clone prompts
f5_model = None
# Default args for worker processes (will be overridden in __main__)
class DefaultArgs:
@ -180,6 +199,7 @@ voices_cache = None
silero_load_semaphore = asyncio.Semaphore(1) # Only one Silero model load at a time
kokoro_load_semaphore = asyncio.Semaphore(1) # Only one Kokoro model load at a time
qwen_load_semaphore = asyncio.Semaphore(1) # Only one Qwen model load at a time
f5_load_semaphore = asyncio.Semaphore(1) # Only one F5-TTS model load at a time
def unload_model():
import torch, gc
@ -491,6 +511,72 @@ class qwen3_wrapper():
logger.error(f"Qwen3-TTS generation failed: {e}")
raise
class f5_wrapper():
"""Wrapper for F5-TTS model (SWivid/F5-TTS, MIT)
Flow-matching zero-shot voice cloning:
- ~336M params, smaller than Qwen3-TTS (1.7B)
- 24kHz output, matches Qwen3-TTS sample rate
- Reference audio + transcript, no fine-tuning
- No temperature/top_p/top_k uses cfg_strength + nfe_step instead
"""
def __init__(self, device='cuda'):
self.device = device
self.sample_rate = 24000 # f5_tts.infer.utils_infer.target_sample_rate
logger.info(f"Loading F5-TTS model on device '{device}'")
try:
from f5_tts.api import F5TTS
self.model = F5TTS(device=device)
logger.info(f"Successfully loaded F5-TTS model on {device}")
except Exception as e:
logger.error(f"Failed to load F5-TTS model: {e}")
raise
def tts(self, text, ref_audio, ref_text, speed=1.0, nfe_step=32, cfg_strength=2.0):
"""Generate speech from text using F5-TTS voice cloning.
Args:
text: Text to synthesize
ref_audio: Path to reference audio file
ref_text: Transcript of reference audio
speed: Speed multiplier (1.0 = normal)
nfe_step: Number of ODE steps (32 = default, balance quality/speed)
cfg_strength: Classifier-free guidance strength
Returns:
Audio data as bytes (float32 PCM at 24kHz)
"""
import numpy as np
logger.info(f"F5-TTS generating: text length={len(text)}")
try:
wav, sr, _spec = self.model.infer(
ref_file=ref_audio,
ref_text=ref_text,
gen_text=text,
nfe_step=nfe_step,
cfg_strength=cfg_strength,
speed=speed,
show_info=lambda *a, **k: None,
progress=None,
)
if hasattr(wav, 'detach'):
wav = wav.detach().to('cpu', dtype=torch.float32).numpy()
audio = np.asarray(wav, dtype=np.float32).flatten()
self.sample_rate = sr
logger.info(f"F5-TTS generated {len(audio)} samples at {sr}Hz")
return audio.tobytes()
except Exception as e:
logger.error(f"F5-TTS generation failed: {e}")
raise
def default_exists(filename: str):
if not os.path.exists(filename):
fpath, ext = os.path.splitext(filename)
@ -613,7 +699,7 @@ def build_ffmpeg_args(response_format, input_format, sample_rate):
async def list_models():
"""List all available TTS models (OpenAI-compatible format)"""
# Return minimal OpenAI-compatible model list (no extra fields)
# Only tts-1-qwen is enabled by default
# tts-1-qwen and tts-1-f5 enabled by default
return {
"object": "list",
"data": [
@ -622,6 +708,12 @@ async def list_models():
"object": "model",
"created": 1700000000,
"owned_by": "uncloseai"
},
{
"id": "tts-1-f5",
"object": "model",
"created": 1700000000,
"owned_by": "uncloseai"
}
# Other models disabled by default:
# {
@ -705,6 +797,10 @@ async def list_voices():
model_info["engine"] = "qwen3-tts"
model_info["description"] = "State-of-the-art TTS with voice cloning (1.7B params, 10 languages)"
model_info["sample_rate"] = 24000
elif model_id == 'tts-1-f5':
model_info["engine"] = "f5-tts"
model_info["description"] = "Flow-matching zero-shot voice cloning (336M params, MIT)"
model_info["sample_rate"] = 24000
models_data.append(model_info)
@ -764,6 +860,8 @@ async def generate_speech(request: GenerateSpeechRequest):
media_type = "audio/pcm;rate=24000"
elif model == 'tts-1-qwen': # qwen3-tts
media_type = "audio/pcm;rate=24000"
elif model == 'tts-1-f5': # f5-tts
media_type = "audio/pcm;rate=24000"
else:
raise BadRequestError(f"Invalid response_format: '{response_format}'", param='response_format')
@ -1174,9 +1272,86 @@ async def generate_speech(request: GenerateSpeechRequest):
out_writer_worker = threading.Thread(target=out_writer, daemon=True)
out_writer_worker.start()
return StreamingResponse(content=ffmpeg_proc.stdout, media_type=media_type)
# Use F5-TTS for tts-1-f5
elif model == 'tts-1-f5':
global f5_model
if not F5_TTS_AVAILABLE:
raise ServiceUnavailableError("F5-TTS is not available. Install with: pip install f5-tts")
voice_map = map_voice_to_speaker(voice, 'tts-1-f5')
ref_audio = voice_map.get('ref_audio')
ref_text = voice_map.get('ref_text')
if not (ref_audio and ref_text):
raise BadRequestError(f"Voice '{voice}' requires ref_audio and ref_text configuration", param='voice')
# Load F5 model if not already loaded
if f5_model is None:
async with f5_load_semaphore:
if f5_model is None:
device = args.xtts_device if args.xtts_device != 'none' else 'cpu'
logger.info(f"Loading F5-TTS model on device '{device}'")
f5_model = await asyncio.to_thread(f5_wrapper, device=device)
# Split text into sentences for streaming (first audio arrives faster)
sentences = simple_sentence_split(input_text, max_length=500)
logger.info(f"Split text into {len(sentences)} sentences for F5-TTS streaming")
# F5-TTS outputs float32 PCM at 24kHz
ffmpeg_args = build_ffmpeg_args(response_format, input_format="f32le", sample_rate="24000")
# F5-TTS accepts speed natively; only apply atempo as a fallback when ffmpeg can do it cheaper
# (we pass speed to the model below, leaving ffmpeg speed at 1.0)
ffmpeg_args.extend(["-"])
ffmpeg_proc = subprocess.Popen(ffmpeg_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
in_q = queue.Queue()
def generator():
"""Process sentences sequentially and feed to queue"""
try:
for idx, sentence in enumerate(sentences):
logger.debug(f"F5-TTS processing sentence {idx+1}/{len(sentences)}: {len(sentence)} chars")
audio_bytes = f5_model.tts(
text=sentence,
ref_audio=ref_audio,
ref_text=ref_text,
speed=speed,
)
in_q.put(audio_bytes)
logger.debug(f"F5-TTS: queued sentence {idx+1}/{len(sentences)}")
except Exception as e:
logger.error(f"F5-TTS streaming error: {e}")
finally:
in_q.put(None)
logger.info(f"F5-TTS streaming complete: {len(sentences)} sentences processed")
def out_writer():
"""Write audio from queue to ffmpeg stdin"""
try:
while True:
chunk = in_q.get()
if chunk is None:
break
ffmpeg_proc.stdin.write(chunk)
except Exception as e:
logger.error(f"F5-TTS ffmpeg write error: {e}")
ffmpeg_proc.kill()
finally:
ffmpeg_proc.stdin.close()
generator_worker = threading.Thread(target=generator, daemon=True)
generator_worker.start()
out_writer_worker = threading.Thread(target=out_writer, daemon=True)
out_writer_worker.start()
return StreamingResponse(content=ffmpeg_proc.stdout, media_type=media_type)
else:
raise BadRequestError("No such model, must be tts-1-qwen (default), tts-1, tts-1-hd, tts-1-silero, or tts-1-kokoro.", param='model')
raise BadRequestError("No such model, must be tts-1-qwen (default), tts-1-f5, tts-1, tts-1-hd, tts-1-silero, or tts-1-kokoro.", param='model')
if __name__ == "__main__":
parser = argparse.ArgumentParser(
@ -1203,8 +1378,9 @@ if __name__ == "__main__":
elif args.preload:
xtts = xtts_wrapper(args.preload, device=args.xtts_device, unload_timer=args.unload_timer)
# Register only Qwen by default (other models disabled)
# Register Qwen + F5 by default (other models disabled)
app.register_model('tts-1-qwen')
app.register_model('tts-1-f5')
# To enable other models, uncomment below:
# app.register_model('tts-1')
# app.register_model('tts-1-hd')

View file

@ -266,3 +266,253 @@ tts-1-qwen:
# alloy:
# model: xtts
# speaker: voices/alloy.wav
# ===== F5-TTS voice mappings =====
# Same 40 LibriSpeech speakers as tts-1-qwen, reused for F5-TTS (flow-matching).
# F5-TTS uses ref_audio + ref_text; identical to Qwen3-TTS reference format.
tts-1-f5:
# female - speaker 2094
aria:
ref_audio: cloned-voices/aria.wav
ref_text: "BUT THE WINDOWS ARE PATCHED WITH WOODEN PANES AND THE DOOR I THINK IS LIKE THE GATE IT IS NEVER OPENED"
language: English
# female - speaker 3575
clara:
ref_audio: cloned-voices/clara.wav
ref_text: "BUT IT IS NOT WITH A VIEW TO DISTINCTION THAT YOU SHOULD CULTIVATE THIS TALENT IF YOU CONSULT YOUR OWN HAPPINESS"
language: English
# female - speaker 2961
elena:
ref_audio: cloned-voices/elena.wav
ref_text: "MANY IF NOT ALL THE ELEMENTS OF THE PRE SOCRATIC PHILOSOPHY ARE INCLUDED IN THE TIMAEUS"
language: English
# female - speaker 8463
grace:
ref_audio: cloned-voices/grace.wav
ref_text: "AS TO HIS AGE AND ALSO THE NAME OF HIS MASTER JACOB'S STATEMENT VARIED SOMEWHAT FROM THE ADVERTISEMENT"
language: English
# female - speaker 1995
hazel:
ref_audio: cloned-voices/hazel.wav
ref_text: "I BELIEVE IN THE TRAINING OF PEOPLE TO THEIR HIGHEST CAPACITY THE ENGLISHMAN HERE HEARTILY SECONDED HIM"
language: English
# female - speaker 1284
iris:
ref_audio: cloned-voices/iris.wav
ref_text: "GOLD IS THE MOST COMMON METAL IN THE LAND OF OZ AND IS USED FOR MANY PURPOSES BECAUSE IT IS SOFT AND PLIABLE"
language: English
# female - speaker 5142
luna:
ref_audio: cloned-voices/luna.wav
ref_text: "THE DOOR OPENED AGAIN WHILE I WAS STILL STUDYING THE TWO BROTHERS WITHOUT I HONESTLY CONFESS BEING VERY FAVORABLY IMPRESSED BY EITHER OF THEM"
language: English
# female - speaker 4446
maya:
ref_audio: cloned-voices/maya.wav
ref_text: "HE HAD PRECONCEIVED IDEAS ABOUT EVERYTHING AND HIS IDEA ABOUT AMERICANS WAS THAT THEY SHOULD BE ENGINEERS OR MECHANICS"
language: English
# female - speaker 1221
ruby:
ref_audio: cloned-voices/ruby.wav
ref_text: "YEA HIS HONOURABLE WORSHIP IS WITHIN BUT HE HATH A GODLY MINISTER OR TWO WITH HIM AND LIKEWISE A LEECH"
language: English
# female - speaker 4507
sage:
ref_audio: cloned-voices/sage.wav
ref_text: "NOW WHEN HAS HORROR EVER EXCLUDED STUDY"
language: English
# female - speaker 3729
sofia:
ref_audio: cloned-voices/sofia.wav
ref_text: "I HAD A NAME I BELIEVE IN MY YOUNG DAYS BUT I HAVE FORGOTTEN IT SINCE I HAVE BEEN IN SERVICE"
language: English
# female - speaker 121
amber:
ref_audio: cloned-voices/amber.wav
ref_text: "HAY FEVER A HEART TROUBLE CAUSED BY FALLING IN LOVE WITH A GRASS WIDOW"
language: English
# female - speaker 237
brooke:
ref_audio: cloned-voices/brooke.wav
ref_text: "FRANK READ ENGLISH SLOWLY AND THE MORE HE READ ABOUT THIS DIVORCE CASE THE ANGRIER HE GREW"
language: English
# female - speaker 1580
cora:
ref_audio: cloned-voices/cora.wav
ref_text: "THE ALTERNATIVE WAS THAT SOMEONE PASSING HAD OBSERVED THE KEY IN THE DOOR HAD KNOWN THAT I WAS OUT AND HAD ENTERED TO LOOK AT THE PAPERS"
language: English
# female - speaker 3570
diana:
ref_audio: cloned-voices/diana.wav
ref_text: "THE WEARERS OF UNIFORMS AND LIVERIES MAY BE ROUGHLY DIVIDED INTO TWO CLASSES THE FREE AND THE SERVILE OR THE NOBLE AND THE IGNOBLE"
language: English
# female - speaker 4970
eden:
ref_audio: cloned-voices/eden.wav
ref_text: "RUTH SAT QUITE STILL FOR A TIME WITH FACE INTENT AND FLUSHED IT WAS OUT NOW"
language: English
# female - speaker 4992
faye:
ref_audio: cloned-voices/faye.wav
ref_text: "HE GIVE UP HIS POSITION AND SHUT THE FAMILY UP IN THAT TOMB OF A HOUSE SO T HE COULD STUDY HIS BOOKS"
language: English
# female - speaker 5683
gemma:
ref_audio: cloned-voices/gemma.wav
ref_text: "DO YOU KNOW LAKE OH I REALLY CAN'T TELL BUT HE'LL SOON TIRE OF COUNTRY LIFE"
language: English
# female - speaker 6829
hope:
ref_audio: cloned-voices/hope.wav
ref_text: "MISS DE GRAF SAID KENNETH NOTICING THE BOY'S FACE CRITICALLY AS HE STOOD WHERE THE LIGHT FROM THE PASSAGE FELL UPON IT"
language: English
# female - speaker 8555
ivy:
ref_audio: cloned-voices/ivy.wav
ref_text: "OVER THE TRACK LINED CITY STREET THE YOUNG MEN THE GRINNING MEN PASS"
language: English
# male - speaker 6930
atlas:
ref_audio: cloned-voices/atlas.wav
ref_text: "IT IS YOU WHO ARE MISTAKEN RAOUL I HAVE READ HIS DISTRESS IN HIS EYES IN HIS EVERY GESTURE AND ACTION THE WHOLE DAY"
language: English
# male - speaker 1320
caleb:
ref_audio: cloned-voices/caleb.wav
ref_text: "FOUR OR FIVE OF THE LATTER ONLY LINGERED ABOUT THE DOOR OF THE PRISON OF UNCAS WARY BUT CLOSE OBSERVERS OF THE MANNER OF THEIR CAPTIVE"
language: English
# male - speaker 5639
felix:
ref_audio: cloned-voices/felix.wav
ref_text: "SHE SAW THAT THE BED WAS GILDED AND SO RICH THAT IT SEEMED THAT OF A PRINCE RATHER THAN OF A PRIVATE GENTLEMAN"
language: English
# male - speaker 260
hugo:
ref_audio: cloned-voices/hugo.wav
ref_text: "CRIED ALICE AGAIN FOR THIS TIME THE MOUSE WAS BRISTLING ALL OVER AND SHE FELT CERTAIN IT MUST BE REALLY OFFENDED"
language: English
# male - speaker 7729
jasper:
ref_audio: cloned-voices/jasper.wav
ref_text: "THAT SUMMER'S EMIGRATION HOWEVER BEING MAINLY FROM THE FREE STATES GREATLY CHANGED THE RELATIVE STRENGTH OF THE TWO PARTIES"
language: English
# male - speaker 7127
kai:
ref_audio: cloned-voices/kai.wav
ref_text: "UPON THIS MADAME DEIGNED TO TURN HER EYES LANGUISHINGLY TOWARDS THE COMTE OBSERVING"
language: English
# male - speaker 8230
leo:
ref_audio: cloned-voices/leo.wav
ref_text: "THE BEHAVIOURIST WHO ATTEMPTS TO MAKE PSYCHOLOGY A RECORD OF BEHAVIOUR HAS TO TRUST HIS MEMORY IN MAKING THE RECORD"
language: English
# male - speaker 7176
marcus:
ref_audio: cloned-voices/marcus.wav
ref_text: "IN THE OLD BADLY MADE PLAY IT WAS FREQUENTLY NECESSARY FOR ONE OF THE CHARACTERS TO TAKE THE AUDIENCE INTO HIS CONFIDENCE"
language: English
# male - speaker 8455
owen:
ref_audio: cloned-voices/owen.wav
ref_text: "I DID NOT MEAN SAID CAPTAIN BATTLEAX TO TOUCH UPON PUBLIC SUBJECTS AT SUCH A MOMENT AS THIS"
language: English
# male - speaker 2830
theo:
ref_audio: cloned-voices/theo.wav
ref_text: "I KNEW NOTHING OF THE DOCTRINE OF FAITH BECAUSE WE WERE TAUGHT SOPHISTRY INSTEAD OF CERTAINTY AND NOBODY UNDERSTOOD SPIRITUAL BOASTING"
language: English
# male - speaker 61
archer:
ref_audio: cloned-voices/archer.wav
ref_text: "WHAT IS THE TUMULT AND RIOTING CRIED OUT THE SQUIRE AUTHORITATIVELY AND HE BLEW TWICE ON A SILVER WHISTLE WHICH HUNG AT HIS BELT"
language: English
# male - speaker 672
blake:
ref_audio: cloned-voices/blake.wav
ref_text: "IN AUTUMN THE WOOD CUTTERS ALWAYS CAME AND FELLED SOME OF THE LARGEST TREES"
language: English
# male - speaker 908
cole:
ref_audio: cloned-voices/cole.wav
ref_text: "LIKE THE DOVES VOICE LIKE TRANSIENT DAY LIKE MUSIC IN THE AIR AH"
language: English
# male - speaker 1089
dane:
ref_audio: cloned-voices/dane.wav
ref_text: "THE PRIDE OF THAT DIM IMAGE BROUGHT BACK TO HIS MIND THE DIGNITY OF THE OFFICE HE HAD REFUSED"
language: English
# male - speaker 1188
ezra:
ref_audio: cloned-voices/ezra.wav
ref_text: "BUT IN THIS VIGNETTE COPIED FROM TURNER YOU HAVE THE TWO PRINCIPLES BROUGHT OUT PERFECTLY"
language: English
# male - speaker 2300
finn:
ref_audio: cloned-voices/finn.wav
ref_text: "WHY IF WE ERECT A STATION AT THE FALLS IT IS A GREAT ECONOMY TO GET IT UP TO THE CITY"
language: English
# male - speaker 4077
grant:
ref_audio: cloned-voices/grant.wav
ref_text: "AT THE INCEPTION OF PLURAL MARRIAGE AMONG THE LATTER DAY SAINTS THERE WAS NO LAW NATIONAL OR STATE AGAINST ITS PRACTISE"
language: English
# male - speaker 5105
heath:
ref_audio: cloned-voices/heath.wav
ref_text: "AND WHAT DEMONSTRATION DO YOU OFFER ASKED SERVADAC EAGERLY THAT IT WILL NOT HAPPEN"
language: English
# male - speaker 7021
ivan:
ref_audio: cloned-voices/ivan.wav
ref_text: "THEN TURNING TO JANE SHE ASKED IN A SOMEWHAT ALTERED TONE HAS SHE BEEN A GOOD GIRL JANE"
language: English
# male - speaker 8224
jude:
ref_audio: cloned-voices/jude.wav
ref_text: "THE KING STOOD UP AND CALLED FOR THAT PSALM WHICH BEGINS WITH THESE WORDS"
language: English
# Other TTS engines (disabled by default)
# Uncomment and configure to enable